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::{
  105    any::TypeId,
  106    borrow::Cow,
  107    cmp::{self, Ordering, Reverse},
  108    mem,
  109    num::NonZeroU32,
  110    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  111    path::Path,
  112    sync::Arc,
  113    time::{Duration, Instant},
  114};
  115pub use sum_tree::Bias;
  116use text::{BufferId, OffsetUtf16, Rope};
  117use theme::{
  118    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
  119    ThemeColors, ThemeSettings,
  120};
  121use ui::{
  122    h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover,
  123    Tooltip,
  124};
  125use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
  126use workspace::Toast;
  127use workspace::{searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace};
  128
  129use crate::hover_links::find_url;
  130
  131const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  132const MAX_LINE_LEN: usize = 1024;
  133const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  134const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  135const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
  136pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  137#[doc(hidden)]
  138pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  139#[doc(hidden)]
  140pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
  141
  142pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
  143
  144pub fn render_parsed_markdown(
  145    element_id: impl Into<ElementId>,
  146    parsed: &language::ParsedMarkdown,
  147    editor_style: &EditorStyle,
  148    workspace: Option<WeakView<Workspace>>,
  149    cx: &mut ViewContext<Editor>,
  150) -> InteractiveText {
  151    let code_span_background_color = cx
  152        .theme()
  153        .colors()
  154        .editor_document_highlight_read_background;
  155
  156    let highlights = gpui::combine_highlights(
  157        parsed.highlights.iter().filter_map(|(range, highlight)| {
  158            let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
  159            Some((range.clone(), highlight))
  160        }),
  161        parsed
  162            .regions
  163            .iter()
  164            .zip(&parsed.region_ranges)
  165            .filter_map(|(region, range)| {
  166                if region.code {
  167                    Some((
  168                        range.clone(),
  169                        HighlightStyle {
  170                            background_color: Some(code_span_background_color),
  171                            ..Default::default()
  172                        },
  173                    ))
  174                } else {
  175                    None
  176                }
  177            }),
  178    );
  179
  180    let mut links = Vec::new();
  181    let mut link_ranges = Vec::new();
  182    for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
  183        if let Some(link) = region.link.clone() {
  184            links.push(link);
  185            link_ranges.push(range.clone());
  186        }
  187    }
  188
  189    InteractiveText::new(
  190        element_id,
  191        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),
  192    )
  193    .on_click(link_ranges, move |clicked_range_ix, cx| {
  194        match &links[clicked_range_ix] {
  195            markdown::Link::Web { url } => cx.open_url(url),
  196            markdown::Link::Path { path } => {
  197                if let Some(workspace) = &workspace {
  198                    _ = workspace.update(cx, |workspace, cx| {
  199                        workspace.open_abs_path(path.clone(), false, cx).detach();
  200                    });
  201                }
  202            }
  203        }
  204    })
  205}
  206
  207#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  208pub(crate) enum InlayId {
  209    Suggestion(usize),
  210    Hint(usize),
  211}
  212
  213impl InlayId {
  214    fn id(&self) -> usize {
  215        match self {
  216            Self::Suggestion(id) => *id,
  217            Self::Hint(id) => *id,
  218        }
  219    }
  220}
  221
  222enum DocumentHighlightRead {}
  223enum DocumentHighlightWrite {}
  224enum InputComposition {}
  225
  226#[derive(Copy, Clone, PartialEq, Eq)]
  227pub enum Direction {
  228    Prev,
  229    Next,
  230}
  231
  232pub fn init_settings(cx: &mut AppContext) {
  233    EditorSettings::register(cx);
  234}
  235
  236pub fn init(cx: &mut AppContext) {
  237    init_settings(cx);
  238
  239    workspace::register_project_item::<Editor>(cx);
  240    workspace::register_followable_item::<Editor>(cx);
  241    workspace::register_deserializable_item::<Editor>(cx);
  242    cx.observe_new_views(
  243        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
  244            workspace.register_action(Editor::new_file);
  245            workspace.register_action(Editor::new_file_in_direction);
  246        },
  247    )
  248    .detach();
  249
  250    cx.on_action(move |_: &workspace::NewFile, cx| {
  251        let app_state = workspace::AppState::global(cx);
  252        if let Some(app_state) = app_state.upgrade() {
  253            workspace::open_new(app_state, cx, |workspace, cx| {
  254                Editor::new_file(workspace, &Default::default(), cx)
  255            })
  256            .detach();
  257        }
  258    });
  259    cx.on_action(move |_: &workspace::NewWindow, cx| {
  260        let app_state = workspace::AppState::global(cx);
  261        if let Some(app_state) = app_state.upgrade() {
  262            workspace::open_new(app_state, cx, |workspace, cx| {
  263                Editor::new_file(workspace, &Default::default(), cx)
  264            })
  265            .detach();
  266        }
  267    });
  268}
  269
  270trait InvalidationRegion {
  271    fn ranges(&self) -> &[Range<Anchor>];
  272}
  273
  274#[derive(Clone, Debug, PartialEq)]
  275pub enum SelectPhase {
  276    Begin {
  277        position: DisplayPoint,
  278        add: bool,
  279        click_count: usize,
  280    },
  281    BeginColumnar {
  282        position: DisplayPoint,
  283        goal_column: u32,
  284    },
  285    Extend {
  286        position: DisplayPoint,
  287        click_count: usize,
  288    },
  289    Update {
  290        position: DisplayPoint,
  291        goal_column: u32,
  292        scroll_delta: gpui::Point<f32>,
  293    },
  294    End,
  295}
  296
  297#[derive(Clone, Debug)]
  298pub enum SelectMode {
  299    Character,
  300    Word(Range<Anchor>),
  301    Line(Range<Anchor>),
  302    All,
  303}
  304
  305#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  306pub enum EditorMode {
  307    SingleLine,
  308    AutoHeight { max_lines: usize },
  309    Full,
  310}
  311
  312#[derive(Clone, Debug)]
  313pub enum SoftWrap {
  314    None,
  315    EditorWidth,
  316    Column(u32),
  317}
  318
  319#[derive(Clone)]
  320pub struct EditorStyle {
  321    pub background: Hsla,
  322    pub local_player: PlayerColor,
  323    pub text: TextStyle,
  324    pub scrollbar_width: Pixels,
  325    pub syntax: Arc<SyntaxTheme>,
  326    pub status: StatusColors,
  327    pub inlay_hints_style: HighlightStyle,
  328    pub suggestions_style: HighlightStyle,
  329}
  330
  331impl Default for EditorStyle {
  332    fn default() -> Self {
  333        Self {
  334            background: Hsla::default(),
  335            local_player: PlayerColor::default(),
  336            text: TextStyle::default(),
  337            scrollbar_width: Pixels::default(),
  338            syntax: Default::default(),
  339            // HACK: Status colors don't have a real default.
  340            // We should look into removing the status colors from the editor
  341            // style and retrieve them directly from the theme.
  342            status: StatusColors::dark(),
  343            inlay_hints_style: HighlightStyle::default(),
  344            suggestions_style: HighlightStyle::default(),
  345        }
  346    }
  347}
  348
  349type CompletionId = usize;
  350
  351// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  352// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  353
  354type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>);
  355
  356/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
  357///
  358/// See the [module level documentation](self) for more information.
  359pub struct Editor {
  360    focus_handle: FocusHandle,
  361    /// The text buffer being edited
  362    buffer: Model<MultiBuffer>,
  363    /// Map of how text in the buffer should be displayed.
  364    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  365    display_map: Model<DisplayMap>,
  366    pub selections: SelectionsCollection,
  367    pub scroll_manager: ScrollManager,
  368    columnar_selection_tail: Option<Anchor>,
  369    add_selections_state: Option<AddSelectionsState>,
  370    select_next_state: Option<SelectNextState>,
  371    select_prev_state: Option<SelectNextState>,
  372    selection_history: SelectionHistory,
  373    autoclose_regions: Vec<AutocloseRegion>,
  374    snippet_stack: InvalidationStack<SnippetState>,
  375    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
  376    ime_transaction: Option<TransactionId>,
  377    active_diagnostics: Option<ActiveDiagnosticGroup>,
  378    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  379    project: Option<Model<Project>>,
  380    completion_provider: Option<Box<dyn CompletionProvider>>,
  381    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  382    blink_manager: Model<BlinkManager>,
  383    show_cursor_names: bool,
  384    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  385    pub show_local_selections: bool,
  386    mode: EditorMode,
  387    show_breadcrumbs: bool,
  388    show_gutter: bool,
  389    show_wrap_guides: Option<bool>,
  390    placeholder_text: Option<Arc<str>>,
  391    highlight_order: usize,
  392    highlighted_rows: HashMap<TypeId, Vec<(usize, Range<Anchor>, Hsla)>>,
  393    background_highlights: BTreeMap<TypeId, BackgroundHighlight>,
  394    nav_history: Option<ItemNavHistory>,
  395    context_menu: RwLock<Option<ContextMenu>>,
  396    mouse_context_menu: Option<MouseContextMenu>,
  397    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  398    next_completion_id: CompletionId,
  399    completion_documentation_pre_resolve_debounce: DebouncedDelay,
  400    available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>,
  401    code_actions_task: Option<Task<()>>,
  402    document_highlights_task: Option<Task<()>>,
  403    pending_rename: Option<RenameState>,
  404    searchable: bool,
  405    cursor_shape: CursorShape,
  406    collapse_matches: bool,
  407    autoindent_mode: Option<AutoindentMode>,
  408    workspace: Option<(WeakView<Workspace>, i64)>,
  409    keymap_context_layers: BTreeMap<TypeId, KeyContext>,
  410    input_enabled: bool,
  411    use_modal_editing: bool,
  412    read_only: bool,
  413    leader_peer_id: Option<PeerId>,
  414    remote_id: Option<ViewId>,
  415    hover_state: HoverState,
  416    gutter_hovered: bool,
  417    hovered_link_state: Option<HoveredLinkState>,
  418    copilot_state: CopilotState,
  419    inlay_hint_cache: InlayHintCache,
  420    next_inlay_id: usize,
  421    _subscriptions: Vec<Subscription>,
  422    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  423    gutter_width: Pixels,
  424    style: Option<EditorStyle>,
  425    editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,
  426    show_copilot_suggestions: bool,
  427    use_autoclose: bool,
  428    auto_replace_emoji_shortcode: bool,
  429    custom_context_menu: Option<
  430        Box<
  431            dyn 'static
  432                + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
  433        >,
  434    >,
  435}
  436
  437pub struct EditorSnapshot {
  438    pub mode: EditorMode,
  439    show_gutter: bool,
  440    pub display_snapshot: DisplaySnapshot,
  441    pub placeholder_text: Option<Arc<str>>,
  442    is_focused: bool,
  443    scroll_anchor: ScrollAnchor,
  444    ongoing_scroll: OngoingScroll,
  445}
  446
  447pub struct GutterDimensions {
  448    pub left_padding: Pixels,
  449    pub right_padding: Pixels,
  450    pub width: Pixels,
  451    pub margin: Pixels,
  452}
  453
  454impl Default for GutterDimensions {
  455    fn default() -> Self {
  456        Self {
  457            left_padding: Pixels::ZERO,
  458            right_padding: Pixels::ZERO,
  459            width: Pixels::ZERO,
  460            margin: Pixels::ZERO,
  461        }
  462    }
  463}
  464
  465#[derive(Debug)]
  466pub struct RemoteSelection {
  467    pub replica_id: ReplicaId,
  468    pub selection: Selection<Anchor>,
  469    pub cursor_shape: CursorShape,
  470    pub peer_id: PeerId,
  471    pub line_mode: bool,
  472    pub participant_index: Option<ParticipantIndex>,
  473    pub user_name: Option<SharedString>,
  474}
  475
  476#[derive(Clone, Debug)]
  477struct SelectionHistoryEntry {
  478    selections: Arc<[Selection<Anchor>]>,
  479    select_next_state: Option<SelectNextState>,
  480    select_prev_state: Option<SelectNextState>,
  481    add_selections_state: Option<AddSelectionsState>,
  482}
  483
  484enum SelectionHistoryMode {
  485    Normal,
  486    Undoing,
  487    Redoing,
  488}
  489
  490#[derive(Clone, PartialEq, Eq, Hash)]
  491struct HoveredCursor {
  492    replica_id: u16,
  493    selection_id: usize,
  494}
  495
  496impl Default for SelectionHistoryMode {
  497    fn default() -> Self {
  498        Self::Normal
  499    }
  500}
  501
  502#[derive(Default)]
  503struct SelectionHistory {
  504    #[allow(clippy::type_complexity)]
  505    selections_by_transaction:
  506        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  507    mode: SelectionHistoryMode,
  508    undo_stack: VecDeque<SelectionHistoryEntry>,
  509    redo_stack: VecDeque<SelectionHistoryEntry>,
  510}
  511
  512impl SelectionHistory {
  513    fn insert_transaction(
  514        &mut self,
  515        transaction_id: TransactionId,
  516        selections: Arc<[Selection<Anchor>]>,
  517    ) {
  518        self.selections_by_transaction
  519            .insert(transaction_id, (selections, None));
  520    }
  521
  522    #[allow(clippy::type_complexity)]
  523    fn transaction(
  524        &self,
  525        transaction_id: TransactionId,
  526    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  527        self.selections_by_transaction.get(&transaction_id)
  528    }
  529
  530    #[allow(clippy::type_complexity)]
  531    fn transaction_mut(
  532        &mut self,
  533        transaction_id: TransactionId,
  534    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  535        self.selections_by_transaction.get_mut(&transaction_id)
  536    }
  537
  538    fn push(&mut self, entry: SelectionHistoryEntry) {
  539        if !entry.selections.is_empty() {
  540            match self.mode {
  541                SelectionHistoryMode::Normal => {
  542                    self.push_undo(entry);
  543                    self.redo_stack.clear();
  544                }
  545                SelectionHistoryMode::Undoing => self.push_redo(entry),
  546                SelectionHistoryMode::Redoing => self.push_undo(entry),
  547            }
  548        }
  549    }
  550
  551    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  552        if self
  553            .undo_stack
  554            .back()
  555            .map_or(true, |e| e.selections != entry.selections)
  556        {
  557            self.undo_stack.push_back(entry);
  558            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  559                self.undo_stack.pop_front();
  560            }
  561        }
  562    }
  563
  564    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
  565        if self
  566            .redo_stack
  567            .back()
  568            .map_or(true, |e| e.selections != entry.selections)
  569        {
  570            self.redo_stack.push_back(entry);
  571            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  572                self.redo_stack.pop_front();
  573            }
  574        }
  575    }
  576}
  577
  578#[derive(Clone, Debug)]
  579struct AddSelectionsState {
  580    above: bool,
  581    stack: Vec<usize>,
  582}
  583
  584#[derive(Clone)]
  585struct SelectNextState {
  586    query: AhoCorasick,
  587    wordwise: bool,
  588    done: bool,
  589}
  590
  591impl std::fmt::Debug for SelectNextState {
  592    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  593        f.debug_struct(std::any::type_name::<Self>())
  594            .field("wordwise", &self.wordwise)
  595            .field("done", &self.done)
  596            .finish()
  597    }
  598}
  599
  600#[derive(Debug)]
  601struct AutocloseRegion {
  602    selection_id: usize,
  603    range: Range<Anchor>,
  604    pair: BracketPair,
  605}
  606
  607#[derive(Debug)]
  608struct SnippetState {
  609    ranges: Vec<Vec<Range<Anchor>>>,
  610    active_index: usize,
  611}
  612
  613#[doc(hidden)]
  614pub struct RenameState {
  615    pub range: Range<Anchor>,
  616    pub old_name: Arc<str>,
  617    pub editor: View<Editor>,
  618    block_id: BlockId,
  619}
  620
  621struct InvalidationStack<T>(Vec<T>);
  622
  623enum ContextMenu {
  624    Completions(CompletionsMenu),
  625    CodeActions(CodeActionsMenu),
  626}
  627
  628impl ContextMenu {
  629    fn select_first(
  630        &mut self,
  631        project: Option<&Model<Project>>,
  632        cx: &mut ViewContext<Editor>,
  633    ) -> bool {
  634        if self.visible() {
  635            match self {
  636                ContextMenu::Completions(menu) => menu.select_first(project, cx),
  637                ContextMenu::CodeActions(menu) => menu.select_first(cx),
  638            }
  639            true
  640        } else {
  641            false
  642        }
  643    }
  644
  645    fn select_prev(
  646        &mut self,
  647        project: Option<&Model<Project>>,
  648        cx: &mut ViewContext<Editor>,
  649    ) -> bool {
  650        if self.visible() {
  651            match self {
  652                ContextMenu::Completions(menu) => menu.select_prev(project, cx),
  653                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
  654            }
  655            true
  656        } else {
  657            false
  658        }
  659    }
  660
  661    fn select_next(
  662        &mut self,
  663        project: Option<&Model<Project>>,
  664        cx: &mut ViewContext<Editor>,
  665    ) -> bool {
  666        if self.visible() {
  667            match self {
  668                ContextMenu::Completions(menu) => menu.select_next(project, cx),
  669                ContextMenu::CodeActions(menu) => menu.select_next(cx),
  670            }
  671            true
  672        } else {
  673            false
  674        }
  675    }
  676
  677    fn select_last(
  678        &mut self,
  679        project: Option<&Model<Project>>,
  680        cx: &mut ViewContext<Editor>,
  681    ) -> bool {
  682        if self.visible() {
  683            match self {
  684                ContextMenu::Completions(menu) => menu.select_last(project, cx),
  685                ContextMenu::CodeActions(menu) => menu.select_last(cx),
  686            }
  687            true
  688        } else {
  689            false
  690        }
  691    }
  692
  693    fn visible(&self) -> bool {
  694        match self {
  695            ContextMenu::Completions(menu) => menu.visible(),
  696            ContextMenu::CodeActions(menu) => menu.visible(),
  697        }
  698    }
  699
  700    fn render(
  701        &self,
  702        cursor_position: DisplayPoint,
  703        style: &EditorStyle,
  704        max_height: Pixels,
  705        workspace: Option<WeakView<Workspace>>,
  706        cx: &mut ViewContext<Editor>,
  707    ) -> (DisplayPoint, AnyElement) {
  708        match self {
  709            ContextMenu::Completions(menu) => (
  710                cursor_position,
  711                menu.render(style, max_height, workspace, cx),
  712            ),
  713            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, max_height, cx),
  714        }
  715    }
  716}
  717
  718#[derive(Clone)]
  719struct CompletionsMenu {
  720    id: CompletionId,
  721    initial_position: Anchor,
  722    buffer: Model<Buffer>,
  723    completions: Arc<RwLock<Box<[Completion]>>>,
  724    match_candidates: Arc<[StringMatchCandidate]>,
  725    matches: Arc<[StringMatch]>,
  726    selected_item: usize,
  727    scroll_handle: UniformListScrollHandle,
  728    selected_completion_documentation_resolve_debounce: Arc<Mutex<DebouncedDelay>>,
  729}
  730
  731impl CompletionsMenu {
  732    fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  733        self.selected_item = 0;
  734        self.scroll_handle.scroll_to_item(self.selected_item);
  735        self.attempt_resolve_selected_completion_documentation(project, cx);
  736        cx.notify();
  737    }
  738
  739    fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  740        if self.selected_item > 0 {
  741            self.selected_item -= 1;
  742        } else {
  743            self.selected_item = self.matches.len() - 1;
  744        }
  745        self.scroll_handle.scroll_to_item(self.selected_item);
  746        self.attempt_resolve_selected_completion_documentation(project, cx);
  747        cx.notify();
  748    }
  749
  750    fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  751        if self.selected_item + 1 < self.matches.len() {
  752            self.selected_item += 1;
  753        } else {
  754            self.selected_item = 0;
  755        }
  756        self.scroll_handle.scroll_to_item(self.selected_item);
  757        self.attempt_resolve_selected_completion_documentation(project, cx);
  758        cx.notify();
  759    }
  760
  761    fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  762        self.selected_item = self.matches.len() - 1;
  763        self.scroll_handle.scroll_to_item(self.selected_item);
  764        self.attempt_resolve_selected_completion_documentation(project, cx);
  765        cx.notify();
  766    }
  767
  768    fn pre_resolve_completion_documentation(
  769        completions: Arc<RwLock<Box<[Completion]>>>,
  770        matches: Arc<[StringMatch]>,
  771        editor: &Editor,
  772        cx: &mut ViewContext<Editor>,
  773    ) -> Task<()> {
  774        let settings = EditorSettings::get_global(cx);
  775        if !settings.show_completion_documentation {
  776            return Task::ready(());
  777        }
  778
  779        let Some(provider) = editor.completion_provider.as_ref() else {
  780            return Task::ready(());
  781        };
  782
  783        let resolve_task = provider.resolve_completions(
  784            matches.iter().map(|m| m.candidate_id).collect(),
  785            completions.clone(),
  786            cx,
  787        );
  788
  789        return cx.spawn(move |this, mut cx| async move {
  790            if let Some(true) = resolve_task.await.log_err() {
  791                this.update(&mut cx, |_, cx| cx.notify()).ok();
  792            }
  793        });
  794    }
  795
  796    fn attempt_resolve_selected_completion_documentation(
  797        &mut self,
  798        project: Option<&Model<Project>>,
  799        cx: &mut ViewContext<Editor>,
  800    ) {
  801        let settings = EditorSettings::get_global(cx);
  802        if !settings.show_completion_documentation {
  803            return;
  804        }
  805
  806        let completion_index = self.matches[self.selected_item].candidate_id;
  807        let Some(project) = project else {
  808            return;
  809        };
  810
  811        let resolve_task = project.update(cx, |project, cx| {
  812            project.resolve_completions(vec![completion_index], self.completions.clone(), cx)
  813        });
  814
  815        let delay_ms =
  816            EditorSettings::get_global(cx).completion_documentation_secondary_query_debounce;
  817        let delay = Duration::from_millis(delay_ms);
  818
  819        self.selected_completion_documentation_resolve_debounce
  820            .lock()
  821            .fire_new(delay, cx, |_, cx| {
  822                cx.spawn(move |this, mut cx| async move {
  823                    if let Some(true) = resolve_task.await.log_err() {
  824                        this.update(&mut cx, |_, cx| cx.notify()).ok();
  825                    }
  826                })
  827            });
  828    }
  829
  830    fn visible(&self) -> bool {
  831        !self.matches.is_empty()
  832    }
  833
  834    fn render(
  835        &self,
  836        style: &EditorStyle,
  837        max_height: Pixels,
  838        workspace: Option<WeakView<Workspace>>,
  839        cx: &mut ViewContext<Editor>,
  840    ) -> AnyElement {
  841        let settings = EditorSettings::get_global(cx);
  842        let show_completion_documentation = settings.show_completion_documentation;
  843
  844        let widest_completion_ix = self
  845            .matches
  846            .iter()
  847            .enumerate()
  848            .max_by_key(|(_, mat)| {
  849                let completions = self.completions.read();
  850                let completion = &completions[mat.candidate_id];
  851                let documentation = &completion.documentation;
  852
  853                let mut len = completion.label.text.chars().count();
  854                if let Some(Documentation::SingleLine(text)) = documentation {
  855                    if show_completion_documentation {
  856                        len += text.chars().count();
  857                    }
  858                }
  859
  860                len
  861            })
  862            .map(|(ix, _)| ix);
  863
  864        let completions = self.completions.clone();
  865        let matches = self.matches.clone();
  866        let selected_item = self.selected_item;
  867        let style = style.clone();
  868
  869        let multiline_docs = if show_completion_documentation {
  870            let mat = &self.matches[selected_item];
  871            let multiline_docs = match &self.completions.read()[mat.candidate_id].documentation {
  872                Some(Documentation::MultiLinePlainText(text)) => {
  873                    Some(div().child(SharedString::from(text.clone())))
  874                }
  875                Some(Documentation::MultiLineMarkdown(parsed)) if !parsed.text.is_empty() => {
  876                    Some(div().child(render_parsed_markdown(
  877                        "completions_markdown",
  878                        parsed,
  879                        &style,
  880                        workspace,
  881                        cx,
  882                    )))
  883                }
  884                _ => None,
  885            };
  886            multiline_docs.map(|div| {
  887                div.id("multiline_docs")
  888                    .max_h(max_height)
  889                    .flex_1()
  890                    .px_1p5()
  891                    .py_1()
  892                    .min_w(px(260.))
  893                    .max_w(px(640.))
  894                    .w(px(500.))
  895                    .overflow_y_scroll()
  896                    // Prevent a mouse down on documentation from being propagated to the editor,
  897                    // because that would move the cursor.
  898                    .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
  899            })
  900        } else {
  901            None
  902        };
  903
  904        let list = uniform_list(
  905            cx.view().clone(),
  906            "completions",
  907            matches.len(),
  908            move |_editor, range, cx| {
  909                let start_ix = range.start;
  910                let completions_guard = completions.read();
  911
  912                matches[range]
  913                    .iter()
  914                    .enumerate()
  915                    .map(|(ix, mat)| {
  916                        let item_ix = start_ix + ix;
  917                        let candidate_id = mat.candidate_id;
  918                        let completion = &completions_guard[candidate_id];
  919
  920                        let documentation = if show_completion_documentation {
  921                            &completion.documentation
  922                        } else {
  923                            &None
  924                        };
  925
  926                        let highlights = gpui::combine_highlights(
  927                            mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
  928                            styled_runs_for_code_label(&completion.label, &style.syntax).map(
  929                                |(range, mut highlight)| {
  930                                    // Ignore font weight for syntax highlighting, as we'll use it
  931                                    // for fuzzy matches.
  932                                    highlight.font_weight = None;
  933
  934                                    if completion.lsp_completion.deprecated.unwrap_or(false) {
  935                                        highlight.strikethrough = Some(StrikethroughStyle {
  936                                            thickness: 1.0.into(),
  937                                            ..Default::default()
  938                                        });
  939                                        highlight.color = Some(cx.theme().colors().text_muted);
  940                                    }
  941
  942                                    (range, highlight)
  943                                },
  944                            ),
  945                        );
  946                        let completion_label = StyledText::new(completion.label.text.clone())
  947                            .with_highlights(&style.text, highlights);
  948                        let documentation_label =
  949                            if let Some(Documentation::SingleLine(text)) = documentation {
  950                                if text.trim().is_empty() {
  951                                    None
  952                                } else {
  953                                    Some(
  954                                        h_flex().ml_4().child(
  955                                            Label::new(text.clone())
  956                                                .size(LabelSize::Small)
  957                                                .color(Color::Muted),
  958                                        ),
  959                                    )
  960                                }
  961                            } else {
  962                                None
  963                            };
  964
  965                        div().min_w(px(220.)).max_w(px(540.)).child(
  966                            ListItem::new(mat.candidate_id)
  967                                .inset(true)
  968                                .selected(item_ix == selected_item)
  969                                .on_click(cx.listener(move |editor, _event, cx| {
  970                                    cx.stop_propagation();
  971                                    if let Some(task) = editor.confirm_completion(
  972                                        &ConfirmCompletion {
  973                                            item_ix: Some(item_ix),
  974                                        },
  975                                        cx,
  976                                    ) {
  977                                        task.detach_and_log_err(cx)
  978                                    }
  979                                }))
  980                                .child(h_flex().overflow_hidden().child(completion_label))
  981                                .end_slot::<Div>(documentation_label),
  982                        )
  983                    })
  984                    .collect()
  985            },
  986        )
  987        .max_h(max_height)
  988        .track_scroll(self.scroll_handle.clone())
  989        .with_width_from_item(widest_completion_ix);
  990
  991        Popover::new()
  992            .child(list)
  993            .when_some(multiline_docs, |popover, multiline_docs| {
  994                popover.aside(multiline_docs)
  995            })
  996            .into_any_element()
  997    }
  998
  999    pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) {
 1000        let mut matches = if let Some(query) = query {
 1001            fuzzy::match_strings(
 1002                &self.match_candidates,
 1003                query,
 1004                query.chars().any(|c| c.is_uppercase()),
 1005                100,
 1006                &Default::default(),
 1007                executor,
 1008            )
 1009            .await
 1010        } else {
 1011            self.match_candidates
 1012                .iter()
 1013                .enumerate()
 1014                .map(|(candidate_id, candidate)| StringMatch {
 1015                    candidate_id,
 1016                    score: Default::default(),
 1017                    positions: Default::default(),
 1018                    string: candidate.string.clone(),
 1019                })
 1020                .collect()
 1021        };
 1022
 1023        // Remove all candidates where the query's start does not match the start of any word in the candidate
 1024        if let Some(query) = query {
 1025            if let Some(query_start) = query.chars().next() {
 1026                matches.retain(|string_match| {
 1027                    split_words(&string_match.string).any(|word| {
 1028                        // Check that the first codepoint of the word as lowercase matches the first
 1029                        // codepoint of the query as lowercase
 1030                        word.chars()
 1031                            .flat_map(|codepoint| codepoint.to_lowercase())
 1032                            .zip(query_start.to_lowercase())
 1033                            .all(|(word_cp, query_cp)| word_cp == query_cp)
 1034                    })
 1035                });
 1036            }
 1037        }
 1038
 1039        let completions = self.completions.read();
 1040        matches.sort_unstable_by_key(|mat| {
 1041            // We do want to strike a balance here between what the language server tells us
 1042            // to sort by (the sort_text) and what are "obvious" good matches (i.e. when you type
 1043            // `Creat` and there is a local variable called `CreateComponent`).
 1044            // So what we do is: we bucket all matches into two buckets
 1045            // - Strong matches
 1046            // - Weak matches
 1047            // Strong matches are the ones with a high fuzzy-matcher score (the "obvious" matches)
 1048            // and the Weak matches are the rest.
 1049            //
 1050            // For the strong matches, we sort by the language-servers score first and for the weak
 1051            // matches, we prefer our fuzzy finder first.
 1052            //
 1053            // The thinking behind that: it's useless to take the sort_text the language-server gives
 1054            // us into account when it's obviously a bad match.
 1055
 1056            #[derive(PartialEq, Eq, PartialOrd, Ord)]
 1057            enum MatchScore<'a> {
 1058                Strong {
 1059                    sort_text: Option<&'a str>,
 1060                    score: Reverse<OrderedFloat<f64>>,
 1061                    sort_key: (usize, &'a str),
 1062                },
 1063                Weak {
 1064                    score: Reverse<OrderedFloat<f64>>,
 1065                    sort_text: Option<&'a str>,
 1066                    sort_key: (usize, &'a str),
 1067                },
 1068            }
 1069
 1070            let completion = &completions[mat.candidate_id];
 1071            let sort_key = completion.sort_key();
 1072            let sort_text = completion.lsp_completion.sort_text.as_deref();
 1073            let score = Reverse(OrderedFloat(mat.score));
 1074
 1075            if mat.score >= 0.2 {
 1076                MatchScore::Strong {
 1077                    sort_text,
 1078                    score,
 1079                    sort_key,
 1080                }
 1081            } else {
 1082                MatchScore::Weak {
 1083                    score,
 1084                    sort_text,
 1085                    sort_key,
 1086                }
 1087            }
 1088        });
 1089
 1090        for mat in &mut matches {
 1091            let completion = &completions[mat.candidate_id];
 1092            mat.string = completion.label.text.clone();
 1093            for position in &mut mat.positions {
 1094                *position += completion.label.filter_range.start;
 1095            }
 1096        }
 1097        drop(completions);
 1098
 1099        self.matches = matches.into();
 1100        self.selected_item = 0;
 1101    }
 1102}
 1103
 1104#[derive(Clone)]
 1105struct CodeActionsMenu {
 1106    actions: Arc<[CodeAction]>,
 1107    buffer: Model<Buffer>,
 1108    selected_item: usize,
 1109    scroll_handle: UniformListScrollHandle,
 1110    deployed_from_indicator: bool,
 1111}
 1112
 1113impl CodeActionsMenu {
 1114    fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
 1115        self.selected_item = 0;
 1116        self.scroll_handle.scroll_to_item(self.selected_item);
 1117        cx.notify()
 1118    }
 1119
 1120    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
 1121        if self.selected_item > 0 {
 1122            self.selected_item -= 1;
 1123        } else {
 1124            self.selected_item = self.actions.len() - 1;
 1125        }
 1126        self.scroll_handle.scroll_to_item(self.selected_item);
 1127        cx.notify();
 1128    }
 1129
 1130    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
 1131        if self.selected_item + 1 < self.actions.len() {
 1132            self.selected_item += 1;
 1133        } else {
 1134            self.selected_item = 0;
 1135        }
 1136        self.scroll_handle.scroll_to_item(self.selected_item);
 1137        cx.notify();
 1138    }
 1139
 1140    fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
 1141        self.selected_item = self.actions.len() - 1;
 1142        self.scroll_handle.scroll_to_item(self.selected_item);
 1143        cx.notify()
 1144    }
 1145
 1146    fn visible(&self) -> bool {
 1147        !self.actions.is_empty()
 1148    }
 1149
 1150    fn render(
 1151        &self,
 1152        mut cursor_position: DisplayPoint,
 1153        _style: &EditorStyle,
 1154        max_height: Pixels,
 1155        cx: &mut ViewContext<Editor>,
 1156    ) -> (DisplayPoint, AnyElement) {
 1157        let actions = self.actions.clone();
 1158        let selected_item = self.selected_item;
 1159
 1160        let element = uniform_list(
 1161            cx.view().clone(),
 1162            "code_actions_menu",
 1163            self.actions.len(),
 1164            move |_this, range, cx| {
 1165                actions[range.clone()]
 1166                    .iter()
 1167                    .enumerate()
 1168                    .map(|(ix, action)| {
 1169                        let item_ix = range.start + ix;
 1170                        let selected = selected_item == item_ix;
 1171                        let colors = cx.theme().colors();
 1172                        div()
 1173                            .px_2()
 1174                            .text_color(colors.text)
 1175                            .when(selected, |style| {
 1176                                style
 1177                                    .bg(colors.element_active)
 1178                                    .text_color(colors.text_accent)
 1179                            })
 1180                            .hover(|style| {
 1181                                style
 1182                                    .bg(colors.element_hover)
 1183                                    .text_color(colors.text_accent)
 1184                            })
 1185                            .on_mouse_down(
 1186                                MouseButton::Left,
 1187                                cx.listener(move |editor, _, cx| {
 1188                                    cx.stop_propagation();
 1189                                    if let Some(task) = editor.confirm_code_action(
 1190                                        &ConfirmCodeAction {
 1191                                            item_ix: Some(item_ix),
 1192                                        },
 1193                                        cx,
 1194                                    ) {
 1195                                        task.detach_and_log_err(cx)
 1196                                    }
 1197                                }),
 1198                            )
 1199                            .whitespace_nowrap()
 1200                            // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
 1201                            .child(SharedString::from(action.lsp_action.title.clone()))
 1202                    })
 1203                    .collect()
 1204            },
 1205        )
 1206        .elevation_1(cx)
 1207        .px_2()
 1208        .py_1()
 1209        .max_h(max_height)
 1210        .track_scroll(self.scroll_handle.clone())
 1211        .with_width_from_item(
 1212            self.actions
 1213                .iter()
 1214                .enumerate()
 1215                .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
 1216                .map(|(ix, _)| ix),
 1217        )
 1218        .into_any_element();
 1219
 1220        if self.deployed_from_indicator {
 1221            *cursor_position.column_mut() = 0;
 1222        }
 1223
 1224        (cursor_position, element)
 1225    }
 1226}
 1227
 1228#[derive(Debug)]
 1229pub(crate) struct CopilotState {
 1230    excerpt_id: Option<ExcerptId>,
 1231    pending_refresh: Task<Option<()>>,
 1232    pending_cycling_refresh: Task<Option<()>>,
 1233    cycled: bool,
 1234    completions: Vec<copilot::Completion>,
 1235    active_completion_index: usize,
 1236    suggestion: Option<Inlay>,
 1237}
 1238
 1239impl Default for CopilotState {
 1240    fn default() -> Self {
 1241        Self {
 1242            excerpt_id: None,
 1243            pending_cycling_refresh: Task::ready(Some(())),
 1244            pending_refresh: Task::ready(Some(())),
 1245            completions: Default::default(),
 1246            active_completion_index: 0,
 1247            cycled: false,
 1248            suggestion: None,
 1249        }
 1250    }
 1251}
 1252
 1253impl CopilotState {
 1254    fn active_completion(&self) -> Option<&copilot::Completion> {
 1255        self.completions.get(self.active_completion_index)
 1256    }
 1257
 1258    fn text_for_active_completion(
 1259        &self,
 1260        cursor: Anchor,
 1261        buffer: &MultiBufferSnapshot,
 1262    ) -> Option<&str> {
 1263        use language::ToOffset as _;
 1264
 1265        let completion = self.active_completion()?;
 1266        let excerpt_id = self.excerpt_id?;
 1267        let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
 1268        if excerpt_id != cursor.excerpt_id
 1269            || !completion.range.start.is_valid(completion_buffer)
 1270            || !completion.range.end.is_valid(completion_buffer)
 1271        {
 1272            return None;
 1273        }
 1274
 1275        let mut completion_range = completion.range.to_offset(&completion_buffer);
 1276        let prefix_len = Self::common_prefix(
 1277            completion_buffer.chars_for_range(completion_range.clone()),
 1278            completion.text.chars(),
 1279        );
 1280        completion_range.start += prefix_len;
 1281        let suffix_len = Self::common_prefix(
 1282            completion_buffer.reversed_chars_for_range(completion_range.clone()),
 1283            completion.text[prefix_len..].chars().rev(),
 1284        );
 1285        completion_range.end = completion_range.end.saturating_sub(suffix_len);
 1286
 1287        if completion_range.is_empty()
 1288            && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer)
 1289        {
 1290            let completion_text = &completion.text[prefix_len..completion.text.len() - suffix_len];
 1291            if completion_text.trim().is_empty() {
 1292                None
 1293            } else {
 1294                Some(completion_text)
 1295            }
 1296        } else {
 1297            None
 1298        }
 1299    }
 1300
 1301    fn cycle_completions(&mut self, direction: Direction) {
 1302        match direction {
 1303            Direction::Prev => {
 1304                self.active_completion_index = if self.active_completion_index == 0 {
 1305                    self.completions.len().saturating_sub(1)
 1306                } else {
 1307                    self.active_completion_index - 1
 1308                };
 1309            }
 1310            Direction::Next => {
 1311                if self.completions.len() == 0 {
 1312                    self.active_completion_index = 0
 1313                } else {
 1314                    self.active_completion_index =
 1315                        (self.active_completion_index + 1) % self.completions.len();
 1316                }
 1317            }
 1318        }
 1319    }
 1320
 1321    fn push_completion(&mut self, new_completion: copilot::Completion) {
 1322        for completion in &self.completions {
 1323            if completion.text == new_completion.text && completion.range == new_completion.range {
 1324                return;
 1325            }
 1326        }
 1327        self.completions.push(new_completion);
 1328    }
 1329
 1330    fn common_prefix<T1: Iterator<Item = char>, T2: Iterator<Item = char>>(a: T1, b: T2) -> usize {
 1331        a.zip(b)
 1332            .take_while(|(a, b)| a == b)
 1333            .map(|(a, _)| a.len_utf8())
 1334            .sum()
 1335    }
 1336}
 1337
 1338#[derive(Debug)]
 1339struct ActiveDiagnosticGroup {
 1340    primary_range: Range<Anchor>,
 1341    primary_message: String,
 1342    blocks: HashMap<BlockId, Diagnostic>,
 1343    is_valid: bool,
 1344}
 1345
 1346#[derive(Serialize, Deserialize)]
 1347pub struct ClipboardSelection {
 1348    pub len: usize,
 1349    pub is_entire_line: bool,
 1350    pub first_line_indent: u32,
 1351}
 1352
 1353#[derive(Debug)]
 1354pub(crate) struct NavigationData {
 1355    cursor_anchor: Anchor,
 1356    cursor_position: Point,
 1357    scroll_anchor: ScrollAnchor,
 1358    scroll_top_row: u32,
 1359}
 1360
 1361enum GotoDefinitionKind {
 1362    Symbol,
 1363    Type,
 1364    Implementation,
 1365}
 1366
 1367#[derive(Debug, Clone)]
 1368enum InlayHintRefreshReason {
 1369    Toggle(bool),
 1370    SettingsChange(InlayHintSettings),
 1371    NewLinesShown,
 1372    BufferEdited(HashSet<Arc<Language>>),
 1373    RefreshRequested,
 1374    ExcerptsRemoved(Vec<ExcerptId>),
 1375}
 1376
 1377impl InlayHintRefreshReason {
 1378    fn description(&self) -> &'static str {
 1379        match self {
 1380            Self::Toggle(_) => "toggle",
 1381            Self::SettingsChange(_) => "settings change",
 1382            Self::NewLinesShown => "new lines shown",
 1383            Self::BufferEdited(_) => "buffer edited",
 1384            Self::RefreshRequested => "refresh requested",
 1385            Self::ExcerptsRemoved(_) => "excerpts removed",
 1386        }
 1387    }
 1388}
 1389
 1390impl Editor {
 1391    pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
 1392        let buffer = cx.new_model(|cx| {
 1393            Buffer::new(
 1394                0,
 1395                BufferId::new(cx.entity_id().as_u64()).unwrap(),
 1396                String::new(),
 1397            )
 1398        });
 1399        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1400        Self::new(EditorMode::SingleLine, buffer, None, cx)
 1401    }
 1402
 1403    pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
 1404        let buffer = cx.new_model(|cx| {
 1405            Buffer::new(
 1406                0,
 1407                BufferId::new(cx.entity_id().as_u64()).unwrap(),
 1408                String::new(),
 1409            )
 1410        });
 1411        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1412        Self::new(EditorMode::Full, buffer, None, cx)
 1413    }
 1414
 1415    pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
 1416        let buffer = cx.new_model(|cx| {
 1417            Buffer::new(
 1418                0,
 1419                BufferId::new(cx.entity_id().as_u64()).unwrap(),
 1420                String::new(),
 1421            )
 1422        });
 1423        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1424        Self::new(EditorMode::AutoHeight { max_lines }, buffer, None, cx)
 1425    }
 1426
 1427    pub fn for_buffer(
 1428        buffer: Model<Buffer>,
 1429        project: Option<Model<Project>>,
 1430        cx: &mut ViewContext<Self>,
 1431    ) -> Self {
 1432        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1433        Self::new(EditorMode::Full, buffer, project, cx)
 1434    }
 1435
 1436    pub fn for_multibuffer(
 1437        buffer: Model<MultiBuffer>,
 1438        project: Option<Model<Project>>,
 1439        cx: &mut ViewContext<Self>,
 1440    ) -> Self {
 1441        Self::new(EditorMode::Full, buffer, project, cx)
 1442    }
 1443
 1444    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
 1445        let mut clone = Self::new(self.mode, self.buffer.clone(), self.project.clone(), cx);
 1446        self.display_map.update(cx, |display_map, cx| {
 1447            let snapshot = display_map.snapshot(cx);
 1448            clone.display_map.update(cx, |display_map, cx| {
 1449                display_map.set_state(&snapshot, cx);
 1450            });
 1451        });
 1452        clone.selections.clone_state(&self.selections);
 1453        clone.scroll_manager.clone_state(&self.scroll_manager);
 1454        clone.searchable = self.searchable;
 1455        clone
 1456    }
 1457
 1458    fn new(
 1459        mode: EditorMode,
 1460        buffer: Model<MultiBuffer>,
 1461        project: Option<Model<Project>>,
 1462        cx: &mut ViewContext<Self>,
 1463    ) -> Self {
 1464        let style = cx.text_style();
 1465        let font_size = style.font_size.to_pixels(cx.rem_size());
 1466        let display_map = cx.new_model(|cx| {
 1467            DisplayMap::new(buffer.clone(), style.font(), font_size, None, 2, 1, cx)
 1468        });
 1469
 1470        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1471
 1472        let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1473
 1474        let soft_wrap_mode_override =
 1475            (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1476
 1477        let mut project_subscriptions = Vec::new();
 1478        if mode == EditorMode::Full {
 1479            if let Some(project) = project.as_ref() {
 1480                if buffer.read(cx).is_singleton() {
 1481                    project_subscriptions.push(cx.observe(project, |_, _, cx| {
 1482                        cx.emit(EditorEvent::TitleChanged);
 1483                    }));
 1484                }
 1485                project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
 1486                    if let project::Event::RefreshInlayHints = event {
 1487                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1488                    };
 1489                }));
 1490            }
 1491        }
 1492
 1493        let inlay_hint_settings = inlay_hint_settings(
 1494            selections.newest_anchor().head(),
 1495            &buffer.read(cx).snapshot(cx),
 1496            cx,
 1497        );
 1498
 1499        let focus_handle = cx.focus_handle();
 1500        cx.on_focus(&focus_handle, Self::handle_focus).detach();
 1501        cx.on_blur(&focus_handle, Self::handle_blur).detach();
 1502
 1503        let mut this = Self {
 1504            focus_handle,
 1505            buffer: buffer.clone(),
 1506            display_map: display_map.clone(),
 1507            selections,
 1508            scroll_manager: ScrollManager::new(cx),
 1509            columnar_selection_tail: None,
 1510            add_selections_state: None,
 1511            select_next_state: None,
 1512            select_prev_state: None,
 1513            selection_history: Default::default(),
 1514            autoclose_regions: Default::default(),
 1515            snippet_stack: Default::default(),
 1516            select_larger_syntax_node_stack: Vec::new(),
 1517            ime_transaction: Default::default(),
 1518            active_diagnostics: None,
 1519            soft_wrap_mode_override,
 1520            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1521            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1522            project,
 1523            blink_manager: blink_manager.clone(),
 1524            show_local_selections: true,
 1525            mode,
 1526            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1527            show_gutter: mode == EditorMode::Full,
 1528            show_wrap_guides: None,
 1529            placeholder_text: None,
 1530            highlight_order: 0,
 1531            highlighted_rows: HashMap::default(),
 1532            background_highlights: Default::default(),
 1533            nav_history: None,
 1534            context_menu: RwLock::new(None),
 1535            mouse_context_menu: None,
 1536            completion_tasks: Default::default(),
 1537            next_completion_id: 0,
 1538            completion_documentation_pre_resolve_debounce: DebouncedDelay::new(),
 1539            next_inlay_id: 0,
 1540            available_code_actions: Default::default(),
 1541            code_actions_task: Default::default(),
 1542            document_highlights_task: Default::default(),
 1543            pending_rename: Default::default(),
 1544            searchable: true,
 1545            cursor_shape: Default::default(),
 1546            autoindent_mode: Some(AutoindentMode::EachLine),
 1547            collapse_matches: false,
 1548            workspace: None,
 1549            keymap_context_layers: Default::default(),
 1550            input_enabled: true,
 1551            use_modal_editing: mode == EditorMode::Full,
 1552            read_only: false,
 1553            use_autoclose: true,
 1554            auto_replace_emoji_shortcode: false,
 1555            leader_peer_id: None,
 1556            remote_id: None,
 1557            hover_state: Default::default(),
 1558            hovered_link_state: Default::default(),
 1559            copilot_state: Default::default(),
 1560            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1561            gutter_hovered: false,
 1562            pixel_position_of_newest_cursor: None,
 1563            gutter_width: Default::default(),
 1564            style: None,
 1565            show_cursor_names: false,
 1566            hovered_cursors: Default::default(),
 1567            editor_actions: Default::default(),
 1568            show_copilot_suggestions: mode == EditorMode::Full,
 1569            custom_context_menu: None,
 1570            _subscriptions: vec![
 1571                cx.observe(&buffer, Self::on_buffer_changed),
 1572                cx.subscribe(&buffer, Self::on_buffer_event),
 1573                cx.observe(&display_map, Self::on_display_map_changed),
 1574                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1575                cx.observe_global::<SettingsStore>(Self::settings_changed),
 1576                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1577                cx.observe_window_activation(|editor, cx| {
 1578                    let active = cx.is_window_active();
 1579                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1580                        if active {
 1581                            blink_manager.enable(cx);
 1582                        } else {
 1583                            blink_manager.show_cursor(cx);
 1584                            blink_manager.disable(cx);
 1585                        }
 1586                    });
 1587                }),
 1588            ],
 1589        };
 1590
 1591        this._subscriptions.extend(project_subscriptions);
 1592
 1593        this.end_selection(cx);
 1594        this.scroll_manager.show_scrollbar(cx);
 1595
 1596        if mode == EditorMode::Full {
 1597            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1598            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1599        }
 1600
 1601        this.report_editor_event("open", None, cx);
 1602        this
 1603    }
 1604
 1605    fn key_context(&self, cx: &AppContext) -> KeyContext {
 1606        let mut key_context = KeyContext::default();
 1607        key_context.add("Editor");
 1608        let mode = match self.mode {
 1609            EditorMode::SingleLine => "single_line",
 1610            EditorMode::AutoHeight { .. } => "auto_height",
 1611            EditorMode::Full => "full",
 1612        };
 1613        key_context.set("mode", mode);
 1614        if self.pending_rename.is_some() {
 1615            key_context.add("renaming");
 1616        }
 1617        if self.context_menu_visible() {
 1618            match self.context_menu.read().as_ref() {
 1619                Some(ContextMenu::Completions(_)) => {
 1620                    key_context.add("menu");
 1621                    key_context.add("showing_completions")
 1622                }
 1623                Some(ContextMenu::CodeActions(_)) => {
 1624                    key_context.add("menu");
 1625                    key_context.add("showing_code_actions")
 1626                }
 1627                None => {}
 1628            }
 1629        }
 1630
 1631        for layer in self.keymap_context_layers.values() {
 1632            key_context.extend(layer);
 1633        }
 1634
 1635        if let Some(extension) = self
 1636            .buffer
 1637            .read(cx)
 1638            .as_singleton()
 1639            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
 1640        {
 1641            key_context.set("extension", extension.to_string());
 1642        }
 1643
 1644        if self.has_active_copilot_suggestion(cx) {
 1645            key_context.add("copilot_suggestion");
 1646        }
 1647
 1648        key_context
 1649    }
 1650
 1651    pub fn new_file(
 1652        workspace: &mut Workspace,
 1653        _: &workspace::NewFile,
 1654        cx: &mut ViewContext<Workspace>,
 1655    ) {
 1656        let project = workspace.project().clone();
 1657        if project.read(cx).is_remote() {
 1658            cx.propagate();
 1659        } else if let Some(buffer) = project
 1660            .update(cx, |project, cx| project.create_buffer("", None, cx))
 1661            .log_err()
 1662        {
 1663            workspace.add_item_to_active_pane(
 1664                Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
 1665                cx,
 1666            );
 1667        }
 1668    }
 1669
 1670    pub fn new_file_in_direction(
 1671        workspace: &mut Workspace,
 1672        action: &workspace::NewFileInDirection,
 1673        cx: &mut ViewContext<Workspace>,
 1674    ) {
 1675        let project = workspace.project().clone();
 1676        if project.read(cx).is_remote() {
 1677            cx.propagate();
 1678        } else if let Some(buffer) = project
 1679            .update(cx, |project, cx| project.create_buffer("", None, cx))
 1680            .log_err()
 1681        {
 1682            workspace.split_item(
 1683                action.0,
 1684                Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
 1685                cx,
 1686            );
 1687        }
 1688    }
 1689
 1690    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
 1691        self.buffer.read(cx).replica_id()
 1692    }
 1693
 1694    pub fn leader_peer_id(&self) -> Option<PeerId> {
 1695        self.leader_peer_id
 1696    }
 1697
 1698    pub fn buffer(&self) -> &Model<MultiBuffer> {
 1699        &self.buffer
 1700    }
 1701
 1702    pub fn workspace(&self) -> Option<View<Workspace>> {
 1703        self.workspace.as_ref()?.0.upgrade()
 1704    }
 1705
 1706    pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
 1707        self.buffer().read(cx).title(cx)
 1708    }
 1709
 1710    pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
 1711        EditorSnapshot {
 1712            mode: self.mode,
 1713            show_gutter: self.show_gutter,
 1714            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 1715            scroll_anchor: self.scroll_manager.anchor(),
 1716            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 1717            placeholder_text: self.placeholder_text.clone(),
 1718            is_focused: self.focus_handle.is_focused(cx),
 1719        }
 1720    }
 1721
 1722    pub fn language_at<T: ToOffset>(&self, point: T, cx: &AppContext) -> Option<Arc<Language>> {
 1723        self.buffer.read(cx).language_at(point, cx)
 1724    }
 1725
 1726    pub fn file_at<T: ToOffset>(
 1727        &self,
 1728        point: T,
 1729        cx: &AppContext,
 1730    ) -> Option<Arc<dyn language::File>> {
 1731        self.buffer.read(cx).read(cx).file_at(point).cloned()
 1732    }
 1733
 1734    pub fn active_excerpt(
 1735        &self,
 1736        cx: &AppContext,
 1737    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
 1738        self.buffer
 1739            .read(cx)
 1740            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 1741    }
 1742
 1743    pub fn mode(&self) -> EditorMode {
 1744        self.mode
 1745    }
 1746
 1747    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 1748        self.collaboration_hub.as_deref()
 1749    }
 1750
 1751    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 1752        self.collaboration_hub = Some(hub);
 1753    }
 1754
 1755    pub fn set_custom_context_menu(
 1756        &mut self,
 1757        f: impl 'static
 1758            + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
 1759    ) {
 1760        self.custom_context_menu = Some(Box::new(f))
 1761    }
 1762
 1763    pub fn set_completion_provider(&mut self, hub: Box<dyn CompletionProvider>) {
 1764        self.completion_provider = Some(hub);
 1765    }
 1766
 1767    pub fn placeholder_text(&self, _cx: &mut WindowContext) -> Option<&str> {
 1768        self.placeholder_text.as_deref()
 1769    }
 1770
 1771    pub fn set_placeholder_text(
 1772        &mut self,
 1773        placeholder_text: impl Into<Arc<str>>,
 1774        cx: &mut ViewContext<Self>,
 1775    ) {
 1776        let placeholder_text = Some(placeholder_text.into());
 1777        if self.placeholder_text != placeholder_text {
 1778            self.placeholder_text = placeholder_text;
 1779            cx.notify();
 1780        }
 1781    }
 1782
 1783    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
 1784        self.cursor_shape = cursor_shape;
 1785        cx.notify();
 1786    }
 1787
 1788    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 1789        self.collapse_matches = collapse_matches;
 1790    }
 1791
 1792    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 1793        if self.collapse_matches {
 1794            return range.start..range.start;
 1795        }
 1796        range.clone()
 1797    }
 1798
 1799    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
 1800        if self.display_map.read(cx).clip_at_line_ends != clip {
 1801            self.display_map
 1802                .update(cx, |map, _| map.clip_at_line_ends = clip);
 1803        }
 1804    }
 1805
 1806    pub fn set_keymap_context_layer<Tag: 'static>(
 1807        &mut self,
 1808        context: KeyContext,
 1809        cx: &mut ViewContext<Self>,
 1810    ) {
 1811        self.keymap_context_layers
 1812            .insert(TypeId::of::<Tag>(), context);
 1813        cx.notify();
 1814    }
 1815
 1816    pub fn remove_keymap_context_layer<Tag: 'static>(&mut self, cx: &mut ViewContext<Self>) {
 1817        self.keymap_context_layers.remove(&TypeId::of::<Tag>());
 1818        cx.notify();
 1819    }
 1820
 1821    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 1822        self.input_enabled = input_enabled;
 1823    }
 1824
 1825    pub fn set_autoindent(&mut self, autoindent: bool) {
 1826        if autoindent {
 1827            self.autoindent_mode = Some(AutoindentMode::EachLine);
 1828        } else {
 1829            self.autoindent_mode = None;
 1830        }
 1831    }
 1832
 1833    pub fn read_only(&self, cx: &AppContext) -> bool {
 1834        self.read_only || self.buffer.read(cx).read_only()
 1835    }
 1836
 1837    pub fn set_read_only(&mut self, read_only: bool) {
 1838        self.read_only = read_only;
 1839    }
 1840
 1841    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 1842        self.use_autoclose = autoclose;
 1843    }
 1844
 1845    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 1846        self.auto_replace_emoji_shortcode = auto_replace;
 1847    }
 1848
 1849    pub fn set_show_copilot_suggestions(&mut self, show_copilot_suggestions: bool) {
 1850        self.show_copilot_suggestions = show_copilot_suggestions;
 1851    }
 1852
 1853    pub fn set_use_modal_editing(&mut self, to: bool) {
 1854        self.use_modal_editing = to;
 1855    }
 1856
 1857    pub fn use_modal_editing(&self) -> bool {
 1858        self.use_modal_editing
 1859    }
 1860
 1861    fn selections_did_change(
 1862        &mut self,
 1863        local: bool,
 1864        old_cursor_position: &Anchor,
 1865        cx: &mut ViewContext<Self>,
 1866    ) {
 1867        if self.focus_handle.is_focused(cx) && self.leader_peer_id.is_none() {
 1868            self.buffer.update(cx, |buffer, cx| {
 1869                buffer.set_active_selections(
 1870                    &self.selections.disjoint_anchors(),
 1871                    self.selections.line_mode,
 1872                    self.cursor_shape,
 1873                    cx,
 1874                )
 1875            });
 1876        }
 1877
 1878        let display_map = self
 1879            .display_map
 1880            .update(cx, |display_map, cx| display_map.snapshot(cx));
 1881        let buffer = &display_map.buffer_snapshot;
 1882        self.add_selections_state = None;
 1883        self.select_next_state = None;
 1884        self.select_prev_state = None;
 1885        self.select_larger_syntax_node_stack.clear();
 1886        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 1887        self.snippet_stack
 1888            .invalidate(&self.selections.disjoint_anchors(), buffer);
 1889        self.take_rename(false, cx);
 1890
 1891        let new_cursor_position = self.selections.newest_anchor().head();
 1892
 1893        self.push_to_nav_history(
 1894            *old_cursor_position,
 1895            Some(new_cursor_position.to_point(buffer)),
 1896            cx,
 1897        );
 1898
 1899        if local {
 1900            let new_cursor_position = self.selections.newest_anchor().head();
 1901            let mut context_menu = self.context_menu.write();
 1902            let completion_menu = match context_menu.as_ref() {
 1903                Some(ContextMenu::Completions(menu)) => Some(menu),
 1904
 1905                _ => {
 1906                    *context_menu = None;
 1907                    None
 1908                }
 1909            };
 1910
 1911            if let Some(completion_menu) = completion_menu {
 1912                let cursor_position = new_cursor_position.to_offset(buffer);
 1913                let (word_range, kind) = buffer.surrounding_word(completion_menu.initial_position);
 1914                if kind == Some(CharKind::Word)
 1915                    && word_range.to_inclusive().contains(&cursor_position)
 1916                {
 1917                    let mut completion_menu = completion_menu.clone();
 1918                    drop(context_menu);
 1919
 1920                    let query = Self::completion_query(buffer, cursor_position);
 1921                    cx.spawn(move |this, mut cx| async move {
 1922                        completion_menu
 1923                            .filter(query.as_deref(), cx.background_executor().clone())
 1924                            .await;
 1925
 1926                        this.update(&mut cx, |this, cx| {
 1927                            let mut context_menu = this.context_menu.write();
 1928                            let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
 1929                                return;
 1930                            };
 1931
 1932                            if menu.id > completion_menu.id {
 1933                                return;
 1934                            }
 1935
 1936                            *context_menu = Some(ContextMenu::Completions(completion_menu));
 1937                            drop(context_menu);
 1938                            cx.notify();
 1939                        })
 1940                    })
 1941                    .detach();
 1942
 1943                    self.show_completions(&ShowCompletions, cx);
 1944                } else {
 1945                    drop(context_menu);
 1946                    self.hide_context_menu(cx);
 1947                }
 1948            } else {
 1949                drop(context_menu);
 1950            }
 1951
 1952            hide_hover(self, cx);
 1953
 1954            if old_cursor_position.to_display_point(&display_map).row()
 1955                != new_cursor_position.to_display_point(&display_map).row()
 1956            {
 1957                self.available_code_actions.take();
 1958            }
 1959            self.refresh_code_actions(cx);
 1960            self.refresh_document_highlights(cx);
 1961            refresh_matching_bracket_highlights(self, cx);
 1962            self.discard_copilot_suggestion(cx);
 1963        }
 1964
 1965        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 1966        cx.emit(EditorEvent::SelectionsChanged { local });
 1967
 1968        if self.selections.disjoint_anchors().len() == 1 {
 1969            cx.emit(SearchEvent::ActiveMatchChanged)
 1970        }
 1971
 1972        cx.notify();
 1973    }
 1974
 1975    pub fn change_selections<R>(
 1976        &mut self,
 1977        autoscroll: Option<Autoscroll>,
 1978        cx: &mut ViewContext<Self>,
 1979        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 1980    ) -> R {
 1981        let old_cursor_position = self.selections.newest_anchor().head();
 1982        self.push_to_selection_history();
 1983
 1984        let (changed, result) = self.selections.change_with(cx, change);
 1985
 1986        if changed {
 1987            if let Some(autoscroll) = autoscroll {
 1988                self.request_autoscroll(autoscroll, cx);
 1989            }
 1990            self.selections_did_change(true, &old_cursor_position, cx);
 1991        }
 1992
 1993        result
 1994    }
 1995
 1996    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 1997    where
 1998        I: IntoIterator<Item = (Range<S>, T)>,
 1999        S: ToOffset,
 2000        T: Into<Arc<str>>,
 2001    {
 2002        if self.read_only(cx) {
 2003            return;
 2004        }
 2005
 2006        self.buffer
 2007            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2008    }
 2009
 2010    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 2011    where
 2012        I: IntoIterator<Item = (Range<S>, T)>,
 2013        S: ToOffset,
 2014        T: Into<Arc<str>>,
 2015    {
 2016        if self.read_only(cx) {
 2017            return;
 2018        }
 2019
 2020        self.buffer.update(cx, |buffer, cx| {
 2021            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2022        });
 2023    }
 2024
 2025    pub fn edit_with_block_indent<I, S, T>(
 2026        &mut self,
 2027        edits: I,
 2028        original_indent_columns: Vec<u32>,
 2029        cx: &mut ViewContext<Self>,
 2030    ) where
 2031        I: IntoIterator<Item = (Range<S>, T)>,
 2032        S: ToOffset,
 2033        T: Into<Arc<str>>,
 2034    {
 2035        if self.read_only(cx) {
 2036            return;
 2037        }
 2038
 2039        self.buffer.update(cx, |buffer, cx| {
 2040            buffer.edit(
 2041                edits,
 2042                Some(AutoindentMode::Block {
 2043                    original_indent_columns,
 2044                }),
 2045                cx,
 2046            )
 2047        });
 2048    }
 2049
 2050    fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
 2051        self.hide_context_menu(cx);
 2052
 2053        match phase {
 2054            SelectPhase::Begin {
 2055                position,
 2056                add,
 2057                click_count,
 2058            } => self.begin_selection(position, add, click_count, cx),
 2059            SelectPhase::BeginColumnar {
 2060                position,
 2061                goal_column,
 2062            } => self.begin_columnar_selection(position, goal_column, cx),
 2063            SelectPhase::Extend {
 2064                position,
 2065                click_count,
 2066            } => self.extend_selection(position, click_count, cx),
 2067            SelectPhase::Update {
 2068                position,
 2069                goal_column,
 2070                scroll_delta,
 2071            } => self.update_selection(position, goal_column, scroll_delta, cx),
 2072            SelectPhase::End => self.end_selection(cx),
 2073        }
 2074    }
 2075
 2076    fn extend_selection(
 2077        &mut self,
 2078        position: DisplayPoint,
 2079        click_count: usize,
 2080        cx: &mut ViewContext<Self>,
 2081    ) {
 2082        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2083        let tail = self.selections.newest::<usize>(cx).tail();
 2084        self.begin_selection(position, false, click_count, cx);
 2085
 2086        let position = position.to_offset(&display_map, Bias::Left);
 2087        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2088
 2089        let mut pending_selection = self
 2090            .selections
 2091            .pending_anchor()
 2092            .expect("extend_selection not called with pending selection");
 2093        if position >= tail {
 2094            pending_selection.start = tail_anchor;
 2095        } else {
 2096            pending_selection.end = tail_anchor;
 2097            pending_selection.reversed = true;
 2098        }
 2099
 2100        let mut pending_mode = self.selections.pending_mode().unwrap();
 2101        match &mut pending_mode {
 2102            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2103            _ => {}
 2104        }
 2105
 2106        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2107            s.set_pending(pending_selection, pending_mode)
 2108        });
 2109    }
 2110
 2111    fn begin_selection(
 2112        &mut self,
 2113        position: DisplayPoint,
 2114        add: bool,
 2115        click_count: usize,
 2116        cx: &mut ViewContext<Self>,
 2117    ) {
 2118        if !self.focus_handle.is_focused(cx) {
 2119            cx.focus(&self.focus_handle);
 2120        }
 2121
 2122        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2123        let buffer = &display_map.buffer_snapshot;
 2124        let newest_selection = self.selections.newest_anchor().clone();
 2125        let position = display_map.clip_point(position, Bias::Left);
 2126
 2127        let start;
 2128        let end;
 2129        let mode;
 2130        let auto_scroll;
 2131        match click_count {
 2132            1 => {
 2133                start = buffer.anchor_before(position.to_point(&display_map));
 2134                end = start;
 2135                mode = SelectMode::Character;
 2136                auto_scroll = true;
 2137            }
 2138            2 => {
 2139                let range = movement::surrounding_word(&display_map, position);
 2140                start = buffer.anchor_before(range.start.to_point(&display_map));
 2141                end = buffer.anchor_before(range.end.to_point(&display_map));
 2142                mode = SelectMode::Word(start..end);
 2143                auto_scroll = true;
 2144            }
 2145            3 => {
 2146                let position = display_map
 2147                    .clip_point(position, Bias::Left)
 2148                    .to_point(&display_map);
 2149                let line_start = display_map.prev_line_boundary(position).0;
 2150                let next_line_start = buffer.clip_point(
 2151                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2152                    Bias::Left,
 2153                );
 2154                start = buffer.anchor_before(line_start);
 2155                end = buffer.anchor_before(next_line_start);
 2156                mode = SelectMode::Line(start..end);
 2157                auto_scroll = true;
 2158            }
 2159            _ => {
 2160                start = buffer.anchor_before(0);
 2161                end = buffer.anchor_before(buffer.len());
 2162                mode = SelectMode::All;
 2163                auto_scroll = false;
 2164            }
 2165        }
 2166
 2167        self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
 2168            if !add {
 2169                s.clear_disjoint();
 2170            } else if click_count > 1 {
 2171                s.delete(newest_selection.id)
 2172            }
 2173
 2174            s.set_pending_anchor_range(start..end, mode);
 2175        });
 2176    }
 2177
 2178    fn begin_columnar_selection(
 2179        &mut self,
 2180        position: DisplayPoint,
 2181        goal_column: u32,
 2182        cx: &mut ViewContext<Self>,
 2183    ) {
 2184        if !self.focus_handle.is_focused(cx) {
 2185            cx.focus(&self.focus_handle);
 2186        }
 2187
 2188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2189        let tail = self.selections.newest::<Point>(cx).tail();
 2190        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2191
 2192        self.select_columns(
 2193            tail.to_display_point(&display_map),
 2194            position,
 2195            goal_column,
 2196            &display_map,
 2197            cx,
 2198        );
 2199    }
 2200
 2201    fn update_selection(
 2202        &mut self,
 2203        position: DisplayPoint,
 2204        goal_column: u32,
 2205        scroll_delta: gpui::Point<f32>,
 2206        cx: &mut ViewContext<Self>,
 2207    ) {
 2208        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2209
 2210        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2211            let tail = tail.to_display_point(&display_map);
 2212            self.select_columns(tail, position, goal_column, &display_map, cx);
 2213        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2214            let buffer = self.buffer.read(cx).snapshot(cx);
 2215            let head;
 2216            let tail;
 2217            let mode = self.selections.pending_mode().unwrap();
 2218            match &mode {
 2219                SelectMode::Character => {
 2220                    head = position.to_point(&display_map);
 2221                    tail = pending.tail().to_point(&buffer);
 2222                }
 2223                SelectMode::Word(original_range) => {
 2224                    let original_display_range = original_range.start.to_display_point(&display_map)
 2225                        ..original_range.end.to_display_point(&display_map);
 2226                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2227                        ..original_display_range.end.to_point(&display_map);
 2228                    if movement::is_inside_word(&display_map, position)
 2229                        || original_display_range.contains(&position)
 2230                    {
 2231                        let word_range = movement::surrounding_word(&display_map, position);
 2232                        if word_range.start < original_display_range.start {
 2233                            head = word_range.start.to_point(&display_map);
 2234                        } else {
 2235                            head = word_range.end.to_point(&display_map);
 2236                        }
 2237                    } else {
 2238                        head = position.to_point(&display_map);
 2239                    }
 2240
 2241                    if head <= original_buffer_range.start {
 2242                        tail = original_buffer_range.end;
 2243                    } else {
 2244                        tail = original_buffer_range.start;
 2245                    }
 2246                }
 2247                SelectMode::Line(original_range) => {
 2248                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 2249
 2250                    let position = display_map
 2251                        .clip_point(position, Bias::Left)
 2252                        .to_point(&display_map);
 2253                    let line_start = display_map.prev_line_boundary(position).0;
 2254                    let next_line_start = buffer.clip_point(
 2255                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2256                        Bias::Left,
 2257                    );
 2258
 2259                    if line_start < original_range.start {
 2260                        head = line_start
 2261                    } else {
 2262                        head = next_line_start
 2263                    }
 2264
 2265                    if head <= original_range.start {
 2266                        tail = original_range.end;
 2267                    } else {
 2268                        tail = original_range.start;
 2269                    }
 2270                }
 2271                SelectMode::All => {
 2272                    return;
 2273                }
 2274            };
 2275
 2276            if head < tail {
 2277                pending.start = buffer.anchor_before(head);
 2278                pending.end = buffer.anchor_before(tail);
 2279                pending.reversed = true;
 2280            } else {
 2281                pending.start = buffer.anchor_before(tail);
 2282                pending.end = buffer.anchor_before(head);
 2283                pending.reversed = false;
 2284            }
 2285
 2286            self.change_selections(None, cx, |s| {
 2287                s.set_pending(pending, mode);
 2288            });
 2289        } else {
 2290            log::error!("update_selection dispatched with no pending selection");
 2291            return;
 2292        }
 2293
 2294        self.apply_scroll_delta(scroll_delta, cx);
 2295        cx.notify();
 2296    }
 2297
 2298    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
 2299        self.columnar_selection_tail.take();
 2300        if self.selections.pending_anchor().is_some() {
 2301            let selections = self.selections.all::<usize>(cx);
 2302            self.change_selections(None, cx, |s| {
 2303                s.select(selections);
 2304                s.clear_pending();
 2305            });
 2306        }
 2307    }
 2308
 2309    fn select_columns(
 2310        &mut self,
 2311        tail: DisplayPoint,
 2312        head: DisplayPoint,
 2313        goal_column: u32,
 2314        display_map: &DisplaySnapshot,
 2315        cx: &mut ViewContext<Self>,
 2316    ) {
 2317        let start_row = cmp::min(tail.row(), head.row());
 2318        let end_row = cmp::max(tail.row(), head.row());
 2319        let start_column = cmp::min(tail.column(), goal_column);
 2320        let end_column = cmp::max(tail.column(), goal_column);
 2321        let reversed = start_column < tail.column();
 2322
 2323        let selection_ranges = (start_row..=end_row)
 2324            .filter_map(|row| {
 2325                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 2326                    let start = display_map
 2327                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 2328                        .to_point(display_map);
 2329                    let end = display_map
 2330                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 2331                        .to_point(display_map);
 2332                    if reversed {
 2333                        Some(end..start)
 2334                    } else {
 2335                        Some(start..end)
 2336                    }
 2337                } else {
 2338                    None
 2339                }
 2340            })
 2341            .collect::<Vec<_>>();
 2342
 2343        self.change_selections(None, cx, |s| {
 2344            s.select_ranges(selection_ranges);
 2345        });
 2346        cx.notify();
 2347    }
 2348
 2349    pub fn has_pending_nonempty_selection(&self) -> bool {
 2350        let pending_nonempty_selection = match self.selections.pending_anchor() {
 2351            Some(Selection { start, end, .. }) => start != end,
 2352            None => false,
 2353        };
 2354        pending_nonempty_selection || self.columnar_selection_tail.is_some()
 2355    }
 2356
 2357    pub fn has_pending_selection(&self) -> bool {
 2358        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 2359    }
 2360
 2361    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
 2362        if self.dismiss_menus_and_popups(cx) {
 2363            return;
 2364        }
 2365
 2366        if self.mode == EditorMode::Full {
 2367            if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
 2368                return;
 2369            }
 2370        }
 2371
 2372        cx.propagate();
 2373    }
 2374
 2375    pub fn dismiss_menus_and_popups(&mut self, cx: &mut ViewContext<Self>) -> bool {
 2376        if self.take_rename(false, cx).is_some() {
 2377            return true;
 2378        }
 2379
 2380        if hide_hover(self, cx) {
 2381            return true;
 2382        }
 2383
 2384        if self.hide_context_menu(cx).is_some() {
 2385            return true;
 2386        }
 2387
 2388        if self.discard_copilot_suggestion(cx) {
 2389            return true;
 2390        }
 2391
 2392        if self.snippet_stack.pop().is_some() {
 2393            return true;
 2394        }
 2395
 2396        if self.mode == EditorMode::Full {
 2397            if self.active_diagnostics.is_some() {
 2398                self.dismiss_diagnostics(cx);
 2399                return true;
 2400            }
 2401        }
 2402
 2403        false
 2404    }
 2405
 2406    pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 2407        let text: Arc<str> = text.into();
 2408
 2409        if self.read_only(cx) {
 2410            return;
 2411        }
 2412
 2413        let selections = self.selections.all_adjusted(cx);
 2414        let mut brace_inserted = false;
 2415        let mut edits = Vec::new();
 2416        let mut new_selections = Vec::with_capacity(selections.len());
 2417        let mut new_autoclose_regions = Vec::new();
 2418        let snapshot = self.buffer.read(cx).read(cx);
 2419
 2420        for (selection, autoclose_region) in
 2421            self.selections_with_autoclose_regions(selections, &snapshot)
 2422        {
 2423            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 2424                // Determine if the inserted text matches the opening or closing
 2425                // bracket of any of this language's bracket pairs.
 2426                let mut bracket_pair = None;
 2427                let mut is_bracket_pair_start = false;
 2428                if !text.is_empty() {
 2429                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 2430                    //  and they are removing the character that triggered IME popup.
 2431                    for (pair, enabled) in scope.brackets() {
 2432                        if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
 2433                            bracket_pair = Some(pair.clone());
 2434                            is_bracket_pair_start = true;
 2435                            break;
 2436                        } else if pair.end.as_str() == text.as_ref() {
 2437                            bracket_pair = Some(pair.clone());
 2438                            break;
 2439                        }
 2440                    }
 2441                }
 2442
 2443                if let Some(bracket_pair) = bracket_pair {
 2444                    if selection.is_empty() {
 2445                        if is_bracket_pair_start {
 2446                            let prefix_len = bracket_pair.start.len() - text.len();
 2447
 2448                            // If the inserted text is a suffix of an opening bracket and the
 2449                            // selection is preceded by the rest of the opening bracket, then
 2450                            // insert the closing bracket.
 2451                            let following_text_allows_autoclose = snapshot
 2452                                .chars_at(selection.start)
 2453                                .next()
 2454                                .map_or(true, |c| scope.should_autoclose_before(c));
 2455                            let preceding_text_matches_prefix = prefix_len == 0
 2456                                || (selection.start.column >= (prefix_len as u32)
 2457                                    && snapshot.contains_str_at(
 2458                                        Point::new(
 2459                                            selection.start.row,
 2460                                            selection.start.column - (prefix_len as u32),
 2461                                        ),
 2462                                        &bracket_pair.start[..prefix_len],
 2463                                    ));
 2464                            let autoclose = self.use_autoclose
 2465                                && snapshot.settings_at(selection.start, cx).use_autoclose;
 2466                            if autoclose
 2467                                && following_text_allows_autoclose
 2468                                && preceding_text_matches_prefix
 2469                            {
 2470                                let anchor = snapshot.anchor_before(selection.end);
 2471                                new_selections.push((selection.map(|_| anchor), text.len()));
 2472                                new_autoclose_regions.push((
 2473                                    anchor,
 2474                                    text.len(),
 2475                                    selection.id,
 2476                                    bracket_pair.clone(),
 2477                                ));
 2478                                edits.push((
 2479                                    selection.range(),
 2480                                    format!("{}{}", text, bracket_pair.end).into(),
 2481                                ));
 2482                                brace_inserted = true;
 2483                                continue;
 2484                            }
 2485                        }
 2486
 2487                        if let Some(region) = autoclose_region {
 2488                            // If the selection is followed by an auto-inserted closing bracket,
 2489                            // then don't insert that closing bracket again; just move the selection
 2490                            // past the closing bracket.
 2491                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 2492                                && text.as_ref() == region.pair.end.as_str();
 2493                            if should_skip {
 2494                                let anchor = snapshot.anchor_after(selection.end);
 2495                                new_selections
 2496                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 2497                                continue;
 2498                            }
 2499                        }
 2500                    }
 2501                    // If an opening bracket is 1 character long and is typed while
 2502                    // text is selected, then surround that text with the bracket pair.
 2503                    else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
 2504                        edits.push((selection.start..selection.start, text.clone()));
 2505                        edits.push((
 2506                            selection.end..selection.end,
 2507                            bracket_pair.end.as_str().into(),
 2508                        ));
 2509                        brace_inserted = true;
 2510                        new_selections.push((
 2511                            Selection {
 2512                                id: selection.id,
 2513                                start: snapshot.anchor_after(selection.start),
 2514                                end: snapshot.anchor_before(selection.end),
 2515                                reversed: selection.reversed,
 2516                                goal: selection.goal,
 2517                            },
 2518                            0,
 2519                        ));
 2520                        continue;
 2521                    }
 2522                }
 2523            }
 2524
 2525            if self.auto_replace_emoji_shortcode
 2526                && selection.is_empty()
 2527                && text.as_ref().ends_with(':')
 2528            {
 2529                if let Some(possible_emoji_short_code) =
 2530                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 2531                {
 2532                    if !possible_emoji_short_code.is_empty() {
 2533                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 2534                            let emoji_shortcode_start = Point::new(
 2535                                selection.start.row,
 2536                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 2537                            );
 2538
 2539                            // Remove shortcode from buffer
 2540                            edits.push((
 2541                                emoji_shortcode_start..selection.start,
 2542                                "".to_string().into(),
 2543                            ));
 2544                            new_selections.push((
 2545                                Selection {
 2546                                    id: selection.id,
 2547                                    start: snapshot.anchor_after(emoji_shortcode_start),
 2548                                    end: snapshot.anchor_before(selection.start),
 2549                                    reversed: selection.reversed,
 2550                                    goal: selection.goal,
 2551                                },
 2552                                0,
 2553                            ));
 2554
 2555                            // Insert emoji
 2556                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 2557                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 2558                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 2559
 2560                            continue;
 2561                        }
 2562                    }
 2563                }
 2564            }
 2565
 2566            // If not handling any auto-close operation, then just replace the selected
 2567            // text with the given input and move the selection to the end of the
 2568            // newly inserted text.
 2569            let anchor = snapshot.anchor_after(selection.end);
 2570            new_selections.push((selection.map(|_| anchor), 0));
 2571            edits.push((selection.start..selection.end, text.clone()));
 2572        }
 2573
 2574        drop(snapshot);
 2575        self.transact(cx, |this, cx| {
 2576            this.buffer.update(cx, |buffer, cx| {
 2577                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 2578            });
 2579
 2580            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 2581            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 2582            let snapshot = this.buffer.read(cx).read(cx);
 2583            let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
 2584                .zip(new_selection_deltas)
 2585                .map(|(selection, delta)| Selection {
 2586                    id: selection.id,
 2587                    start: selection.start + delta,
 2588                    end: selection.end + delta,
 2589                    reversed: selection.reversed,
 2590                    goal: SelectionGoal::None,
 2591                })
 2592                .collect::<Vec<_>>();
 2593
 2594            let mut i = 0;
 2595            for (position, delta, selection_id, pair) in new_autoclose_regions {
 2596                let position = position.to_offset(&snapshot) + delta;
 2597                let start = snapshot.anchor_before(position);
 2598                let end = snapshot.anchor_after(position);
 2599                while let Some(existing_state) = this.autoclose_regions.get(i) {
 2600                    match existing_state.range.start.cmp(&start, &snapshot) {
 2601                        Ordering::Less => i += 1,
 2602                        Ordering::Greater => break,
 2603                        Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
 2604                            Ordering::Less => i += 1,
 2605                            Ordering::Equal => break,
 2606                            Ordering::Greater => break,
 2607                        },
 2608                    }
 2609                }
 2610                this.autoclose_regions.insert(
 2611                    i,
 2612                    AutocloseRegion {
 2613                        selection_id,
 2614                        range: start..end,
 2615                        pair,
 2616                    },
 2617                );
 2618            }
 2619
 2620            drop(snapshot);
 2621            let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
 2622            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 2623
 2624            if brace_inserted {
 2625                // If we inserted a brace while composing text (i.e. typing `"` on a
 2626                // Brazilian keyboard), exit the composing state because most likely
 2627                // the user wanted to surround the selection.
 2628                this.unmark_text(cx);
 2629            } else if EditorSettings::get_global(cx).use_on_type_format {
 2630                if let Some(on_type_format_task) =
 2631                    this.trigger_on_type_formatting(text.to_string(), cx)
 2632                {
 2633                    on_type_format_task.detach_and_log_err(cx);
 2634                }
 2635            }
 2636
 2637            if had_active_copilot_suggestion {
 2638                this.refresh_copilot_suggestions(true, cx);
 2639                if !this.has_active_copilot_suggestion(cx) {
 2640                    this.trigger_completion_on_input(&text, cx);
 2641                }
 2642            } else {
 2643                this.trigger_completion_on_input(&text, cx);
 2644                this.refresh_copilot_suggestions(true, cx);
 2645            }
 2646        });
 2647    }
 2648
 2649    fn find_possible_emoji_shortcode_at_position(
 2650        snapshot: &MultiBufferSnapshot,
 2651        position: Point,
 2652    ) -> Option<String> {
 2653        let mut chars = Vec::new();
 2654        let mut found_colon = false;
 2655        for char in snapshot.reversed_chars_at(position).take(100) {
 2656            // Found a possible emoji shortcode in the middle of the buffer
 2657            if found_colon {
 2658                if char.is_whitespace() {
 2659                    chars.reverse();
 2660                    return Some(chars.iter().collect());
 2661                }
 2662                // If the previous character is not a whitespace, we are in the middle of a word
 2663                // and we only want to complete the shortcode if the word is made up of other emojis
 2664                let mut containing_word = String::new();
 2665                for ch in snapshot
 2666                    .reversed_chars_at(position)
 2667                    .skip(chars.len() + 1)
 2668                    .take(100)
 2669                {
 2670                    if ch.is_whitespace() {
 2671                        break;
 2672                    }
 2673                    containing_word.push(ch);
 2674                }
 2675                let containing_word = containing_word.chars().rev().collect::<String>();
 2676                if util::word_consists_of_emojis(containing_word.as_str()) {
 2677                    chars.reverse();
 2678                    return Some(chars.iter().collect());
 2679                }
 2680            }
 2681
 2682            if char.is_whitespace() || !char.is_ascii() {
 2683                return None;
 2684            }
 2685            if char == ':' {
 2686                found_colon = true;
 2687            } else {
 2688                chars.push(char);
 2689            }
 2690        }
 2691        // Found a possible emoji shortcode at the beginning of the buffer
 2692        chars.reverse();
 2693        Some(chars.iter().collect())
 2694    }
 2695
 2696    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
 2697        self.transact(cx, |this, cx| {
 2698            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 2699                let selections = this.selections.all::<usize>(cx);
 2700                let multi_buffer = this.buffer.read(cx);
 2701                let buffer = multi_buffer.snapshot(cx);
 2702                selections
 2703                    .iter()
 2704                    .map(|selection| {
 2705                        let start_point = selection.start.to_point(&buffer);
 2706                        let mut indent = buffer.indent_size_for_line(start_point.row);
 2707                        indent.len = cmp::min(indent.len, start_point.column);
 2708                        let start = selection.start;
 2709                        let end = selection.end;
 2710                        let is_cursor = start == end;
 2711                        let language_scope = buffer.language_scope_at(start);
 2712                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 2713                            &language_scope
 2714                        {
 2715                            let leading_whitespace_len = buffer
 2716                                .reversed_chars_at(start)
 2717                                .take_while(|c| c.is_whitespace() && *c != '\n')
 2718                                .map(|c| c.len_utf8())
 2719                                .sum::<usize>();
 2720
 2721                            let trailing_whitespace_len = buffer
 2722                                .chars_at(end)
 2723                                .take_while(|c| c.is_whitespace() && *c != '\n')
 2724                                .map(|c| c.len_utf8())
 2725                                .sum::<usize>();
 2726
 2727                            let insert_extra_newline =
 2728                                language.brackets().any(|(pair, enabled)| {
 2729                                    let pair_start = pair.start.trim_end();
 2730                                    let pair_end = pair.end.trim_start();
 2731
 2732                                    enabled
 2733                                        && pair.newline
 2734                                        && buffer.contains_str_at(
 2735                                            end + trailing_whitespace_len,
 2736                                            pair_end,
 2737                                        )
 2738                                        && buffer.contains_str_at(
 2739                                            (start - leading_whitespace_len)
 2740                                                .saturating_sub(pair_start.len()),
 2741                                            pair_start,
 2742                                        )
 2743                                });
 2744                            // Comment extension on newline is allowed only for cursor selections
 2745                            let comment_delimiter = language.line_comment_prefixes().filter(|_| {
 2746                                let is_comment_extension_enabled =
 2747                                    multi_buffer.settings_at(0, cx).extend_comment_on_newline;
 2748                                is_cursor && is_comment_extension_enabled
 2749                            });
 2750                            let get_comment_delimiter = |delimiters: &[Arc<str>]| {
 2751                                let max_len_of_delimiter =
 2752                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 2753                                let (snapshot, range) =
 2754                                    buffer.buffer_line_for_row(start_point.row)?;
 2755
 2756                                let mut index_of_first_non_whitespace = 0;
 2757                                let comment_candidate = snapshot
 2758                                    .chars_for_range(range)
 2759                                    .skip_while(|c| {
 2760                                        let should_skip = c.is_whitespace();
 2761                                        if should_skip {
 2762                                            index_of_first_non_whitespace += 1;
 2763                                        }
 2764                                        should_skip
 2765                                    })
 2766                                    .take(max_len_of_delimiter)
 2767                                    .collect::<String>();
 2768                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 2769                                    comment_candidate.starts_with(comment_prefix.as_ref())
 2770                                })?;
 2771                                let cursor_is_placed_after_comment_marker =
 2772                                    index_of_first_non_whitespace + comment_prefix.len()
 2773                                        <= start_point.column as usize;
 2774                                if cursor_is_placed_after_comment_marker {
 2775                                    Some(comment_prefix.clone())
 2776                                } else {
 2777                                    None
 2778                                }
 2779                            };
 2780                            let comment_delimiter = if let Some(delimiters) = comment_delimiter {
 2781                                get_comment_delimiter(delimiters)
 2782                            } else {
 2783                                None
 2784                            };
 2785                            (comment_delimiter, insert_extra_newline)
 2786                        } else {
 2787                            (None, false)
 2788                        };
 2789
 2790                        let capacity_for_delimiter = comment_delimiter
 2791                            .as_deref()
 2792                            .map(str::len)
 2793                            .unwrap_or_default();
 2794                        let mut new_text =
 2795                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 2796                        new_text.push_str("\n");
 2797                        new_text.extend(indent.chars());
 2798                        if let Some(delimiter) = &comment_delimiter {
 2799                            new_text.push_str(&delimiter);
 2800                        }
 2801                        if insert_extra_newline {
 2802                            new_text = new_text.repeat(2);
 2803                        }
 2804
 2805                        let anchor = buffer.anchor_after(end);
 2806                        let new_selection = selection.map(|_| anchor);
 2807                        (
 2808                            (start..end, new_text),
 2809                            (insert_extra_newline, new_selection),
 2810                        )
 2811                    })
 2812                    .unzip()
 2813            };
 2814
 2815            this.edit_with_autoindent(edits, cx);
 2816            let buffer = this.buffer.read(cx).snapshot(cx);
 2817            let new_selections = selection_fixup_info
 2818                .into_iter()
 2819                .map(|(extra_newline_inserted, new_selection)| {
 2820                    let mut cursor = new_selection.end.to_point(&buffer);
 2821                    if extra_newline_inserted {
 2822                        cursor.row -= 1;
 2823                        cursor.column = buffer.line_len(cursor.row);
 2824                    }
 2825                    new_selection.map(|_| cursor)
 2826                })
 2827                .collect();
 2828
 2829            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 2830            this.refresh_copilot_suggestions(true, cx);
 2831        });
 2832    }
 2833
 2834    pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
 2835        let buffer = self.buffer.read(cx);
 2836        let snapshot = buffer.snapshot(cx);
 2837
 2838        let mut edits = Vec::new();
 2839        let mut rows = Vec::new();
 2840
 2841        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 2842            let cursor = selection.head();
 2843            let row = cursor.row;
 2844
 2845            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 2846
 2847            let newline = "\n".to_string();
 2848            edits.push((start_of_line..start_of_line, newline));
 2849
 2850            rows.push(row + rows_inserted as u32);
 2851        }
 2852
 2853        self.transact(cx, |editor, cx| {
 2854            editor.edit(edits, cx);
 2855
 2856            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2857                let mut index = 0;
 2858                s.move_cursors_with(|map, _, _| {
 2859                    let row = rows[index];
 2860                    index += 1;
 2861
 2862                    let point = Point::new(row, 0);
 2863                    let boundary = map.next_line_boundary(point).1;
 2864                    let clipped = map.clip_point(boundary, Bias::Left);
 2865
 2866                    (clipped, SelectionGoal::None)
 2867                });
 2868            });
 2869
 2870            let mut indent_edits = Vec::new();
 2871            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 2872            for row in rows {
 2873                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 2874                for (row, indent) in indents {
 2875                    if indent.len == 0 {
 2876                        continue;
 2877                    }
 2878
 2879                    let text = match indent.kind {
 2880                        IndentKind::Space => " ".repeat(indent.len as usize),
 2881                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 2882                    };
 2883                    let point = Point::new(row, 0);
 2884                    indent_edits.push((point..point, text));
 2885                }
 2886            }
 2887            editor.edit(indent_edits, cx);
 2888        });
 2889    }
 2890
 2891    pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
 2892        let buffer = self.buffer.read(cx);
 2893        let snapshot = buffer.snapshot(cx);
 2894
 2895        let mut edits = Vec::new();
 2896        let mut rows = Vec::new();
 2897        let mut rows_inserted = 0;
 2898
 2899        for selection in self.selections.all_adjusted(cx) {
 2900            let cursor = selection.head();
 2901            let row = cursor.row;
 2902
 2903            let point = Point::new(row + 1, 0);
 2904            let start_of_line = snapshot.clip_point(point, Bias::Left);
 2905
 2906            let newline = "\n".to_string();
 2907            edits.push((start_of_line..start_of_line, newline));
 2908
 2909            rows_inserted += 1;
 2910            rows.push(row + rows_inserted);
 2911        }
 2912
 2913        self.transact(cx, |editor, cx| {
 2914            editor.edit(edits, cx);
 2915
 2916            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2917                let mut index = 0;
 2918                s.move_cursors_with(|map, _, _| {
 2919                    let row = rows[index];
 2920                    index += 1;
 2921
 2922                    let point = Point::new(row, 0);
 2923                    let boundary = map.next_line_boundary(point).1;
 2924                    let clipped = map.clip_point(boundary, Bias::Left);
 2925
 2926                    (clipped, SelectionGoal::None)
 2927                });
 2928            });
 2929
 2930            let mut indent_edits = Vec::new();
 2931            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 2932            for row in rows {
 2933                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 2934                for (row, indent) in indents {
 2935                    if indent.len == 0 {
 2936                        continue;
 2937                    }
 2938
 2939                    let text = match indent.kind {
 2940                        IndentKind::Space => " ".repeat(indent.len as usize),
 2941                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 2942                    };
 2943                    let point = Point::new(row, 0);
 2944                    indent_edits.push((point..point, text));
 2945                }
 2946            }
 2947            editor.edit(indent_edits, cx);
 2948        });
 2949    }
 2950
 2951    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 2952        self.insert_with_autoindent_mode(
 2953            text,
 2954            Some(AutoindentMode::Block {
 2955                original_indent_columns: Vec::new(),
 2956            }),
 2957            cx,
 2958        );
 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::worktree::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        }
 5699    }
 5700
 5701    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
 5702        if self.read_only(cx) {
 5703            return;
 5704        }
 5705
 5706        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
 5707            if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
 5708            {
 5709                self.change_selections(None, cx, |s| {
 5710                    s.select_anchors(selections.to_vec());
 5711                });
 5712            }
 5713            self.request_autoscroll(Autoscroll::fit(), cx);
 5714            self.unmark_text(cx);
 5715            self.refresh_copilot_suggestions(true, cx);
 5716            cx.emit(EditorEvent::Edited);
 5717        }
 5718    }
 5719
 5720    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
 5721        self.buffer
 5722            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
 5723    }
 5724
 5725    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
 5726        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5727            let line_mode = s.line_mode;
 5728            s.move_with(|map, selection| {
 5729                let cursor = if selection.is_empty() && !line_mode {
 5730                    movement::left(map, selection.start)
 5731                } else {
 5732                    selection.start
 5733                };
 5734                selection.collapse_to(cursor, SelectionGoal::None);
 5735            });
 5736        })
 5737    }
 5738
 5739    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
 5740        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5741            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
 5742        })
 5743    }
 5744
 5745    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
 5746        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5747            let line_mode = s.line_mode;
 5748            s.move_with(|map, selection| {
 5749                let cursor = if selection.is_empty() && !line_mode {
 5750                    movement::right(map, selection.end)
 5751                } else {
 5752                    selection.end
 5753                };
 5754                selection.collapse_to(cursor, SelectionGoal::None)
 5755            });
 5756        })
 5757    }
 5758
 5759    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
 5760        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5761            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
 5762        })
 5763    }
 5764
 5765    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
 5766        if self.take_rename(true, cx).is_some() {
 5767            return;
 5768        }
 5769
 5770        if matches!(self.mode, EditorMode::SingleLine) {
 5771            cx.propagate();
 5772            return;
 5773        }
 5774
 5775        let text_layout_details = &self.text_layout_details(cx);
 5776
 5777        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5778            let line_mode = s.line_mode;
 5779            s.move_with(|map, selection| {
 5780                if !selection.is_empty() && !line_mode {
 5781                    selection.goal = SelectionGoal::None;
 5782                }
 5783                let (cursor, goal) = movement::up(
 5784                    map,
 5785                    selection.start,
 5786                    selection.goal,
 5787                    false,
 5788                    &text_layout_details,
 5789                );
 5790                selection.collapse_to(cursor, goal);
 5791            });
 5792        })
 5793    }
 5794
 5795    pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext<Self>) {
 5796        if self.take_rename(true, cx).is_some() {
 5797            return;
 5798        }
 5799
 5800        if matches!(self.mode, EditorMode::SingleLine) {
 5801            cx.propagate();
 5802            return;
 5803        }
 5804
 5805        let text_layout_details = &self.text_layout_details(cx);
 5806
 5807        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5808            let line_mode = s.line_mode;
 5809            s.move_with(|map, selection| {
 5810                if !selection.is_empty() && !line_mode {
 5811                    selection.goal = SelectionGoal::None;
 5812                }
 5813                let (cursor, goal) = movement::up_by_rows(
 5814                    map,
 5815                    selection.start,
 5816                    action.lines,
 5817                    selection.goal,
 5818                    false,
 5819                    &text_layout_details,
 5820                );
 5821                selection.collapse_to(cursor, goal);
 5822            });
 5823        })
 5824    }
 5825
 5826    pub fn move_down_by_lines(&mut self, action: &MoveDownByLines, cx: &mut ViewContext<Self>) {
 5827        if self.take_rename(true, cx).is_some() {
 5828            return;
 5829        }
 5830
 5831        if matches!(self.mode, EditorMode::SingleLine) {
 5832            cx.propagate();
 5833            return;
 5834        }
 5835
 5836        let text_layout_details = &self.text_layout_details(cx);
 5837
 5838        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5839            let line_mode = s.line_mode;
 5840            s.move_with(|map, selection| {
 5841                if !selection.is_empty() && !line_mode {
 5842                    selection.goal = SelectionGoal::None;
 5843                }
 5844                let (cursor, goal) = movement::down_by_rows(
 5845                    map,
 5846                    selection.start,
 5847                    action.lines,
 5848                    selection.goal,
 5849                    false,
 5850                    &text_layout_details,
 5851                );
 5852                selection.collapse_to(cursor, goal);
 5853            });
 5854        })
 5855    }
 5856
 5857    pub fn select_down_by_lines(&mut self, action: &SelectDownByLines, cx: &mut ViewContext<Self>) {
 5858        let text_layout_details = &self.text_layout_details(cx);
 5859        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5860            s.move_heads_with(|map, head, goal| {
 5861                movement::down_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 5862            })
 5863        })
 5864    }
 5865
 5866    pub fn select_up_by_lines(&mut self, action: &SelectUpByLines, cx: &mut ViewContext<Self>) {
 5867        let text_layout_details = &self.text_layout_details(cx);
 5868        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5869            s.move_heads_with(|map, head, goal| {
 5870                movement::up_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 5871            })
 5872        })
 5873    }
 5874
 5875    pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
 5876        if self.take_rename(true, cx).is_some() {
 5877            return;
 5878        }
 5879
 5880        if matches!(self.mode, EditorMode::SingleLine) {
 5881            cx.propagate();
 5882            return;
 5883        }
 5884
 5885        let row_count = if let Some(row_count) = self.visible_line_count() {
 5886            row_count as u32 - 1
 5887        } else {
 5888            return;
 5889        };
 5890
 5891        let autoscroll = if action.center_cursor {
 5892            Autoscroll::center()
 5893        } else {
 5894            Autoscroll::fit()
 5895        };
 5896
 5897        let text_layout_details = &self.text_layout_details(cx);
 5898
 5899        self.change_selections(Some(autoscroll), cx, |s| {
 5900            let line_mode = s.line_mode;
 5901            s.move_with(|map, selection| {
 5902                if !selection.is_empty() && !line_mode {
 5903                    selection.goal = SelectionGoal::None;
 5904                }
 5905                let (cursor, goal) = movement::up_by_rows(
 5906                    map,
 5907                    selection.end,
 5908                    row_count,
 5909                    selection.goal,
 5910                    false,
 5911                    &text_layout_details,
 5912                );
 5913                selection.collapse_to(cursor, goal);
 5914            });
 5915        });
 5916    }
 5917
 5918    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
 5919        let text_layout_details = &self.text_layout_details(cx);
 5920        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5921            s.move_heads_with(|map, head, goal| {
 5922                movement::up(map, head, goal, false, &text_layout_details)
 5923            })
 5924        })
 5925    }
 5926
 5927    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
 5928        self.take_rename(true, cx);
 5929
 5930        if self.mode == EditorMode::SingleLine {
 5931            cx.propagate();
 5932            return;
 5933        }
 5934
 5935        let text_layout_details = &self.text_layout_details(cx);
 5936        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5937            let line_mode = s.line_mode;
 5938            s.move_with(|map, selection| {
 5939                if !selection.is_empty() && !line_mode {
 5940                    selection.goal = SelectionGoal::None;
 5941                }
 5942                let (cursor, goal) = movement::down(
 5943                    map,
 5944                    selection.end,
 5945                    selection.goal,
 5946                    false,
 5947                    &text_layout_details,
 5948                );
 5949                selection.collapse_to(cursor, goal);
 5950            });
 5951        });
 5952    }
 5953
 5954    pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
 5955        if self.take_rename(true, cx).is_some() {
 5956            return;
 5957        }
 5958
 5959        if self
 5960            .context_menu
 5961            .write()
 5962            .as_mut()
 5963            .map(|menu| menu.select_last(self.project.as_ref(), cx))
 5964            .unwrap_or(false)
 5965        {
 5966            return;
 5967        }
 5968
 5969        if matches!(self.mode, EditorMode::SingleLine) {
 5970            cx.propagate();
 5971            return;
 5972        }
 5973
 5974        let row_count = if let Some(row_count) = self.visible_line_count() {
 5975            row_count as u32 - 1
 5976        } else {
 5977            return;
 5978        };
 5979
 5980        let autoscroll = if action.center_cursor {
 5981            Autoscroll::center()
 5982        } else {
 5983            Autoscroll::fit()
 5984        };
 5985
 5986        let text_layout_details = &self.text_layout_details(cx);
 5987        self.change_selections(Some(autoscroll), cx, |s| {
 5988            let line_mode = s.line_mode;
 5989            s.move_with(|map, selection| {
 5990                if !selection.is_empty() && !line_mode {
 5991                    selection.goal = SelectionGoal::None;
 5992                }
 5993                let (cursor, goal) = movement::down_by_rows(
 5994                    map,
 5995                    selection.end,
 5996                    row_count,
 5997                    selection.goal,
 5998                    false,
 5999                    &text_layout_details,
 6000                );
 6001                selection.collapse_to(cursor, goal);
 6002            });
 6003        });
 6004    }
 6005
 6006    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
 6007        let text_layout_details = &self.text_layout_details(cx);
 6008        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6009            s.move_heads_with(|map, head, goal| {
 6010                movement::down(map, head, goal, false, &text_layout_details)
 6011            })
 6012        });
 6013    }
 6014
 6015    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
 6016        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6017            context_menu.select_first(self.project.as_ref(), cx);
 6018        }
 6019    }
 6020
 6021    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
 6022        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6023            context_menu.select_prev(self.project.as_ref(), cx);
 6024        }
 6025    }
 6026
 6027    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
 6028        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6029            context_menu.select_next(self.project.as_ref(), cx);
 6030        }
 6031    }
 6032
 6033    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
 6034        if let Some(context_menu) = self.context_menu.write().as_mut() {
 6035            context_menu.select_last(self.project.as_ref(), cx);
 6036        }
 6037    }
 6038
 6039    pub fn move_to_previous_word_start(
 6040        &mut self,
 6041        _: &MoveToPreviousWordStart,
 6042        cx: &mut ViewContext<Self>,
 6043    ) {
 6044        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6045            s.move_cursors_with(|map, head, _| {
 6046                (
 6047                    movement::previous_word_start(map, head),
 6048                    SelectionGoal::None,
 6049                )
 6050            });
 6051        })
 6052    }
 6053
 6054    pub fn move_to_previous_subword_start(
 6055        &mut self,
 6056        _: &MoveToPreviousSubwordStart,
 6057        cx: &mut ViewContext<Self>,
 6058    ) {
 6059        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6060            s.move_cursors_with(|map, head, _| {
 6061                (
 6062                    movement::previous_subword_start(map, head),
 6063                    SelectionGoal::None,
 6064                )
 6065            });
 6066        })
 6067    }
 6068
 6069    pub fn select_to_previous_word_start(
 6070        &mut self,
 6071        _: &SelectToPreviousWordStart,
 6072        cx: &mut ViewContext<Self>,
 6073    ) {
 6074        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6075            s.move_heads_with(|map, head, _| {
 6076                (
 6077                    movement::previous_word_start(map, head),
 6078                    SelectionGoal::None,
 6079                )
 6080            });
 6081        })
 6082    }
 6083
 6084    pub fn select_to_previous_subword_start(
 6085        &mut self,
 6086        _: &SelectToPreviousSubwordStart,
 6087        cx: &mut ViewContext<Self>,
 6088    ) {
 6089        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6090            s.move_heads_with(|map, head, _| {
 6091                (
 6092                    movement::previous_subword_start(map, head),
 6093                    SelectionGoal::None,
 6094                )
 6095            });
 6096        })
 6097    }
 6098
 6099    pub fn delete_to_previous_word_start(
 6100        &mut self,
 6101        _: &DeleteToPreviousWordStart,
 6102        cx: &mut ViewContext<Self>,
 6103    ) {
 6104        self.transact(cx, |this, cx| {
 6105            this.select_autoclose_pair(cx);
 6106            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6107                let line_mode = s.line_mode;
 6108                s.move_with(|map, selection| {
 6109                    if selection.is_empty() && !line_mode {
 6110                        let cursor = movement::previous_word_start(map, selection.head());
 6111                        selection.set_head(cursor, SelectionGoal::None);
 6112                    }
 6113                });
 6114            });
 6115            this.insert("", cx);
 6116        });
 6117    }
 6118
 6119    pub fn delete_to_previous_subword_start(
 6120        &mut self,
 6121        _: &DeleteToPreviousSubwordStart,
 6122        cx: &mut ViewContext<Self>,
 6123    ) {
 6124        self.transact(cx, |this, cx| {
 6125            this.select_autoclose_pair(cx);
 6126            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6127                let line_mode = s.line_mode;
 6128                s.move_with(|map, selection| {
 6129                    if selection.is_empty() && !line_mode {
 6130                        let cursor = movement::previous_subword_start(map, selection.head());
 6131                        selection.set_head(cursor, SelectionGoal::None);
 6132                    }
 6133                });
 6134            });
 6135            this.insert("", cx);
 6136        });
 6137    }
 6138
 6139    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
 6140        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6141            s.move_cursors_with(|map, head, _| {
 6142                (movement::next_word_end(map, head), SelectionGoal::None)
 6143            });
 6144        })
 6145    }
 6146
 6147    pub fn move_to_next_subword_end(
 6148        &mut self,
 6149        _: &MoveToNextSubwordEnd,
 6150        cx: &mut ViewContext<Self>,
 6151    ) {
 6152        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6153            s.move_cursors_with(|map, head, _| {
 6154                (movement::next_subword_end(map, head), SelectionGoal::None)
 6155            });
 6156        })
 6157    }
 6158
 6159    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
 6160        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6161            s.move_heads_with(|map, head, _| {
 6162                (movement::next_word_end(map, head), SelectionGoal::None)
 6163            });
 6164        })
 6165    }
 6166
 6167    pub fn select_to_next_subword_end(
 6168        &mut self,
 6169        _: &SelectToNextSubwordEnd,
 6170        cx: &mut ViewContext<Self>,
 6171    ) {
 6172        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6173            s.move_heads_with(|map, head, _| {
 6174                (movement::next_subword_end(map, head), SelectionGoal::None)
 6175            });
 6176        })
 6177    }
 6178
 6179    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
 6180        self.transact(cx, |this, cx| {
 6181            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6182                let line_mode = s.line_mode;
 6183                s.move_with(|map, selection| {
 6184                    if selection.is_empty() && !line_mode {
 6185                        let cursor = movement::next_word_end(map, selection.head());
 6186                        selection.set_head(cursor, SelectionGoal::None);
 6187                    }
 6188                });
 6189            });
 6190            this.insert("", cx);
 6191        });
 6192    }
 6193
 6194    pub fn delete_to_next_subword_end(
 6195        &mut self,
 6196        _: &DeleteToNextSubwordEnd,
 6197        cx: &mut ViewContext<Self>,
 6198    ) {
 6199        self.transact(cx, |this, cx| {
 6200            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6201                s.move_with(|map, selection| {
 6202                    if selection.is_empty() {
 6203                        let cursor = movement::next_subword_end(map, selection.head());
 6204                        selection.set_head(cursor, SelectionGoal::None);
 6205                    }
 6206                });
 6207            });
 6208            this.insert("", cx);
 6209        });
 6210    }
 6211
 6212    pub fn move_to_beginning_of_line(
 6213        &mut self,
 6214        _: &MoveToBeginningOfLine,
 6215        cx: &mut ViewContext<Self>,
 6216    ) {
 6217        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6218            s.move_cursors_with(|map, head, _| {
 6219                (
 6220                    movement::indented_line_beginning(map, head, true),
 6221                    SelectionGoal::None,
 6222                )
 6223            });
 6224        })
 6225    }
 6226
 6227    pub fn select_to_beginning_of_line(
 6228        &mut self,
 6229        action: &SelectToBeginningOfLine,
 6230        cx: &mut ViewContext<Self>,
 6231    ) {
 6232        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6233            s.move_heads_with(|map, head, _| {
 6234                (
 6235                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 6236                    SelectionGoal::None,
 6237                )
 6238            });
 6239        });
 6240    }
 6241
 6242    pub fn delete_to_beginning_of_line(
 6243        &mut self,
 6244        _: &DeleteToBeginningOfLine,
 6245        cx: &mut ViewContext<Self>,
 6246    ) {
 6247        self.transact(cx, |this, cx| {
 6248            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6249                s.move_with(|_, selection| {
 6250                    selection.reversed = true;
 6251                });
 6252            });
 6253
 6254            this.select_to_beginning_of_line(
 6255                &SelectToBeginningOfLine {
 6256                    stop_at_soft_wraps: false,
 6257                },
 6258                cx,
 6259            );
 6260            this.backspace(&Backspace, cx);
 6261        });
 6262    }
 6263
 6264    pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
 6265        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6266            s.move_cursors_with(|map, head, _| {
 6267                (movement::line_end(map, head, true), SelectionGoal::None)
 6268            });
 6269        })
 6270    }
 6271
 6272    pub fn select_to_end_of_line(
 6273        &mut self,
 6274        action: &SelectToEndOfLine,
 6275        cx: &mut ViewContext<Self>,
 6276    ) {
 6277        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6278            s.move_heads_with(|map, head, _| {
 6279                (
 6280                    movement::line_end(map, head, action.stop_at_soft_wraps),
 6281                    SelectionGoal::None,
 6282                )
 6283            });
 6284        })
 6285    }
 6286
 6287    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
 6288        self.transact(cx, |this, cx| {
 6289            this.select_to_end_of_line(
 6290                &SelectToEndOfLine {
 6291                    stop_at_soft_wraps: false,
 6292                },
 6293                cx,
 6294            );
 6295            this.delete(&Delete, cx);
 6296        });
 6297    }
 6298
 6299    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
 6300        self.transact(cx, |this, cx| {
 6301            this.select_to_end_of_line(
 6302                &SelectToEndOfLine {
 6303                    stop_at_soft_wraps: false,
 6304                },
 6305                cx,
 6306            );
 6307            this.cut(&Cut, cx);
 6308        });
 6309    }
 6310
 6311    pub fn move_to_start_of_paragraph(
 6312        &mut self,
 6313        _: &MoveToStartOfParagraph,
 6314        cx: &mut ViewContext<Self>,
 6315    ) {
 6316        if matches!(self.mode, EditorMode::SingleLine) {
 6317            cx.propagate();
 6318            return;
 6319        }
 6320
 6321        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6322            s.move_with(|map, selection| {
 6323                selection.collapse_to(
 6324                    movement::start_of_paragraph(map, selection.head(), 1),
 6325                    SelectionGoal::None,
 6326                )
 6327            });
 6328        })
 6329    }
 6330
 6331    pub fn move_to_end_of_paragraph(
 6332        &mut self,
 6333        _: &MoveToEndOfParagraph,
 6334        cx: &mut ViewContext<Self>,
 6335    ) {
 6336        if matches!(self.mode, EditorMode::SingleLine) {
 6337            cx.propagate();
 6338            return;
 6339        }
 6340
 6341        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6342            s.move_with(|map, selection| {
 6343                selection.collapse_to(
 6344                    movement::end_of_paragraph(map, selection.head(), 1),
 6345                    SelectionGoal::None,
 6346                )
 6347            });
 6348        })
 6349    }
 6350
 6351    pub fn select_to_start_of_paragraph(
 6352        &mut self,
 6353        _: &SelectToStartOfParagraph,
 6354        cx: &mut ViewContext<Self>,
 6355    ) {
 6356        if matches!(self.mode, EditorMode::SingleLine) {
 6357            cx.propagate();
 6358            return;
 6359        }
 6360
 6361        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6362            s.move_heads_with(|map, head, _| {
 6363                (
 6364                    movement::start_of_paragraph(map, head, 1),
 6365                    SelectionGoal::None,
 6366                )
 6367            });
 6368        })
 6369    }
 6370
 6371    pub fn select_to_end_of_paragraph(
 6372        &mut self,
 6373        _: &SelectToEndOfParagraph,
 6374        cx: &mut ViewContext<Self>,
 6375    ) {
 6376        if matches!(self.mode, EditorMode::SingleLine) {
 6377            cx.propagate();
 6378            return;
 6379        }
 6380
 6381        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6382            s.move_heads_with(|map, head, _| {
 6383                (
 6384                    movement::end_of_paragraph(map, head, 1),
 6385                    SelectionGoal::None,
 6386                )
 6387            });
 6388        })
 6389    }
 6390
 6391    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
 6392        if matches!(self.mode, EditorMode::SingleLine) {
 6393            cx.propagate();
 6394            return;
 6395        }
 6396
 6397        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6398            s.select_ranges(vec![0..0]);
 6399        });
 6400    }
 6401
 6402    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
 6403        let mut selection = self.selections.last::<Point>(cx);
 6404        selection.set_head(Point::zero(), SelectionGoal::None);
 6405
 6406        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6407            s.select(vec![selection]);
 6408        });
 6409    }
 6410
 6411    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
 6412        if matches!(self.mode, EditorMode::SingleLine) {
 6413            cx.propagate();
 6414            return;
 6415        }
 6416
 6417        let cursor = self.buffer.read(cx).read(cx).len();
 6418        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6419            s.select_ranges(vec![cursor..cursor])
 6420        });
 6421    }
 6422
 6423    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
 6424        self.nav_history = nav_history;
 6425    }
 6426
 6427    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
 6428        self.nav_history.as_ref()
 6429    }
 6430
 6431    fn push_to_nav_history(
 6432        &mut self,
 6433        cursor_anchor: Anchor,
 6434        new_position: Option<Point>,
 6435        cx: &mut ViewContext<Self>,
 6436    ) {
 6437        if let Some(nav_history) = self.nav_history.as_mut() {
 6438            let buffer = self.buffer.read(cx).read(cx);
 6439            let cursor_position = cursor_anchor.to_point(&buffer);
 6440            let scroll_state = self.scroll_manager.anchor();
 6441            let scroll_top_row = scroll_state.top_row(&buffer);
 6442            drop(buffer);
 6443
 6444            if let Some(new_position) = new_position {
 6445                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
 6446                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
 6447                    return;
 6448                }
 6449            }
 6450
 6451            nav_history.push(
 6452                Some(NavigationData {
 6453                    cursor_anchor,
 6454                    cursor_position,
 6455                    scroll_anchor: scroll_state,
 6456                    scroll_top_row,
 6457                }),
 6458                cx,
 6459            );
 6460        }
 6461    }
 6462
 6463    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
 6464        let buffer = self.buffer.read(cx).snapshot(cx);
 6465        let mut selection = self.selections.first::<usize>(cx);
 6466        selection.set_head(buffer.len(), SelectionGoal::None);
 6467        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6468            s.select(vec![selection]);
 6469        });
 6470    }
 6471
 6472    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
 6473        let end = self.buffer.read(cx).read(cx).len();
 6474        self.change_selections(None, cx, |s| {
 6475            s.select_ranges(vec![0..end]);
 6476        });
 6477    }
 6478
 6479    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
 6480        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6481        let mut selections = self.selections.all::<Point>(cx);
 6482        let max_point = display_map.buffer_snapshot.max_point();
 6483        for selection in &mut selections {
 6484            let rows = selection.spanned_rows(true, &display_map);
 6485            selection.start = Point::new(rows.start, 0);
 6486            selection.end = cmp::min(max_point, Point::new(rows.end, 0));
 6487            selection.reversed = false;
 6488        }
 6489        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6490            s.select(selections);
 6491        });
 6492    }
 6493
 6494    pub fn split_selection_into_lines(
 6495        &mut self,
 6496        _: &SplitSelectionIntoLines,
 6497        cx: &mut ViewContext<Self>,
 6498    ) {
 6499        let mut to_unfold = Vec::new();
 6500        let mut new_selection_ranges = Vec::new();
 6501        {
 6502            let selections = self.selections.all::<Point>(cx);
 6503            let buffer = self.buffer.read(cx).read(cx);
 6504            for selection in selections {
 6505                for row in selection.start.row..selection.end.row {
 6506                    let cursor = Point::new(row, buffer.line_len(row));
 6507                    new_selection_ranges.push(cursor..cursor);
 6508                }
 6509                new_selection_ranges.push(selection.end..selection.end);
 6510                to_unfold.push(selection.start..selection.end);
 6511            }
 6512        }
 6513        self.unfold_ranges(to_unfold, true, true, cx);
 6514        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6515            s.select_ranges(new_selection_ranges);
 6516        });
 6517    }
 6518
 6519    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
 6520        self.add_selection(true, cx);
 6521    }
 6522
 6523    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
 6524        self.add_selection(false, cx);
 6525    }
 6526
 6527    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
 6528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6529        let mut selections = self.selections.all::<Point>(cx);
 6530        let text_layout_details = self.text_layout_details(cx);
 6531        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
 6532            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
 6533            let range = oldest_selection.display_range(&display_map).sorted();
 6534
 6535            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
 6536            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
 6537            let positions = start_x.min(end_x)..start_x.max(end_x);
 6538
 6539            selections.clear();
 6540            let mut stack = Vec::new();
 6541            for row in range.start.row()..=range.end.row() {
 6542                if let Some(selection) = self.selections.build_columnar_selection(
 6543                    &display_map,
 6544                    row,
 6545                    &positions,
 6546                    oldest_selection.reversed,
 6547                    &text_layout_details,
 6548                ) {
 6549                    stack.push(selection.id);
 6550                    selections.push(selection);
 6551                }
 6552            }
 6553
 6554            if above {
 6555                stack.reverse();
 6556            }
 6557
 6558            AddSelectionsState { above, stack }
 6559        });
 6560
 6561        let last_added_selection = *state.stack.last().unwrap();
 6562        let mut new_selections = Vec::new();
 6563        if above == state.above {
 6564            let end_row = if above {
 6565                0
 6566            } else {
 6567                display_map.max_point().row()
 6568            };
 6569
 6570            'outer: for selection in selections {
 6571                if selection.id == last_added_selection {
 6572                    let range = selection.display_range(&display_map).sorted();
 6573                    debug_assert_eq!(range.start.row(), range.end.row());
 6574                    let mut row = range.start.row();
 6575                    let positions =
 6576                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
 6577                            px(start)..px(end)
 6578                        } else {
 6579                            let start_x =
 6580                                display_map.x_for_display_point(range.start, &text_layout_details);
 6581                            let end_x =
 6582                                display_map.x_for_display_point(range.end, &text_layout_details);
 6583                            start_x.min(end_x)..start_x.max(end_x)
 6584                        };
 6585
 6586                    while row != end_row {
 6587                        if above {
 6588                            row -= 1;
 6589                        } else {
 6590                            row += 1;
 6591                        }
 6592
 6593                        if let Some(new_selection) = self.selections.build_columnar_selection(
 6594                            &display_map,
 6595                            row,
 6596                            &positions,
 6597                            selection.reversed,
 6598                            &text_layout_details,
 6599                        ) {
 6600                            state.stack.push(new_selection.id);
 6601                            if above {
 6602                                new_selections.push(new_selection);
 6603                                new_selections.push(selection);
 6604                            } else {
 6605                                new_selections.push(selection);
 6606                                new_selections.push(new_selection);
 6607                            }
 6608
 6609                            continue 'outer;
 6610                        }
 6611                    }
 6612                }
 6613
 6614                new_selections.push(selection);
 6615            }
 6616        } else {
 6617            new_selections = selections;
 6618            new_selections.retain(|s| s.id != last_added_selection);
 6619            state.stack.pop();
 6620        }
 6621
 6622        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6623            s.select(new_selections);
 6624        });
 6625        if state.stack.len() > 1 {
 6626            self.add_selections_state = Some(state);
 6627        }
 6628    }
 6629
 6630    pub fn select_next_match_internal(
 6631        &mut self,
 6632        display_map: &DisplaySnapshot,
 6633        replace_newest: bool,
 6634        autoscroll: Option<Autoscroll>,
 6635        cx: &mut ViewContext<Self>,
 6636    ) -> Result<()> {
 6637        fn select_next_match_ranges(
 6638            this: &mut Editor,
 6639            range: Range<usize>,
 6640            replace_newest: bool,
 6641            auto_scroll: Option<Autoscroll>,
 6642            cx: &mut ViewContext<Editor>,
 6643        ) {
 6644            this.unfold_ranges([range.clone()], false, true, cx);
 6645            this.change_selections(auto_scroll, cx, |s| {
 6646                if replace_newest {
 6647                    s.delete(s.newest_anchor().id);
 6648                }
 6649                s.insert_range(range.clone());
 6650            });
 6651        }
 6652
 6653        let buffer = &display_map.buffer_snapshot;
 6654        let mut selections = self.selections.all::<usize>(cx);
 6655        if let Some(mut select_next_state) = self.select_next_state.take() {
 6656            let query = &select_next_state.query;
 6657            if !select_next_state.done {
 6658                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 6659                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 6660                let mut next_selected_range = None;
 6661
 6662                let bytes_after_last_selection =
 6663                    buffer.bytes_in_range(last_selection.end..buffer.len());
 6664                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
 6665                let query_matches = query
 6666                    .stream_find_iter(bytes_after_last_selection)
 6667                    .map(|result| (last_selection.end, result))
 6668                    .chain(
 6669                        query
 6670                            .stream_find_iter(bytes_before_first_selection)
 6671                            .map(|result| (0, result)),
 6672                    );
 6673
 6674                for (start_offset, query_match) in query_matches {
 6675                    let query_match = query_match.unwrap(); // can only fail due to I/O
 6676                    let offset_range =
 6677                        start_offset + query_match.start()..start_offset + query_match.end();
 6678                    let display_range = offset_range.start.to_display_point(&display_map)
 6679                        ..offset_range.end.to_display_point(&display_map);
 6680
 6681                    if !select_next_state.wordwise
 6682                        || (!movement::is_inside_word(&display_map, display_range.start)
 6683                            && !movement::is_inside_word(&display_map, display_range.end))
 6684                    {
 6685                        // TODO: This is n^2, because we might check all the selections
 6686                        if !selections
 6687                            .iter()
 6688                            .any(|selection| selection.range().overlaps(&offset_range))
 6689                        {
 6690                            next_selected_range = Some(offset_range);
 6691                            break;
 6692                        }
 6693                    }
 6694                }
 6695
 6696                if let Some(next_selected_range) = next_selected_range {
 6697                    select_next_match_ranges(
 6698                        self,
 6699                        next_selected_range,
 6700                        replace_newest,
 6701                        autoscroll,
 6702                        cx,
 6703                    );
 6704                } else {
 6705                    select_next_state.done = true;
 6706                }
 6707            }
 6708
 6709            self.select_next_state = Some(select_next_state);
 6710        } else {
 6711            let mut only_carets = true;
 6712            let mut same_text_selected = true;
 6713            let mut selected_text = None;
 6714
 6715            let mut selections_iter = selections.iter().peekable();
 6716            while let Some(selection) = selections_iter.next() {
 6717                if selection.start != selection.end {
 6718                    only_carets = false;
 6719                }
 6720
 6721                if same_text_selected {
 6722                    if selected_text.is_none() {
 6723                        selected_text =
 6724                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 6725                    }
 6726
 6727                    if let Some(next_selection) = selections_iter.peek() {
 6728                        if next_selection.range().len() == selection.range().len() {
 6729                            let next_selected_text = buffer
 6730                                .text_for_range(next_selection.range())
 6731                                .collect::<String>();
 6732                            if Some(next_selected_text) != selected_text {
 6733                                same_text_selected = false;
 6734                                selected_text = None;
 6735                            }
 6736                        } else {
 6737                            same_text_selected = false;
 6738                            selected_text = None;
 6739                        }
 6740                    }
 6741                }
 6742            }
 6743
 6744            if only_carets {
 6745                for selection in &mut selections {
 6746                    let word_range = movement::surrounding_word(
 6747                        &display_map,
 6748                        selection.start.to_display_point(&display_map),
 6749                    );
 6750                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 6751                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 6752                    selection.goal = SelectionGoal::None;
 6753                    selection.reversed = false;
 6754                    select_next_match_ranges(
 6755                        self,
 6756                        selection.start..selection.end,
 6757                        replace_newest,
 6758                        autoscroll,
 6759                        cx,
 6760                    );
 6761                }
 6762
 6763                if selections.len() == 1 {
 6764                    let selection = selections
 6765                        .last()
 6766                        .expect("ensured that there's only one selection");
 6767                    let query = buffer
 6768                        .text_for_range(selection.start..selection.end)
 6769                        .collect::<String>();
 6770                    let is_empty = query.is_empty();
 6771                    let select_state = SelectNextState {
 6772                        query: AhoCorasick::new(&[query])?,
 6773                        wordwise: true,
 6774                        done: is_empty,
 6775                    };
 6776                    self.select_next_state = Some(select_state);
 6777                } else {
 6778                    self.select_next_state = None;
 6779                }
 6780            } else if let Some(selected_text) = selected_text {
 6781                self.select_next_state = Some(SelectNextState {
 6782                    query: AhoCorasick::new(&[selected_text])?,
 6783                    wordwise: false,
 6784                    done: false,
 6785                });
 6786                self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
 6787            }
 6788        }
 6789        Ok(())
 6790    }
 6791
 6792    pub fn select_all_matches(
 6793        &mut self,
 6794        _action: &SelectAllMatches,
 6795        cx: &mut ViewContext<Self>,
 6796    ) -> Result<()> {
 6797        self.push_to_selection_history();
 6798        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6799
 6800        self.select_next_match_internal(&display_map, false, None, cx)?;
 6801        let Some(select_next_state) = self.select_next_state.as_mut() else {
 6802            return Ok(());
 6803        };
 6804        if select_next_state.done {
 6805            return Ok(());
 6806        }
 6807
 6808        let mut new_selections = self.selections.all::<usize>(cx);
 6809
 6810        let buffer = &display_map.buffer_snapshot;
 6811        let query_matches = select_next_state
 6812            .query
 6813            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
 6814
 6815        for query_match in query_matches {
 6816            let query_match = query_match.unwrap(); // can only fail due to I/O
 6817            let offset_range = query_match.start()..query_match.end();
 6818            let display_range = offset_range.start.to_display_point(&display_map)
 6819                ..offset_range.end.to_display_point(&display_map);
 6820
 6821            if !select_next_state.wordwise
 6822                || (!movement::is_inside_word(&display_map, display_range.start)
 6823                    && !movement::is_inside_word(&display_map, display_range.end))
 6824            {
 6825                self.selections.change_with(cx, |selections| {
 6826                    new_selections.push(Selection {
 6827                        id: selections.new_selection_id(),
 6828                        start: offset_range.start,
 6829                        end: offset_range.end,
 6830                        reversed: false,
 6831                        goal: SelectionGoal::None,
 6832                    });
 6833                });
 6834            }
 6835        }
 6836
 6837        new_selections.sort_by_key(|selection| selection.start);
 6838        let mut ix = 0;
 6839        while ix + 1 < new_selections.len() {
 6840            let current_selection = &new_selections[ix];
 6841            let next_selection = &new_selections[ix + 1];
 6842            if current_selection.range().overlaps(&next_selection.range()) {
 6843                if current_selection.id < next_selection.id {
 6844                    new_selections.remove(ix + 1);
 6845                } else {
 6846                    new_selections.remove(ix);
 6847                }
 6848            } else {
 6849                ix += 1;
 6850            }
 6851        }
 6852
 6853        select_next_state.done = true;
 6854        self.unfold_ranges(
 6855            new_selections.iter().map(|selection| selection.range()),
 6856            false,
 6857            false,
 6858            cx,
 6859        );
 6860        self.change_selections(Some(Autoscroll::fit()), cx, |selections| {
 6861            selections.select(new_selections)
 6862        });
 6863
 6864        Ok(())
 6865    }
 6866
 6867    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
 6868        self.push_to_selection_history();
 6869        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6870        self.select_next_match_internal(
 6871            &display_map,
 6872            action.replace_newest,
 6873            Some(Autoscroll::newest()),
 6874            cx,
 6875        )?;
 6876        Ok(())
 6877    }
 6878
 6879    pub fn select_previous(
 6880        &mut self,
 6881        action: &SelectPrevious,
 6882        cx: &mut ViewContext<Self>,
 6883    ) -> Result<()> {
 6884        self.push_to_selection_history();
 6885        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6886        let buffer = &display_map.buffer_snapshot;
 6887        let mut selections = self.selections.all::<usize>(cx);
 6888        if let Some(mut select_prev_state) = self.select_prev_state.take() {
 6889            let query = &select_prev_state.query;
 6890            if !select_prev_state.done {
 6891                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 6892                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 6893                let mut next_selected_range = None;
 6894                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
 6895                let bytes_before_last_selection =
 6896                    buffer.reversed_bytes_in_range(0..last_selection.start);
 6897                let bytes_after_first_selection =
 6898                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
 6899                let query_matches = query
 6900                    .stream_find_iter(bytes_before_last_selection)
 6901                    .map(|result| (last_selection.start, result))
 6902                    .chain(
 6903                        query
 6904                            .stream_find_iter(bytes_after_first_selection)
 6905                            .map(|result| (buffer.len(), result)),
 6906                    );
 6907                for (end_offset, query_match) in query_matches {
 6908                    let query_match = query_match.unwrap(); // can only fail due to I/O
 6909                    let offset_range =
 6910                        end_offset - query_match.end()..end_offset - query_match.start();
 6911                    let display_range = offset_range.start.to_display_point(&display_map)
 6912                        ..offset_range.end.to_display_point(&display_map);
 6913
 6914                    if !select_prev_state.wordwise
 6915                        || (!movement::is_inside_word(&display_map, display_range.start)
 6916                            && !movement::is_inside_word(&display_map, display_range.end))
 6917                    {
 6918                        next_selected_range = Some(offset_range);
 6919                        break;
 6920                    }
 6921                }
 6922
 6923                if let Some(next_selected_range) = next_selected_range {
 6924                    self.unfold_ranges([next_selected_range.clone()], false, true, cx);
 6925                    self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 6926                        if action.replace_newest {
 6927                            s.delete(s.newest_anchor().id);
 6928                        }
 6929                        s.insert_range(next_selected_range);
 6930                    });
 6931                } else {
 6932                    select_prev_state.done = true;
 6933                }
 6934            }
 6935
 6936            self.select_prev_state = Some(select_prev_state);
 6937        } else {
 6938            let mut only_carets = true;
 6939            let mut same_text_selected = true;
 6940            let mut selected_text = None;
 6941
 6942            let mut selections_iter = selections.iter().peekable();
 6943            while let Some(selection) = selections_iter.next() {
 6944                if selection.start != selection.end {
 6945                    only_carets = false;
 6946                }
 6947
 6948                if same_text_selected {
 6949                    if selected_text.is_none() {
 6950                        selected_text =
 6951                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 6952                    }
 6953
 6954                    if let Some(next_selection) = selections_iter.peek() {
 6955                        if next_selection.range().len() == selection.range().len() {
 6956                            let next_selected_text = buffer
 6957                                .text_for_range(next_selection.range())
 6958                                .collect::<String>();
 6959                            if Some(next_selected_text) != selected_text {
 6960                                same_text_selected = false;
 6961                                selected_text = None;
 6962                            }
 6963                        } else {
 6964                            same_text_selected = false;
 6965                            selected_text = None;
 6966                        }
 6967                    }
 6968                }
 6969            }
 6970
 6971            if only_carets {
 6972                for selection in &mut selections {
 6973                    let word_range = movement::surrounding_word(
 6974                        &display_map,
 6975                        selection.start.to_display_point(&display_map),
 6976                    );
 6977                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 6978                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 6979                    selection.goal = SelectionGoal::None;
 6980                    selection.reversed = false;
 6981                }
 6982                if selections.len() == 1 {
 6983                    let selection = selections
 6984                        .last()
 6985                        .expect("ensured that there's only one selection");
 6986                    let query = buffer
 6987                        .text_for_range(selection.start..selection.end)
 6988                        .collect::<String>();
 6989                    let is_empty = query.is_empty();
 6990                    let select_state = SelectNextState {
 6991                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
 6992                        wordwise: true,
 6993                        done: is_empty,
 6994                    };
 6995                    self.select_prev_state = Some(select_state);
 6996                } else {
 6997                    self.select_prev_state = None;
 6998                }
 6999
 7000                self.unfold_ranges(
 7001                    selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
 7002                    false,
 7003                    true,
 7004                    cx,
 7005                );
 7006                self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 7007                    s.select(selections);
 7008                });
 7009            } else if let Some(selected_text) = selected_text {
 7010                self.select_prev_state = Some(SelectNextState {
 7011                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
 7012                    wordwise: false,
 7013                    done: false,
 7014                });
 7015                self.select_previous(action, cx)?;
 7016            }
 7017        }
 7018        Ok(())
 7019    }
 7020
 7021    pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
 7022        let text_layout_details = &self.text_layout_details(cx);
 7023        self.transact(cx, |this, cx| {
 7024            let mut selections = this.selections.all::<Point>(cx);
 7025            let mut edits = Vec::new();
 7026            let mut selection_edit_ranges = Vec::new();
 7027            let mut last_toggled_row = None;
 7028            let snapshot = this.buffer.read(cx).read(cx);
 7029            let empty_str: Arc<str> = "".into();
 7030            let mut suffixes_inserted = Vec::new();
 7031
 7032            fn comment_prefix_range(
 7033                snapshot: &MultiBufferSnapshot,
 7034                row: u32,
 7035                comment_prefix: &str,
 7036                comment_prefix_whitespace: &str,
 7037            ) -> Range<Point> {
 7038                let start = Point::new(row, snapshot.indent_size_for_line(row).len);
 7039
 7040                let mut line_bytes = snapshot
 7041                    .bytes_in_range(start..snapshot.max_point())
 7042                    .flatten()
 7043                    .copied();
 7044
 7045                // If this line currently begins with the line comment prefix, then record
 7046                // the range containing the prefix.
 7047                if line_bytes
 7048                    .by_ref()
 7049                    .take(comment_prefix.len())
 7050                    .eq(comment_prefix.bytes())
 7051                {
 7052                    // Include any whitespace that matches the comment prefix.
 7053                    let matching_whitespace_len = line_bytes
 7054                        .zip(comment_prefix_whitespace.bytes())
 7055                        .take_while(|(a, b)| a == b)
 7056                        .count() as u32;
 7057                    let end = Point::new(
 7058                        start.row,
 7059                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
 7060                    );
 7061                    start..end
 7062                } else {
 7063                    start..start
 7064                }
 7065            }
 7066
 7067            fn comment_suffix_range(
 7068                snapshot: &MultiBufferSnapshot,
 7069                row: u32,
 7070                comment_suffix: &str,
 7071                comment_suffix_has_leading_space: bool,
 7072            ) -> Range<Point> {
 7073                let end = Point::new(row, snapshot.line_len(row));
 7074                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
 7075
 7076                let mut line_end_bytes = snapshot
 7077                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
 7078                    .flatten()
 7079                    .copied();
 7080
 7081                let leading_space_len = if suffix_start_column > 0
 7082                    && line_end_bytes.next() == Some(b' ')
 7083                    && comment_suffix_has_leading_space
 7084                {
 7085                    1
 7086                } else {
 7087                    0
 7088                };
 7089
 7090                // If this line currently begins with the line comment prefix, then record
 7091                // the range containing the prefix.
 7092                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
 7093                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
 7094                    start..end
 7095                } else {
 7096                    end..end
 7097                }
 7098            }
 7099
 7100            // TODO: Handle selections that cross excerpts
 7101            for selection in &mut selections {
 7102                let start_column = snapshot.indent_size_for_line(selection.start.row).len;
 7103                let language = if let Some(language) =
 7104                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
 7105                {
 7106                    language
 7107                } else {
 7108                    continue;
 7109                };
 7110
 7111                selection_edit_ranges.clear();
 7112
 7113                // If multiple selections contain a given row, avoid processing that
 7114                // row more than once.
 7115                let mut start_row = selection.start.row;
 7116                if last_toggled_row == Some(start_row) {
 7117                    start_row += 1;
 7118                }
 7119                let end_row =
 7120                    if selection.end.row > selection.start.row && selection.end.column == 0 {
 7121                        selection.end.row - 1
 7122                    } else {
 7123                        selection.end.row
 7124                    };
 7125                last_toggled_row = Some(end_row);
 7126
 7127                if start_row > end_row {
 7128                    continue;
 7129                }
 7130
 7131                // If the language has line comments, toggle those.
 7132                if let Some(full_comment_prefix) = language
 7133                    .line_comment_prefixes()
 7134                    .and_then(|prefixes| prefixes.first())
 7135                {
 7136                    // Split the comment prefix's trailing whitespace into a separate string,
 7137                    // as that portion won't be used for detecting if a line is a comment.
 7138                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 7139                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 7140                    let mut all_selection_lines_are_comments = true;
 7141
 7142                    for row in start_row..=end_row {
 7143                        if start_row < end_row && snapshot.is_line_blank(row) {
 7144                            continue;
 7145                        }
 7146
 7147                        let prefix_range = comment_prefix_range(
 7148                            snapshot.deref(),
 7149                            row,
 7150                            comment_prefix,
 7151                            comment_prefix_whitespace,
 7152                        );
 7153                        if prefix_range.is_empty() {
 7154                            all_selection_lines_are_comments = false;
 7155                        }
 7156                        selection_edit_ranges.push(prefix_range);
 7157                    }
 7158
 7159                    if all_selection_lines_are_comments {
 7160                        edits.extend(
 7161                            selection_edit_ranges
 7162                                .iter()
 7163                                .cloned()
 7164                                .map(|range| (range, empty_str.clone())),
 7165                        );
 7166                    } else {
 7167                        let min_column = selection_edit_ranges
 7168                            .iter()
 7169                            .map(|r| r.start.column)
 7170                            .min()
 7171                            .unwrap_or(0);
 7172                        edits.extend(selection_edit_ranges.iter().map(|range| {
 7173                            let position = Point::new(range.start.row, min_column);
 7174                            (position..position, full_comment_prefix.clone())
 7175                        }));
 7176                    }
 7177                } else if let Some((full_comment_prefix, comment_suffix)) =
 7178                    language.block_comment_delimiters()
 7179                {
 7180                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 7181                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 7182                    let prefix_range = comment_prefix_range(
 7183                        snapshot.deref(),
 7184                        start_row,
 7185                        comment_prefix,
 7186                        comment_prefix_whitespace,
 7187                    );
 7188                    let suffix_range = comment_suffix_range(
 7189                        snapshot.deref(),
 7190                        end_row,
 7191                        comment_suffix.trim_start_matches(' '),
 7192                        comment_suffix.starts_with(' '),
 7193                    );
 7194
 7195                    if prefix_range.is_empty() || suffix_range.is_empty() {
 7196                        edits.push((
 7197                            prefix_range.start..prefix_range.start,
 7198                            full_comment_prefix.clone(),
 7199                        ));
 7200                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
 7201                        suffixes_inserted.push((end_row, comment_suffix.len()));
 7202                    } else {
 7203                        edits.push((prefix_range, empty_str.clone()));
 7204                        edits.push((suffix_range, empty_str.clone()));
 7205                    }
 7206                } else {
 7207                    continue;
 7208                }
 7209            }
 7210
 7211            drop(snapshot);
 7212            this.buffer.update(cx, |buffer, cx| {
 7213                buffer.edit(edits, None, cx);
 7214            });
 7215
 7216            // Adjust selections so that they end before any comment suffixes that
 7217            // were inserted.
 7218            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
 7219            let mut selections = this.selections.all::<Point>(cx);
 7220            let snapshot = this.buffer.read(cx).read(cx);
 7221            for selection in &mut selections {
 7222                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
 7223                    match row.cmp(&selection.end.row) {
 7224                        Ordering::Less => {
 7225                            suffixes_inserted.next();
 7226                            continue;
 7227                        }
 7228                        Ordering::Greater => break,
 7229                        Ordering::Equal => {
 7230                            if selection.end.column == snapshot.line_len(row) {
 7231                                if selection.is_empty() {
 7232                                    selection.start.column -= suffix_len as u32;
 7233                                }
 7234                                selection.end.column -= suffix_len as u32;
 7235                            }
 7236                            break;
 7237                        }
 7238                    }
 7239                }
 7240            }
 7241
 7242            drop(snapshot);
 7243            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 7244
 7245            let selections = this.selections.all::<Point>(cx);
 7246            let selections_on_single_row = selections.windows(2).all(|selections| {
 7247                selections[0].start.row == selections[1].start.row
 7248                    && selections[0].end.row == selections[1].end.row
 7249                    && selections[0].start.row == selections[0].end.row
 7250            });
 7251            let selections_selecting = selections
 7252                .iter()
 7253                .any(|selection| selection.start != selection.end);
 7254            let advance_downwards = action.advance_downwards
 7255                && selections_on_single_row
 7256                && !selections_selecting
 7257                && this.mode != EditorMode::SingleLine;
 7258
 7259            if advance_downwards {
 7260                let snapshot = this.buffer.read(cx).snapshot(cx);
 7261
 7262                this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7263                    s.move_cursors_with(|display_snapshot, display_point, _| {
 7264                        let mut point = display_point.to_point(display_snapshot);
 7265                        point.row += 1;
 7266                        point = snapshot.clip_point(point, Bias::Left);
 7267                        let display_point = point.to_display_point(display_snapshot);
 7268                        let goal = SelectionGoal::HorizontalPosition(
 7269                            display_snapshot
 7270                                .x_for_display_point(display_point, &text_layout_details)
 7271                                .into(),
 7272                        );
 7273                        (display_point, goal)
 7274                    })
 7275                });
 7276            }
 7277        });
 7278    }
 7279
 7280    pub fn select_larger_syntax_node(
 7281        &mut self,
 7282        _: &SelectLargerSyntaxNode,
 7283        cx: &mut ViewContext<Self>,
 7284    ) {
 7285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7286        let buffer = self.buffer.read(cx).snapshot(cx);
 7287        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 7288
 7289        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 7290        let mut selected_larger_node = false;
 7291        let new_selections = old_selections
 7292            .iter()
 7293            .map(|selection| {
 7294                let old_range = selection.start..selection.end;
 7295                let mut new_range = old_range.clone();
 7296                while let Some(containing_range) =
 7297                    buffer.range_for_syntax_ancestor(new_range.clone())
 7298                {
 7299                    new_range = containing_range;
 7300                    if !display_map.intersects_fold(new_range.start)
 7301                        && !display_map.intersects_fold(new_range.end)
 7302                    {
 7303                        break;
 7304                    }
 7305                }
 7306
 7307                selected_larger_node |= new_range != old_range;
 7308                Selection {
 7309                    id: selection.id,
 7310                    start: new_range.start,
 7311                    end: new_range.end,
 7312                    goal: SelectionGoal::None,
 7313                    reversed: selection.reversed,
 7314                }
 7315            })
 7316            .collect::<Vec<_>>();
 7317
 7318        if selected_larger_node {
 7319            stack.push(old_selections);
 7320            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7321                s.select(new_selections);
 7322            });
 7323        }
 7324        self.select_larger_syntax_node_stack = stack;
 7325    }
 7326
 7327    pub fn select_smaller_syntax_node(
 7328        &mut self,
 7329        _: &SelectSmallerSyntaxNode,
 7330        cx: &mut ViewContext<Self>,
 7331    ) {
 7332        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 7333        if let Some(selections) = stack.pop() {
 7334            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7335                s.select(selections.to_vec());
 7336            });
 7337        }
 7338        self.select_larger_syntax_node_stack = stack;
 7339    }
 7340
 7341    pub fn move_to_enclosing_bracket(
 7342        &mut self,
 7343        _: &MoveToEnclosingBracket,
 7344        cx: &mut ViewContext<Self>,
 7345    ) {
 7346        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7347            s.move_offsets_with(|snapshot, selection| {
 7348                let Some(enclosing_bracket_ranges) =
 7349                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
 7350                else {
 7351                    return;
 7352                };
 7353
 7354                let mut best_length = usize::MAX;
 7355                let mut best_inside = false;
 7356                let mut best_in_bracket_range = false;
 7357                let mut best_destination = None;
 7358                for (open, close) in enclosing_bracket_ranges {
 7359                    let close = close.to_inclusive();
 7360                    let length = close.end() - open.start;
 7361                    let inside = selection.start >= open.end && selection.end <= *close.start();
 7362                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
 7363                        || close.contains(&selection.head());
 7364
 7365                    // If best is next to a bracket and current isn't, skip
 7366                    if !in_bracket_range && best_in_bracket_range {
 7367                        continue;
 7368                    }
 7369
 7370                    // Prefer smaller lengths unless best is inside and current isn't
 7371                    if length > best_length && (best_inside || !inside) {
 7372                        continue;
 7373                    }
 7374
 7375                    best_length = length;
 7376                    best_inside = inside;
 7377                    best_in_bracket_range = in_bracket_range;
 7378                    best_destination = Some(
 7379                        if close.contains(&selection.start) && close.contains(&selection.end) {
 7380                            if inside {
 7381                                open.end
 7382                            } else {
 7383                                open.start
 7384                            }
 7385                        } else {
 7386                            if inside {
 7387                                *close.start()
 7388                            } else {
 7389                                *close.end()
 7390                            }
 7391                        },
 7392                    );
 7393                }
 7394
 7395                if let Some(destination) = best_destination {
 7396                    selection.collapse_to(destination, SelectionGoal::None);
 7397                }
 7398            })
 7399        });
 7400    }
 7401
 7402    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
 7403        self.end_selection(cx);
 7404        self.selection_history.mode = SelectionHistoryMode::Undoing;
 7405        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
 7406            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 7407            self.select_next_state = entry.select_next_state;
 7408            self.select_prev_state = entry.select_prev_state;
 7409            self.add_selections_state = entry.add_selections_state;
 7410            self.request_autoscroll(Autoscroll::newest(), cx);
 7411        }
 7412        self.selection_history.mode = SelectionHistoryMode::Normal;
 7413    }
 7414
 7415    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
 7416        self.end_selection(cx);
 7417        self.selection_history.mode = SelectionHistoryMode::Redoing;
 7418        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
 7419            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 7420            self.select_next_state = entry.select_next_state;
 7421            self.select_prev_state = entry.select_prev_state;
 7422            self.add_selections_state = entry.add_selections_state;
 7423            self.request_autoscroll(Autoscroll::newest(), cx);
 7424        }
 7425        self.selection_history.mode = SelectionHistoryMode::Normal;
 7426    }
 7427
 7428    fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
 7429        self.go_to_diagnostic_impl(Direction::Next, cx)
 7430    }
 7431
 7432    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
 7433        self.go_to_diagnostic_impl(Direction::Prev, cx)
 7434    }
 7435
 7436    pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
 7437        let buffer = self.buffer.read(cx).snapshot(cx);
 7438        let selection = self.selections.newest::<usize>(cx);
 7439
 7440        // If there is an active Diagnostic Popover jump to its diagnostic instead.
 7441        if direction == Direction::Next {
 7442            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
 7443                let (group_id, jump_to) = popover.activation_info();
 7444                if self.activate_diagnostics(group_id, cx) {
 7445                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7446                        let mut new_selection = s.newest_anchor().clone();
 7447                        new_selection.collapse_to(jump_to, SelectionGoal::None);
 7448                        s.select_anchors(vec![new_selection.clone()]);
 7449                    });
 7450                }
 7451                return;
 7452            }
 7453        }
 7454
 7455        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
 7456            active_diagnostics
 7457                .primary_range
 7458                .to_offset(&buffer)
 7459                .to_inclusive()
 7460        });
 7461        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
 7462            if active_primary_range.contains(&selection.head()) {
 7463                *active_primary_range.end()
 7464            } else {
 7465                selection.head()
 7466            }
 7467        } else {
 7468            selection.head()
 7469        };
 7470
 7471        loop {
 7472            let mut diagnostics = if direction == Direction::Prev {
 7473                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
 7474            } else {
 7475                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
 7476            };
 7477            let group = diagnostics.find_map(|entry| {
 7478                if entry.diagnostic.is_primary
 7479                    && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
 7480                    && !entry.range.is_empty()
 7481                    && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
 7482                    && !entry.range.contains(&search_start)
 7483                {
 7484                    Some((entry.range, entry.diagnostic.group_id))
 7485                } else {
 7486                    None
 7487                }
 7488            });
 7489
 7490            if let Some((primary_range, group_id)) = group {
 7491                if self.activate_diagnostics(group_id, cx) {
 7492                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7493                        s.select(vec![Selection {
 7494                            id: selection.id,
 7495                            start: primary_range.start,
 7496                            end: primary_range.start,
 7497                            reversed: false,
 7498                            goal: SelectionGoal::None,
 7499                        }]);
 7500                    });
 7501                }
 7502                break;
 7503            } else {
 7504                // Cycle around to the start of the buffer, potentially moving back to the start of
 7505                // the currently active diagnostic.
 7506                active_primary_range.take();
 7507                if direction == Direction::Prev {
 7508                    if search_start == buffer.len() {
 7509                        break;
 7510                    } else {
 7511                        search_start = buffer.len();
 7512                    }
 7513                } else if search_start == 0 {
 7514                    break;
 7515                } else {
 7516                    search_start = 0;
 7517                }
 7518            }
 7519        }
 7520    }
 7521
 7522    fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
 7523        let snapshot = self
 7524            .display_map
 7525            .update(cx, |display_map, cx| display_map.snapshot(cx));
 7526        let selection = self.selections.newest::<Point>(cx);
 7527
 7528        if !self.seek_in_direction(
 7529            &snapshot,
 7530            selection.head(),
 7531            false,
 7532            snapshot
 7533                .buffer_snapshot
 7534                .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX),
 7535            cx,
 7536        ) {
 7537            let wrapped_point = Point::zero();
 7538            self.seek_in_direction(
 7539                &snapshot,
 7540                wrapped_point,
 7541                true,
 7542                snapshot
 7543                    .buffer_snapshot
 7544                    .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX),
 7545                cx,
 7546            );
 7547        }
 7548    }
 7549
 7550    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
 7551        let snapshot = self
 7552            .display_map
 7553            .update(cx, |display_map, cx| display_map.snapshot(cx));
 7554        let selection = self.selections.newest::<Point>(cx);
 7555
 7556        if !self.seek_in_direction(
 7557            &snapshot,
 7558            selection.head(),
 7559            false,
 7560            snapshot
 7561                .buffer_snapshot
 7562                .git_diff_hunks_in_range_rev(0..selection.head().row),
 7563            cx,
 7564        ) {
 7565            let wrapped_point = snapshot.buffer_snapshot.max_point();
 7566            self.seek_in_direction(
 7567                &snapshot,
 7568                wrapped_point,
 7569                true,
 7570                snapshot
 7571                    .buffer_snapshot
 7572                    .git_diff_hunks_in_range_rev(0..wrapped_point.row),
 7573                cx,
 7574            );
 7575        }
 7576    }
 7577
 7578    fn seek_in_direction(
 7579        &mut self,
 7580        snapshot: &DisplaySnapshot,
 7581        initial_point: Point,
 7582        is_wrapped: bool,
 7583        hunks: impl Iterator<Item = DiffHunk<u32>>,
 7584        cx: &mut ViewContext<Editor>,
 7585    ) -> bool {
 7586        let display_point = initial_point.to_display_point(snapshot);
 7587        let mut hunks = hunks
 7588            .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
 7589            .filter(|hunk| {
 7590                if is_wrapped {
 7591                    true
 7592                } else {
 7593                    !hunk.contains_display_row(display_point.row())
 7594                }
 7595            })
 7596            .dedup();
 7597
 7598        if let Some(hunk) = hunks.next() {
 7599            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7600                let row = hunk.start_display_row();
 7601                let point = DisplayPoint::new(row, 0);
 7602                s.select_display_ranges([point..point]);
 7603            });
 7604
 7605            true
 7606        } else {
 7607            false
 7608        }
 7609    }
 7610
 7611    pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext<Self>) {
 7612        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
 7613    }
 7614
 7615    pub fn go_to_implementation(&mut self, _: &GoToImplementation, cx: &mut ViewContext<Self>) {
 7616        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, cx);
 7617    }
 7618
 7619    pub fn go_to_implementation_split(
 7620        &mut self,
 7621        _: &GoToImplementationSplit,
 7622        cx: &mut ViewContext<Self>,
 7623    ) {
 7624        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, cx);
 7625    }
 7626
 7627    pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
 7628        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx);
 7629    }
 7630
 7631    pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext<Self>) {
 7632        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx);
 7633    }
 7634
 7635    pub fn go_to_type_definition_split(
 7636        &mut self,
 7637        _: &GoToTypeDefinitionSplit,
 7638        cx: &mut ViewContext<Self>,
 7639    ) {
 7640        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx);
 7641    }
 7642
 7643    fn go_to_definition_of_kind(
 7644        &mut self,
 7645        kind: GotoDefinitionKind,
 7646        split: bool,
 7647        cx: &mut ViewContext<Self>,
 7648    ) {
 7649        let Some(workspace) = self.workspace() else {
 7650            return;
 7651        };
 7652        let buffer = self.buffer.read(cx);
 7653        let head = self.selections.newest::<usize>(cx).head();
 7654        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
 7655            text_anchor
 7656        } else {
 7657            return;
 7658        };
 7659
 7660        let project = workspace.read(cx).project().clone();
 7661        let definitions = project.update(cx, |project, cx| match kind {
 7662            GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
 7663            GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
 7664            GotoDefinitionKind::Implementation => project.implementation(&buffer, head, cx),
 7665        });
 7666
 7667        cx.spawn(|editor, mut cx| async move {
 7668            let definitions = definitions.await?;
 7669            editor.update(&mut cx, |editor, cx| {
 7670                editor.navigate_to_hover_links(
 7671                    Some(kind),
 7672                    definitions.into_iter().map(HoverLink::Text).collect(),
 7673                    split,
 7674                    cx,
 7675                );
 7676            })?;
 7677            Ok::<(), anyhow::Error>(())
 7678        })
 7679        .detach_and_log_err(cx);
 7680    }
 7681
 7682    pub fn open_url(&mut self, _: &OpenUrl, cx: &mut ViewContext<Self>) {
 7683        let position = self.selections.newest_anchor().head();
 7684        let Some((buffer, buffer_position)) =
 7685            self.buffer.read(cx).text_anchor_for_position(position, cx)
 7686        else {
 7687            return;
 7688        };
 7689
 7690        cx.spawn(|editor, mut cx| async move {
 7691            if let Some((_, url)) = find_url(&buffer, buffer_position, cx.clone()) {
 7692                editor.update(&mut cx, |_, cx| {
 7693                    cx.open_url(&url);
 7694                })
 7695            } else {
 7696                Ok(())
 7697            }
 7698        })
 7699        .detach();
 7700    }
 7701
 7702    pub(crate) fn navigate_to_hover_links(
 7703        &mut self,
 7704        kind: Option<GotoDefinitionKind>,
 7705        mut definitions: Vec<HoverLink>,
 7706        split: bool,
 7707        cx: &mut ViewContext<Editor>,
 7708    ) {
 7709        // If there is one definition, just open it directly
 7710        if definitions.len() == 1 {
 7711            let definition = definitions.pop().unwrap();
 7712            let target_task = match definition {
 7713                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 7714                HoverLink::InlayHint(lsp_location, server_id) => {
 7715                    self.compute_target_location(lsp_location, server_id, cx)
 7716                }
 7717                HoverLink::Url(url) => {
 7718                    cx.open_url(&url);
 7719                    Task::ready(Ok(None))
 7720                }
 7721            };
 7722            cx.spawn(|editor, mut cx| async move {
 7723                let target = target_task.await.context("target resolution task")?;
 7724                if let Some(target) = target {
 7725                    editor.update(&mut cx, |editor, cx| {
 7726                        let Some(workspace) = editor.workspace() else {
 7727                            return;
 7728                        };
 7729                        let pane = workspace.read(cx).active_pane().clone();
 7730
 7731                        let range = target.range.to_offset(target.buffer.read(cx));
 7732                        let range = editor.range_for_match(&range);
 7733                        if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
 7734                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7735                                s.select_ranges([range]);
 7736                            });
 7737                        } else {
 7738                            cx.window_context().defer(move |cx| {
 7739                                let target_editor: View<Self> =
 7740                                    workspace.update(cx, |workspace, cx| {
 7741                                        let pane = if split {
 7742                                            workspace.adjacent_pane(cx)
 7743                                        } else {
 7744                                            workspace.active_pane().clone()
 7745                                        };
 7746
 7747                                        workspace.open_project_item(pane, target.buffer.clone(), cx)
 7748                                    });
 7749                                target_editor.update(cx, |target_editor, cx| {
 7750                                    // When selecting a definition in a different buffer, disable the nav history
 7751                                    // to avoid creating a history entry at the previous cursor location.
 7752                                    pane.update(cx, |pane, _| pane.disable_history());
 7753                                    target_editor.change_selections(
 7754                                        Some(Autoscroll::fit()),
 7755                                        cx,
 7756                                        |s| {
 7757                                            s.select_ranges([range]);
 7758                                        },
 7759                                    );
 7760                                    pane.update(cx, |pane, _| pane.enable_history());
 7761                                });
 7762                            });
 7763                        }
 7764                    })
 7765                } else {
 7766                    Ok(())
 7767                }
 7768            })
 7769            .detach_and_log_err(cx);
 7770        } else if !definitions.is_empty() {
 7771            let replica_id = self.replica_id(cx);
 7772            cx.spawn(|editor, mut cx| async move {
 7773                let (title, location_tasks, workspace) = editor
 7774                    .update(&mut cx, |editor, cx| {
 7775                        let tab_kind = match kind {
 7776                            Some(GotoDefinitionKind::Implementation) => "Implementations",
 7777                            _ => "Definitions",
 7778                        };
 7779                        let title = definitions
 7780                            .iter()
 7781                            .find_map(|definition| match definition {
 7782                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
 7783                                    let buffer = origin.buffer.read(cx);
 7784                                    format!(
 7785                                        "{} for {}",
 7786                                        tab_kind,
 7787                                        buffer
 7788                                            .text_for_range(origin.range.clone())
 7789                                            .collect::<String>()
 7790                                    )
 7791                                }),
 7792                                HoverLink::InlayHint(_, _) => None,
 7793                                HoverLink::Url(_) => None,
 7794                            })
 7795                            .unwrap_or(tab_kind.to_string());
 7796                        let location_tasks = definitions
 7797                            .into_iter()
 7798                            .map(|definition| match definition {
 7799                                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 7800                                HoverLink::InlayHint(lsp_location, server_id) => {
 7801                                    editor.compute_target_location(lsp_location, server_id, cx)
 7802                                }
 7803                                HoverLink::Url(_) => Task::ready(Ok(None)),
 7804                            })
 7805                            .collect::<Vec<_>>();
 7806                        (title, location_tasks, editor.workspace().clone())
 7807                    })
 7808                    .context("location tasks preparation")?;
 7809
 7810                let locations = futures::future::join_all(location_tasks)
 7811                    .await
 7812                    .into_iter()
 7813                    .filter_map(|location| location.transpose())
 7814                    .collect::<Result<_>>()
 7815                    .context("location tasks")?;
 7816
 7817                let Some(workspace) = workspace else {
 7818                    return Ok(());
 7819                };
 7820                workspace
 7821                    .update(&mut cx, |workspace, cx| {
 7822                        Self::open_locations_in_multibuffer(
 7823                            workspace, locations, replica_id, title, split, cx,
 7824                        )
 7825                    })
 7826                    .ok();
 7827
 7828                anyhow::Ok(())
 7829            })
 7830            .detach_and_log_err(cx);
 7831        }
 7832    }
 7833
 7834    fn compute_target_location(
 7835        &self,
 7836        lsp_location: lsp::Location,
 7837        server_id: LanguageServerId,
 7838        cx: &mut ViewContext<Editor>,
 7839    ) -> Task<anyhow::Result<Option<Location>>> {
 7840        let Some(project) = self.project.clone() else {
 7841            return Task::Ready(Some(Ok(None)));
 7842        };
 7843
 7844        cx.spawn(move |editor, mut cx| async move {
 7845            let location_task = editor.update(&mut cx, |editor, cx| {
 7846                project.update(cx, |project, cx| {
 7847                    let language_server_name =
 7848                        editor.buffer.read(cx).as_singleton().and_then(|buffer| {
 7849                            project
 7850                                .language_server_for_buffer(buffer.read(cx), server_id, cx)
 7851                                .map(|(lsp_adapter, _)| lsp_adapter.name.clone())
 7852                        });
 7853                    language_server_name.map(|language_server_name| {
 7854                        project.open_local_buffer_via_lsp(
 7855                            lsp_location.uri.clone(),
 7856                            server_id,
 7857                            language_server_name,
 7858                            cx,
 7859                        )
 7860                    })
 7861                })
 7862            })?;
 7863            let location = match location_task {
 7864                Some(task) => Some({
 7865                    let target_buffer_handle = task.await.context("open local buffer")?;
 7866                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
 7867                        let target_start = target_buffer
 7868                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
 7869                        let target_end = target_buffer
 7870                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
 7871                        target_buffer.anchor_after(target_start)
 7872                            ..target_buffer.anchor_before(target_end)
 7873                    })?;
 7874                    Location {
 7875                        buffer: target_buffer_handle,
 7876                        range,
 7877                    }
 7878                }),
 7879                None => None,
 7880            };
 7881            Ok(location)
 7882        })
 7883    }
 7884
 7885    pub fn find_all_references(
 7886        &mut self,
 7887        _: &FindAllReferences,
 7888        cx: &mut ViewContext<Self>,
 7889    ) -> Option<Task<Result<()>>> {
 7890        let buffer = self.buffer.read(cx);
 7891        let head = self.selections.newest::<usize>(cx).head();
 7892        let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
 7893        let replica_id = self.replica_id(cx);
 7894
 7895        let workspace = self.workspace()?;
 7896        let project = workspace.read(cx).project().clone();
 7897        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
 7898        Some(cx.spawn(|editor, mut cx| async move {
 7899            let mut locations = references.await?;
 7900            let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
 7901            let head_offset = text::ToOffset::to_offset(&head, &snapshot);
 7902
 7903            // LSP may return references that contain the item itself we requested `find_all_references` for (eg. rust-analyzer)
 7904            // So we will remove it from locations
 7905            // If there is only one reference, we will not do this filter cause it may make locations empty
 7906            if locations.len() > 1 {
 7907                cx.update(|cx| {
 7908                    locations.retain(|location| {
 7909                        // fn foo(x : i64) {
 7910                        //         ^
 7911                        //  println!(x);
 7912                        // }
 7913                        // It is ok to find reference when caret being at ^ (the end of the word)
 7914                        // So we turn offset into inclusive to include the end of the word
 7915                        !location
 7916                            .range
 7917                            .to_offset(location.buffer.read(cx))
 7918                            .to_inclusive()
 7919                            .contains(&head_offset)
 7920                    });
 7921                })?;
 7922            }
 7923
 7924            if locations.is_empty() {
 7925                return Ok(());
 7926            }
 7927
 7928            // If there is one reference, just open it directly
 7929            if locations.len() == 1 {
 7930                let target = locations.pop().unwrap();
 7931
 7932                return editor.update(&mut cx, |editor, cx| {
 7933                    let range = target.range.to_offset(target.buffer.read(cx));
 7934                    let range = editor.range_for_match(&range);
 7935
 7936                    if Some(&target.buffer) == editor.buffer().read(cx).as_singleton().as_ref() {
 7937                        editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7938                            s.select_ranges([range]);
 7939                        });
 7940                    } else {
 7941                        cx.window_context().defer(move |cx| {
 7942                            let target_editor: View<Self> =
 7943                                workspace.update(cx, |workspace, cx| {
 7944                                    workspace.open_project_item(
 7945                                        workspace.active_pane().clone(),
 7946                                        target.buffer.clone(),
 7947                                        cx,
 7948                                    )
 7949                                });
 7950                            target_editor.update(cx, |target_editor, cx| {
 7951                                target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7952                                    s.select_ranges([range]);
 7953                                })
 7954                            })
 7955                        })
 7956                    }
 7957                });
 7958            }
 7959
 7960            workspace.update(&mut cx, |workspace, cx| {
 7961                let title = locations
 7962                    .first()
 7963                    .as_ref()
 7964                    .map(|location| {
 7965                        let buffer = location.buffer.read(cx);
 7966                        format!(
 7967                            "References to `{}`",
 7968                            buffer
 7969                                .text_for_range(location.range.clone())
 7970                                .collect::<String>()
 7971                        )
 7972                    })
 7973                    .unwrap();
 7974                Self::open_locations_in_multibuffer(
 7975                    workspace, locations, replica_id, title, false, cx,
 7976                );
 7977            })?;
 7978
 7979            Ok(())
 7980        }))
 7981    }
 7982
 7983    /// Opens a multibuffer with the given project locations in it
 7984    pub fn open_locations_in_multibuffer(
 7985        workspace: &mut Workspace,
 7986        mut locations: Vec<Location>,
 7987        replica_id: ReplicaId,
 7988        title: String,
 7989        split: bool,
 7990        cx: &mut ViewContext<Workspace>,
 7991    ) {
 7992        // If there are multiple definitions, open them in a multibuffer
 7993        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
 7994        let mut locations = locations.into_iter().peekable();
 7995        let mut ranges_to_highlight = Vec::new();
 7996        let capability = workspace.project().read(cx).capability();
 7997
 7998        let excerpt_buffer = cx.new_model(|cx| {
 7999            let mut multibuffer = MultiBuffer::new(replica_id, capability);
 8000            while let Some(location) = locations.next() {
 8001                let buffer = location.buffer.read(cx);
 8002                let mut ranges_for_buffer = Vec::new();
 8003                let range = location.range.to_offset(buffer);
 8004                ranges_for_buffer.push(range.clone());
 8005
 8006                while let Some(next_location) = locations.peek() {
 8007                    if next_location.buffer == location.buffer {
 8008                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
 8009                        locations.next();
 8010                    } else {
 8011                        break;
 8012                    }
 8013                }
 8014
 8015                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
 8016                ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
 8017                    location.buffer.clone(),
 8018                    ranges_for_buffer,
 8019                    1,
 8020                    cx,
 8021                ))
 8022            }
 8023
 8024            multibuffer.with_title(title)
 8025        });
 8026
 8027        let editor = cx.new_view(|cx| {
 8028            Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
 8029        });
 8030        editor.update(cx, |editor, cx| {
 8031            editor.highlight_background::<Self>(
 8032                ranges_to_highlight,
 8033                |theme| theme.editor_highlighted_line_background,
 8034                cx,
 8035            );
 8036        });
 8037        if split {
 8038            workspace.split_item(SplitDirection::Right, Box::new(editor), cx);
 8039        } else {
 8040            workspace.add_item_to_active_pane(Box::new(editor), cx);
 8041        }
 8042    }
 8043
 8044    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 8045        use language::ToOffset as _;
 8046
 8047        let project = self.project.clone()?;
 8048        let selection = self.selections.newest_anchor().clone();
 8049        let (cursor_buffer, cursor_buffer_position) = self
 8050            .buffer
 8051            .read(cx)
 8052            .text_anchor_for_position(selection.head(), cx)?;
 8053        let (tail_buffer, _) = self
 8054            .buffer
 8055            .read(cx)
 8056            .text_anchor_for_position(selection.tail(), cx)?;
 8057        if tail_buffer != cursor_buffer {
 8058            return None;
 8059        }
 8060
 8061        let snapshot = cursor_buffer.read(cx).snapshot();
 8062        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
 8063        let prepare_rename = project.update(cx, |project, cx| {
 8064            project.prepare_rename(cursor_buffer.clone(), cursor_buffer_offset, cx)
 8065        });
 8066        drop(snapshot);
 8067
 8068        Some(cx.spawn(|this, mut cx| async move {
 8069            let rename_range = if let Some(range) = prepare_rename.await? {
 8070                Some(range)
 8071            } else {
 8072                this.update(&mut cx, |this, cx| {
 8073                    let buffer = this.buffer.read(cx).snapshot(cx);
 8074                    let mut buffer_highlights = this
 8075                        .document_highlights_for_position(selection.head(), &buffer)
 8076                        .filter(|highlight| {
 8077                            highlight.start.excerpt_id == selection.head().excerpt_id
 8078                                && highlight.end.excerpt_id == selection.head().excerpt_id
 8079                        });
 8080                    buffer_highlights
 8081                        .next()
 8082                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
 8083                })?
 8084            };
 8085            if let Some(rename_range) = rename_range {
 8086                this.update(&mut cx, |this, cx| {
 8087                    let snapshot = cursor_buffer.read(cx).snapshot();
 8088                    let rename_buffer_range = rename_range.to_offset(&snapshot);
 8089                    let cursor_offset_in_rename_range =
 8090                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
 8091
 8092                    this.take_rename(false, cx);
 8093                    let buffer = this.buffer.read(cx).read(cx);
 8094                    let cursor_offset = selection.head().to_offset(&buffer);
 8095                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
 8096                    let rename_end = rename_start + rename_buffer_range.len();
 8097                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
 8098                    let mut old_highlight_id = None;
 8099                    let old_name: Arc<str> = buffer
 8100                        .chunks(rename_start..rename_end, true)
 8101                        .map(|chunk| {
 8102                            if old_highlight_id.is_none() {
 8103                                old_highlight_id = chunk.syntax_highlight_id;
 8104                            }
 8105                            chunk.text
 8106                        })
 8107                        .collect::<String>()
 8108                        .into();
 8109
 8110                    drop(buffer);
 8111
 8112                    // Position the selection in the rename editor so that it matches the current selection.
 8113                    this.show_local_selections = false;
 8114                    let rename_editor = cx.new_view(|cx| {
 8115                        let mut editor = Editor::single_line(cx);
 8116                        editor.buffer.update(cx, |buffer, cx| {
 8117                            buffer.edit([(0..0, old_name.clone())], None, cx)
 8118                        });
 8119                        editor.select_all(&SelectAll, cx);
 8120                        editor
 8121                    });
 8122
 8123                    let ranges = this
 8124                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
 8125                        .into_iter()
 8126                        .flat_map(|(_, ranges)| ranges.into_iter())
 8127                        .chain(
 8128                            this.clear_background_highlights::<DocumentHighlightRead>(cx)
 8129                                .into_iter()
 8130                                .flat_map(|(_, ranges)| ranges.into_iter()),
 8131                        )
 8132                        .collect();
 8133
 8134                    this.highlight_text::<Rename>(
 8135                        ranges,
 8136                        HighlightStyle {
 8137                            fade_out: Some(0.6),
 8138                            ..Default::default()
 8139                        },
 8140                        cx,
 8141                    );
 8142                    let rename_focus_handle = rename_editor.focus_handle(cx);
 8143                    cx.focus(&rename_focus_handle);
 8144                    let block_id = this.insert_blocks(
 8145                        [BlockProperties {
 8146                            style: BlockStyle::Flex,
 8147                            position: range.start,
 8148                            height: 1,
 8149                            render: Arc::new({
 8150                                let rename_editor = rename_editor.clone();
 8151                                move |cx: &mut BlockContext| {
 8152                                    let mut text_style = cx.editor_style.text.clone();
 8153                                    if let Some(highlight_style) = old_highlight_id
 8154                                        .and_then(|h| h.style(&cx.editor_style.syntax))
 8155                                    {
 8156                                        text_style = text_style.highlight(highlight_style);
 8157                                    }
 8158                                    div()
 8159                                        .pl(cx.anchor_x)
 8160                                        .child(EditorElement::new(
 8161                                            &rename_editor,
 8162                                            EditorStyle {
 8163                                                background: cx.theme().system().transparent,
 8164                                                local_player: cx.editor_style.local_player,
 8165                                                text: text_style,
 8166                                                scrollbar_width: cx.editor_style.scrollbar_width,
 8167                                                syntax: cx.editor_style.syntax.clone(),
 8168                                                status: cx.editor_style.status.clone(),
 8169                                                inlay_hints_style: HighlightStyle {
 8170                                                    color: Some(cx.theme().status().hint),
 8171                                                    font_weight: Some(FontWeight::BOLD),
 8172                                                    ..HighlightStyle::default()
 8173                                                },
 8174                                                suggestions_style: HighlightStyle {
 8175                                                    color: Some(cx.theme().status().predictive),
 8176                                                    ..HighlightStyle::default()
 8177                                                },
 8178                                            },
 8179                                        ))
 8180                                        .into_any_element()
 8181                                }
 8182                            }),
 8183                            disposition: BlockDisposition::Below,
 8184                        }],
 8185                        Some(Autoscroll::fit()),
 8186                        cx,
 8187                    )[0];
 8188                    this.pending_rename = Some(RenameState {
 8189                        range,
 8190                        old_name,
 8191                        editor: rename_editor,
 8192                        block_id,
 8193                    });
 8194                })?;
 8195            }
 8196
 8197            Ok(())
 8198        }))
 8199    }
 8200
 8201    pub fn confirm_rename(
 8202        &mut self,
 8203        _: &ConfirmRename,
 8204        cx: &mut ViewContext<Self>,
 8205    ) -> Option<Task<Result<()>>> {
 8206        let rename = self.take_rename(false, cx)?;
 8207        let workspace = self.workspace()?;
 8208        let (start_buffer, start) = self
 8209            .buffer
 8210            .read(cx)
 8211            .text_anchor_for_position(rename.range.start, cx)?;
 8212        let (end_buffer, end) = self
 8213            .buffer
 8214            .read(cx)
 8215            .text_anchor_for_position(rename.range.end, cx)?;
 8216        if start_buffer != end_buffer {
 8217            return None;
 8218        }
 8219
 8220        let buffer = start_buffer;
 8221        let range = start..end;
 8222        let old_name = rename.old_name;
 8223        let new_name = rename.editor.read(cx).text(cx);
 8224
 8225        let rename = workspace
 8226            .read(cx)
 8227            .project()
 8228            .clone()
 8229            .update(cx, |project, cx| {
 8230                project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
 8231            });
 8232        let workspace = workspace.downgrade();
 8233
 8234        Some(cx.spawn(|editor, mut cx| async move {
 8235            let project_transaction = rename.await?;
 8236            Self::open_project_transaction(
 8237                &editor,
 8238                workspace,
 8239                project_transaction,
 8240                format!("Rename: {}{}", old_name, new_name),
 8241                cx.clone(),
 8242            )
 8243            .await?;
 8244
 8245            editor.update(&mut cx, |editor, cx| {
 8246                editor.refresh_document_highlights(cx);
 8247            })?;
 8248            Ok(())
 8249        }))
 8250    }
 8251
 8252    fn take_rename(
 8253        &mut self,
 8254        moving_cursor: bool,
 8255        cx: &mut ViewContext<Self>,
 8256    ) -> Option<RenameState> {
 8257        let rename = self.pending_rename.take()?;
 8258        if rename.editor.focus_handle(cx).is_focused(cx) {
 8259            cx.focus(&self.focus_handle);
 8260        }
 8261
 8262        self.remove_blocks(
 8263            [rename.block_id].into_iter().collect(),
 8264            Some(Autoscroll::fit()),
 8265            cx,
 8266        );
 8267        self.clear_highlights::<Rename>(cx);
 8268        self.show_local_selections = true;
 8269
 8270        if moving_cursor {
 8271            let rename_editor = rename.editor.read(cx);
 8272            let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
 8273
 8274            // Update the selection to match the position of the selection inside
 8275            // the rename editor.
 8276            let snapshot = self.buffer.read(cx).read(cx);
 8277            let rename_range = rename.range.to_offset(&snapshot);
 8278            let cursor_in_editor = snapshot
 8279                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
 8280                .min(rename_range.end);
 8281            drop(snapshot);
 8282
 8283            self.change_selections(None, cx, |s| {
 8284                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
 8285            });
 8286        } else {
 8287            self.refresh_document_highlights(cx);
 8288        }
 8289
 8290        Some(rename)
 8291    }
 8292
 8293    pub fn pending_rename(&self) -> Option<&RenameState> {
 8294        self.pending_rename.as_ref()
 8295    }
 8296
 8297    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 8298        let project = match &self.project {
 8299            Some(project) => project.clone(),
 8300            None => return None,
 8301        };
 8302
 8303        Some(self.perform_format(project, FormatTrigger::Manual, cx))
 8304    }
 8305
 8306    fn perform_format(
 8307        &mut self,
 8308        project: Model<Project>,
 8309        trigger: FormatTrigger,
 8310        cx: &mut ViewContext<Self>,
 8311    ) -> Task<Result<()>> {
 8312        let buffer = self.buffer().clone();
 8313        let buffers = buffer.read(cx).all_buffers();
 8314
 8315        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
 8316        let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
 8317
 8318        cx.spawn(|_, mut cx| async move {
 8319            let transaction = futures::select_biased! {
 8320                _ = timeout => {
 8321                    log::warn!("timed out waiting for formatting");
 8322                    None
 8323                }
 8324                transaction = format.log_err().fuse() => transaction,
 8325            };
 8326
 8327            buffer
 8328                .update(&mut cx, |buffer, cx| {
 8329                    if let Some(transaction) = transaction {
 8330                        if !buffer.is_singleton() {
 8331                            buffer.push_transaction(&transaction.0, cx);
 8332                        }
 8333                    }
 8334
 8335                    cx.notify();
 8336                })
 8337                .ok();
 8338
 8339            Ok(())
 8340        })
 8341    }
 8342
 8343    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
 8344        if let Some(project) = self.project.clone() {
 8345            self.buffer.update(cx, |multi_buffer, cx| {
 8346                project.update(cx, |project, cx| {
 8347                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
 8348                });
 8349            })
 8350        }
 8351    }
 8352
 8353    fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
 8354        cx.show_character_palette();
 8355    }
 8356
 8357    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
 8358        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
 8359            let buffer = self.buffer.read(cx).snapshot(cx);
 8360            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
 8361            let is_valid = buffer
 8362                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
 8363                .any(|entry| {
 8364                    entry.diagnostic.is_primary
 8365                        && !entry.range.is_empty()
 8366                        && entry.range.start == primary_range_start
 8367                        && entry.diagnostic.message == active_diagnostics.primary_message
 8368                });
 8369
 8370            if is_valid != active_diagnostics.is_valid {
 8371                active_diagnostics.is_valid = is_valid;
 8372                let mut new_styles = HashMap::default();
 8373                for (block_id, diagnostic) in &active_diagnostics.blocks {
 8374                    new_styles.insert(
 8375                        *block_id,
 8376                        diagnostic_block_renderer(diagnostic.clone(), is_valid),
 8377                    );
 8378                }
 8379                self.display_map
 8380                    .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
 8381            }
 8382        }
 8383    }
 8384
 8385    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
 8386        self.dismiss_diagnostics(cx);
 8387        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
 8388            let buffer = self.buffer.read(cx).snapshot(cx);
 8389
 8390            let mut primary_range = None;
 8391            let mut primary_message = None;
 8392            let mut group_end = Point::zero();
 8393            let diagnostic_group = buffer
 8394                .diagnostic_group::<Point>(group_id)
 8395                .map(|entry| {
 8396                    if entry.range.end > group_end {
 8397                        group_end = entry.range.end;
 8398                    }
 8399                    if entry.diagnostic.is_primary {
 8400                        primary_range = Some(entry.range.clone());
 8401                        primary_message = Some(entry.diagnostic.message.clone());
 8402                    }
 8403                    entry
 8404                })
 8405                .collect::<Vec<_>>();
 8406            let primary_range = primary_range?;
 8407            let primary_message = primary_message?;
 8408            let primary_range =
 8409                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
 8410
 8411            let blocks = display_map
 8412                .insert_blocks(
 8413                    diagnostic_group.iter().map(|entry| {
 8414                        let diagnostic = entry.diagnostic.clone();
 8415                        let message_height = diagnostic.message.matches('\n').count() as u8 + 1;
 8416                        BlockProperties {
 8417                            style: BlockStyle::Fixed,
 8418                            position: buffer.anchor_after(entry.range.start),
 8419                            height: message_height,
 8420                            render: diagnostic_block_renderer(diagnostic, true),
 8421                            disposition: BlockDisposition::Below,
 8422                        }
 8423                    }),
 8424                    cx,
 8425                )
 8426                .into_iter()
 8427                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
 8428                .collect();
 8429
 8430            Some(ActiveDiagnosticGroup {
 8431                primary_range,
 8432                primary_message,
 8433                blocks,
 8434                is_valid: true,
 8435            })
 8436        });
 8437        self.active_diagnostics.is_some()
 8438    }
 8439
 8440    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
 8441        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
 8442            self.display_map.update(cx, |display_map, cx| {
 8443                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
 8444            });
 8445            cx.notify();
 8446        }
 8447    }
 8448
 8449    pub fn set_selections_from_remote(
 8450        &mut self,
 8451        selections: Vec<Selection<Anchor>>,
 8452        pending_selection: Option<Selection<Anchor>>,
 8453        cx: &mut ViewContext<Self>,
 8454    ) {
 8455        let old_cursor_position = self.selections.newest_anchor().head();
 8456        self.selections.change_with(cx, |s| {
 8457            s.select_anchors(selections);
 8458            if let Some(pending_selection) = pending_selection {
 8459                s.set_pending(pending_selection, SelectMode::Character);
 8460            } else {
 8461                s.clear_pending();
 8462            }
 8463        });
 8464        self.selections_did_change(false, &old_cursor_position, cx);
 8465    }
 8466
 8467    fn push_to_selection_history(&mut self) {
 8468        self.selection_history.push(SelectionHistoryEntry {
 8469            selections: self.selections.disjoint_anchors(),
 8470            select_next_state: self.select_next_state.clone(),
 8471            select_prev_state: self.select_prev_state.clone(),
 8472            add_selections_state: self.add_selections_state.clone(),
 8473        });
 8474    }
 8475
 8476    pub fn transact(
 8477        &mut self,
 8478        cx: &mut ViewContext<Self>,
 8479        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
 8480    ) -> Option<TransactionId> {
 8481        self.start_transaction_at(Instant::now(), cx);
 8482        update(self, cx);
 8483        self.end_transaction_at(Instant::now(), cx)
 8484    }
 8485
 8486    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
 8487        self.end_selection(cx);
 8488        if let Some(tx_id) = self
 8489            .buffer
 8490            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
 8491        {
 8492            self.selection_history
 8493                .insert_transaction(tx_id, self.selections.disjoint_anchors());
 8494        }
 8495    }
 8496
 8497    fn end_transaction_at(
 8498        &mut self,
 8499        now: Instant,
 8500        cx: &mut ViewContext<Self>,
 8501    ) -> Option<TransactionId> {
 8502        if let Some(tx_id) = self
 8503            .buffer
 8504            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 8505        {
 8506            if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
 8507                *end_selections = Some(self.selections.disjoint_anchors());
 8508            } else {
 8509                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
 8510            }
 8511
 8512            cx.emit(EditorEvent::Edited);
 8513            Some(tx_id)
 8514        } else {
 8515            None
 8516        }
 8517    }
 8518
 8519    pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
 8520        let mut fold_ranges = Vec::new();
 8521
 8522        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8523
 8524        let selections = self.selections.all_adjusted(cx);
 8525        for selection in selections {
 8526            let range = selection.range().sorted();
 8527            let buffer_start_row = range.start.row;
 8528
 8529            for row in (0..=range.end.row).rev() {
 8530                let fold_range = display_map.foldable_range(row);
 8531
 8532                if let Some(fold_range) = fold_range {
 8533                    if fold_range.end.row >= buffer_start_row {
 8534                        fold_ranges.push(fold_range);
 8535                        if row <= range.start.row {
 8536                            break;
 8537                        }
 8538                    }
 8539                }
 8540            }
 8541        }
 8542
 8543        self.fold_ranges(fold_ranges, true, cx);
 8544    }
 8545
 8546    pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
 8547        let buffer_row = fold_at.buffer_row;
 8548        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8549
 8550        if let Some(fold_range) = display_map.foldable_range(buffer_row) {
 8551            let autoscroll = self
 8552                .selections
 8553                .all::<Point>(cx)
 8554                .iter()
 8555                .any(|selection| fold_range.overlaps(&selection.range()));
 8556
 8557            self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
 8558        }
 8559    }
 8560
 8561    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
 8562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8563        let buffer = &display_map.buffer_snapshot;
 8564        let selections = self.selections.all::<Point>(cx);
 8565        let ranges = selections
 8566            .iter()
 8567            .map(|s| {
 8568                let range = s.display_range(&display_map).sorted();
 8569                let mut start = range.start.to_point(&display_map);
 8570                let mut end = range.end.to_point(&display_map);
 8571                start.column = 0;
 8572                end.column = buffer.line_len(end.row);
 8573                start..end
 8574            })
 8575            .collect::<Vec<_>>();
 8576
 8577        self.unfold_ranges(ranges, true, true, cx);
 8578    }
 8579
 8580    pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
 8581        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8582
 8583        let intersection_range = Point::new(unfold_at.buffer_row, 0)
 8584            ..Point::new(
 8585                unfold_at.buffer_row,
 8586                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
 8587            );
 8588
 8589        let autoscroll = self
 8590            .selections
 8591            .all::<Point>(cx)
 8592            .iter()
 8593            .any(|selection| selection.range().overlaps(&intersection_range));
 8594
 8595        self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
 8596    }
 8597
 8598    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
 8599        let selections = self.selections.all::<Point>(cx);
 8600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8601        let line_mode = self.selections.line_mode;
 8602        let ranges = selections.into_iter().map(|s| {
 8603            if line_mode {
 8604                let start = Point::new(s.start.row, 0);
 8605                let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row));
 8606                start..end
 8607            } else {
 8608                s.start..s.end
 8609            }
 8610        });
 8611        self.fold_ranges(ranges, true, cx);
 8612    }
 8613
 8614    pub fn fold_ranges<T: ToOffset + Clone>(
 8615        &mut self,
 8616        ranges: impl IntoIterator<Item = Range<T>>,
 8617        auto_scroll: bool,
 8618        cx: &mut ViewContext<Self>,
 8619    ) {
 8620        let mut ranges = ranges.into_iter().peekable();
 8621        if ranges.peek().is_some() {
 8622            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
 8623
 8624            if auto_scroll {
 8625                self.request_autoscroll(Autoscroll::fit(), cx);
 8626            }
 8627
 8628            cx.notify();
 8629        }
 8630    }
 8631
 8632    pub fn unfold_ranges<T: ToOffset + Clone>(
 8633        &mut self,
 8634        ranges: impl IntoIterator<Item = Range<T>>,
 8635        inclusive: bool,
 8636        auto_scroll: bool,
 8637        cx: &mut ViewContext<Self>,
 8638    ) {
 8639        let mut ranges = ranges.into_iter().peekable();
 8640        if ranges.peek().is_some() {
 8641            self.display_map
 8642                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
 8643            if auto_scroll {
 8644                self.request_autoscroll(Autoscroll::fit(), cx);
 8645            }
 8646
 8647            cx.notify();
 8648        }
 8649    }
 8650
 8651    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext<Self>) {
 8652        if hovered != self.gutter_hovered {
 8653            self.gutter_hovered = hovered;
 8654            cx.notify();
 8655        }
 8656    }
 8657
 8658    pub fn insert_blocks(
 8659        &mut self,
 8660        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
 8661        autoscroll: Option<Autoscroll>,
 8662        cx: &mut ViewContext<Self>,
 8663    ) -> Vec<BlockId> {
 8664        let blocks = self
 8665            .display_map
 8666            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
 8667        if let Some(autoscroll) = autoscroll {
 8668            self.request_autoscroll(autoscroll, cx);
 8669        }
 8670        blocks
 8671    }
 8672
 8673    pub fn replace_blocks(
 8674        &mut self,
 8675        blocks: HashMap<BlockId, RenderBlock>,
 8676        autoscroll: Option<Autoscroll>,
 8677        cx: &mut ViewContext<Self>,
 8678    ) {
 8679        self.display_map
 8680            .update(cx, |display_map, _| display_map.replace_blocks(blocks));
 8681        if let Some(autoscroll) = autoscroll {
 8682            self.request_autoscroll(autoscroll, cx);
 8683        }
 8684    }
 8685
 8686    pub fn remove_blocks(
 8687        &mut self,
 8688        block_ids: HashSet<BlockId>,
 8689        autoscroll: Option<Autoscroll>,
 8690        cx: &mut ViewContext<Self>,
 8691    ) {
 8692        self.display_map.update(cx, |display_map, cx| {
 8693            display_map.remove_blocks(block_ids, cx)
 8694        });
 8695        if let Some(autoscroll) = autoscroll {
 8696            self.request_autoscroll(autoscroll, cx);
 8697        }
 8698    }
 8699
 8700    pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
 8701        self.display_map
 8702            .update(cx, |map, cx| map.snapshot(cx))
 8703            .longest_row()
 8704    }
 8705
 8706    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
 8707        self.display_map
 8708            .update(cx, |map, cx| map.snapshot(cx))
 8709            .max_point()
 8710    }
 8711
 8712    pub fn text(&self, cx: &AppContext) -> String {
 8713        self.buffer.read(cx).read(cx).text()
 8714    }
 8715
 8716    pub fn text_option(&self, cx: &AppContext) -> Option<String> {
 8717        let text = self.text(cx);
 8718        let text = text.trim();
 8719
 8720        if text.is_empty() {
 8721            return None;
 8722        }
 8723
 8724        Some(text.to_string())
 8725    }
 8726
 8727    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
 8728        self.transact(cx, |this, cx| {
 8729            this.buffer
 8730                .read(cx)
 8731                .as_singleton()
 8732                .expect("you can only call set_text on editors for singleton buffers")
 8733                .update(cx, |buffer, cx| buffer.set_text(text, cx));
 8734        });
 8735    }
 8736
 8737    pub fn display_text(&self, cx: &mut AppContext) -> String {
 8738        self.display_map
 8739            .update(cx, |map, cx| map.snapshot(cx))
 8740            .text()
 8741    }
 8742
 8743    pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
 8744        let mut wrap_guides = smallvec::smallvec![];
 8745
 8746        if self.show_wrap_guides == Some(false) {
 8747            return wrap_guides;
 8748        }
 8749
 8750        let settings = self.buffer.read(cx).settings_at(0, cx);
 8751        if settings.show_wrap_guides {
 8752            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
 8753                wrap_guides.push((soft_wrap as usize, true));
 8754            }
 8755            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
 8756        }
 8757
 8758        wrap_guides
 8759    }
 8760
 8761    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
 8762        let settings = self.buffer.read(cx).settings_at(0, cx);
 8763        let mode = self
 8764            .soft_wrap_mode_override
 8765            .unwrap_or_else(|| settings.soft_wrap);
 8766        match mode {
 8767            language_settings::SoftWrap::None => SoftWrap::None,
 8768            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
 8769            language_settings::SoftWrap::PreferredLineLength => {
 8770                SoftWrap::Column(settings.preferred_line_length)
 8771            }
 8772        }
 8773    }
 8774
 8775    pub fn set_soft_wrap_mode(
 8776        &mut self,
 8777        mode: language_settings::SoftWrap,
 8778        cx: &mut ViewContext<Self>,
 8779    ) {
 8780        self.soft_wrap_mode_override = Some(mode);
 8781        cx.notify();
 8782    }
 8783
 8784    pub fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
 8785        let rem_size = cx.rem_size();
 8786        self.display_map.update(cx, |map, cx| {
 8787            map.set_font(
 8788                style.text.font(),
 8789                style.text.font_size.to_pixels(rem_size),
 8790                cx,
 8791            )
 8792        });
 8793        self.style = Some(style);
 8794    }
 8795
 8796    #[cfg(any(test, feature = "test-support"))]
 8797    pub fn style(&self) -> Option<&EditorStyle> {
 8798        self.style.as_ref()
 8799    }
 8800
 8801    // Called by the element. This method is not designed to be called outside of the editor
 8802    // element's layout code because it does not notify when rewrapping is computed synchronously.
 8803    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
 8804        self.display_map
 8805            .update(cx, |map, cx| map.set_wrap_width(width, cx))
 8806    }
 8807
 8808    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
 8809        if self.soft_wrap_mode_override.is_some() {
 8810            self.soft_wrap_mode_override.take();
 8811        } else {
 8812            let soft_wrap = match self.soft_wrap_mode(cx) {
 8813                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
 8814                SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None,
 8815            };
 8816            self.soft_wrap_mode_override = Some(soft_wrap);
 8817        }
 8818        cx.notify();
 8819    }
 8820
 8821    pub fn toggle_line_numbers(&mut self, _: &ToggleLineNumbers, cx: &mut ViewContext<Self>) {
 8822        let mut editor_settings = EditorSettings::get_global(cx).clone();
 8823        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
 8824        EditorSettings::override_global(editor_settings, cx);
 8825    }
 8826
 8827    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
 8828        self.show_gutter = show_gutter;
 8829        cx.notify();
 8830    }
 8831
 8832    pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
 8833        self.show_wrap_guides = Some(show_gutter);
 8834        cx.notify();
 8835    }
 8836
 8837    pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
 8838        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 8839            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 8840                cx.reveal_path(&file.abs_path(cx));
 8841            }
 8842        }
 8843    }
 8844
 8845    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
 8846        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 8847            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 8848                if let Some(path) = file.abs_path(cx).to_str() {
 8849                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
 8850                }
 8851            }
 8852        }
 8853    }
 8854
 8855    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
 8856        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 8857            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 8858                if let Some(path) = file.path().to_str() {
 8859                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
 8860                }
 8861            }
 8862        }
 8863    }
 8864
 8865    fn get_permalink_to_line(&mut self, cx: &mut ViewContext<Self>) -> Result<url::Url> {
 8866        use git::permalink::{build_permalink, BuildPermalinkParams};
 8867
 8868        let (path, repo) = maybe!({
 8869            let project_handle = self.project.as_ref()?.clone();
 8870            let project = project_handle.read(cx);
 8871            let buffer = self.buffer().read(cx).as_singleton()?;
 8872            let path = buffer
 8873                .read(cx)
 8874                .file()?
 8875                .as_local()?
 8876                .path()
 8877                .to_str()?
 8878                .to_string();
 8879            let repo = project.get_repo(&buffer.read(cx).project_path(cx)?, cx)?;
 8880            Some((path, repo))
 8881        })
 8882        .ok_or_else(|| anyhow!("unable to open git repository"))?;
 8883
 8884        const REMOTE_NAME: &str = "origin";
 8885        let origin_url = repo
 8886            .lock()
 8887            .remote_url(REMOTE_NAME)
 8888            .ok_or_else(|| anyhow!("remote \"{REMOTE_NAME}\" not found"))?;
 8889        let sha = repo
 8890            .lock()
 8891            .head_sha()
 8892            .ok_or_else(|| anyhow!("failed to read HEAD SHA"))?;
 8893        let selections = self.selections.all::<Point>(cx);
 8894        let selection = selections.iter().peekable().next();
 8895
 8896        build_permalink(BuildPermalinkParams {
 8897            remote_url: &origin_url,
 8898            sha: &sha,
 8899            path: &path,
 8900            selection: selection.map(|selection| selection.range()),
 8901        })
 8902    }
 8903
 8904    pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext<Self>) {
 8905        let permalink = self.get_permalink_to_line(cx);
 8906
 8907        match permalink {
 8908            Ok(permalink) => {
 8909                cx.write_to_clipboard(ClipboardItem::new(permalink.to_string()));
 8910            }
 8911            Err(err) => {
 8912                let message = format!("Failed to copy permalink: {err}");
 8913
 8914                Err::<(), anyhow::Error>(err).log_err();
 8915
 8916                if let Some(workspace) = self.workspace() {
 8917                    workspace.update(cx, |workspace, cx| {
 8918                        workspace.show_toast(Toast::new(0x156a5f9ee, message), cx)
 8919                    })
 8920                }
 8921            }
 8922        }
 8923    }
 8924
 8925    pub fn open_permalink_to_line(&mut self, _: &OpenPermalinkToLine, cx: &mut ViewContext<Self>) {
 8926        let permalink = self.get_permalink_to_line(cx);
 8927
 8928        match permalink {
 8929            Ok(permalink) => {
 8930                cx.open_url(permalink.as_ref());
 8931            }
 8932            Err(err) => {
 8933                let message = format!("Failed to open permalink: {err}");
 8934
 8935                Err::<(), anyhow::Error>(err).log_err();
 8936
 8937                if let Some(workspace) = self.workspace() {
 8938                    workspace.update(cx, |workspace, cx| {
 8939                        workspace.show_toast(Toast::new(0x45a8978, message), cx)
 8940                    })
 8941                }
 8942            }
 8943        }
 8944    }
 8945
 8946    /// Adds or removes (on `None` color) a highlight for the rows corresponding to the anchor range given.
 8947    /// On matching anchor range, replaces the old highlight; does not clear the other existing highlights.
 8948    /// If multiple anchor ranges will produce highlights for the same row, the last range added will be used.
 8949    pub fn highlight_rows<T: 'static>(
 8950        &mut self,
 8951        rows: Range<Anchor>,
 8952        color: Option<Hsla>,
 8953        cx: &mut ViewContext<Self>,
 8954    ) {
 8955        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 8956        match self.highlighted_rows.entry(TypeId::of::<T>()) {
 8957            hash_map::Entry::Occupied(o) => {
 8958                let row_highlights = o.into_mut();
 8959                let existing_highlight_index =
 8960                    row_highlights.binary_search_by(|(_, highlight_range, _)| {
 8961                        highlight_range
 8962                            .start
 8963                            .cmp(&rows.start, &multi_buffer_snapshot)
 8964                            .then(highlight_range.end.cmp(&rows.end, &multi_buffer_snapshot))
 8965                    });
 8966                match color {
 8967                    Some(color) => {
 8968                        let insert_index = match existing_highlight_index {
 8969                            Ok(i) => i,
 8970                            Err(i) => i,
 8971                        };
 8972                        row_highlights.insert(
 8973                            insert_index,
 8974                            (post_inc(&mut self.highlight_order), rows, color),
 8975                        );
 8976                    }
 8977                    None => {
 8978                        if let Ok(i) = existing_highlight_index {
 8979                            row_highlights.remove(i);
 8980                        }
 8981                    }
 8982                }
 8983            }
 8984            hash_map::Entry::Vacant(v) => {
 8985                if let Some(color) = color {
 8986                    v.insert(vec![(post_inc(&mut self.highlight_order), rows, color)]);
 8987                }
 8988            }
 8989        }
 8990    }
 8991
 8992    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
 8993    pub fn clear_row_highlights<T: 'static>(&mut self) {
 8994        self.highlighted_rows.remove(&TypeId::of::<T>());
 8995    }
 8996
 8997    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
 8998    pub fn highlighted_rows<T: 'static>(
 8999        &self,
 9000    ) -> Option<impl Iterator<Item = (&Range<Anchor>, &Hsla)>> {
 9001        Some(
 9002            self.highlighted_rows
 9003                .get(&TypeId::of::<T>())?
 9004                .iter()
 9005                .map(|(_, range, color)| (range, color)),
 9006        )
 9007    }
 9008
 9009    // Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
 9010    // Rerturns a map of display rows that are highlighted and their corresponding highlight color.
 9011    pub fn highlighted_display_rows(&mut self, cx: &mut WindowContext) -> BTreeMap<u32, Hsla> {
 9012        let snapshot = self.snapshot(cx);
 9013        let mut used_highlight_orders = HashMap::default();
 9014        self.highlighted_rows
 9015            .iter()
 9016            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
 9017            .fold(
 9018                BTreeMap::<u32, Hsla>::new(),
 9019                |mut unique_rows, (highlight_order, anchor_range, hsla)| {
 9020                    let start_row = anchor_range.start.to_display_point(&snapshot).row();
 9021                    let end_row = anchor_range.end.to_display_point(&snapshot).row();
 9022                    for row in start_row..=end_row {
 9023                        let used_index =
 9024                            used_highlight_orders.entry(row).or_insert(*highlight_order);
 9025                        if highlight_order >= used_index {
 9026                            *used_index = *highlight_order;
 9027                            unique_rows.insert(row, *hsla);
 9028                        }
 9029                    }
 9030                    unique_rows
 9031                },
 9032            )
 9033    }
 9034
 9035    pub fn highlight_background<T: 'static>(
 9036        &mut self,
 9037        ranges: Vec<Range<Anchor>>,
 9038        color_fetcher: fn(&ThemeColors) -> Hsla,
 9039        cx: &mut ViewContext<Self>,
 9040    ) {
 9041        let snapshot = self.snapshot(cx);
 9042        // this is to try and catch a panic sooner
 9043        for range in &ranges {
 9044            snapshot
 9045                .buffer_snapshot
 9046                .summary_for_anchor::<usize>(&range.start);
 9047            snapshot
 9048                .buffer_snapshot
 9049                .summary_for_anchor::<usize>(&range.end);
 9050        }
 9051
 9052        self.background_highlights
 9053            .insert(TypeId::of::<T>(), (color_fetcher, ranges));
 9054        cx.notify();
 9055    }
 9056
 9057    pub fn clear_background_highlights<T: 'static>(
 9058        &mut self,
 9059        _cx: &mut ViewContext<Self>,
 9060    ) -> Option<BackgroundHighlight> {
 9061        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>());
 9062        text_highlights
 9063    }
 9064
 9065    #[cfg(feature = "test-support")]
 9066    pub fn all_text_background_highlights(
 9067        &mut self,
 9068        cx: &mut ViewContext<Self>,
 9069    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
 9070        let snapshot = self.snapshot(cx);
 9071        let buffer = &snapshot.buffer_snapshot;
 9072        let start = buffer.anchor_before(0);
 9073        let end = buffer.anchor_after(buffer.len());
 9074        let theme = cx.theme().colors();
 9075        self.background_highlights_in_range(start..end, &snapshot, theme)
 9076    }
 9077
 9078    fn document_highlights_for_position<'a>(
 9079        &'a self,
 9080        position: Anchor,
 9081        buffer: &'a MultiBufferSnapshot,
 9082    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
 9083        let read_highlights = self
 9084            .background_highlights
 9085            .get(&TypeId::of::<DocumentHighlightRead>())
 9086            .map(|h| &h.1);
 9087        let write_highlights = self
 9088            .background_highlights
 9089            .get(&TypeId::of::<DocumentHighlightWrite>())
 9090            .map(|h| &h.1);
 9091        let left_position = position.bias_left(buffer);
 9092        let right_position = position.bias_right(buffer);
 9093        read_highlights
 9094            .into_iter()
 9095            .chain(write_highlights)
 9096            .flat_map(move |ranges| {
 9097                let start_ix = match ranges.binary_search_by(|probe| {
 9098                    let cmp = probe.end.cmp(&left_position, buffer);
 9099                    if cmp.is_ge() {
 9100                        Ordering::Greater
 9101                    } else {
 9102                        Ordering::Less
 9103                    }
 9104                }) {
 9105                    Ok(i) | Err(i) => i,
 9106                };
 9107
 9108                ranges[start_ix..]
 9109                    .iter()
 9110                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
 9111            })
 9112    }
 9113
 9114    pub fn has_background_highlights<T: 'static>(&self) -> bool {
 9115        self.background_highlights
 9116            .get(&TypeId::of::<T>())
 9117            .map_or(false, |(_, highlights)| !highlights.is_empty())
 9118    }
 9119
 9120    pub fn background_highlights_in_range(
 9121        &self,
 9122        search_range: Range<Anchor>,
 9123        display_snapshot: &DisplaySnapshot,
 9124        theme: &ThemeColors,
 9125    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
 9126        let mut results = Vec::new();
 9127        for (color_fetcher, ranges) in self.background_highlights.values() {
 9128            let color = color_fetcher(theme);
 9129            let start_ix = match ranges.binary_search_by(|probe| {
 9130                let cmp = probe
 9131                    .end
 9132                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
 9133                if cmp.is_gt() {
 9134                    Ordering::Greater
 9135                } else {
 9136                    Ordering::Less
 9137                }
 9138            }) {
 9139                Ok(i) | Err(i) => i,
 9140            };
 9141            for range in &ranges[start_ix..] {
 9142                if range
 9143                    .start
 9144                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
 9145                    .is_ge()
 9146                {
 9147                    break;
 9148                }
 9149
 9150                let start = range.start.to_display_point(&display_snapshot);
 9151                let end = range.end.to_display_point(&display_snapshot);
 9152                results.push((start..end, color))
 9153            }
 9154        }
 9155        results
 9156    }
 9157
 9158    pub fn background_highlight_row_ranges<T: 'static>(
 9159        &self,
 9160        search_range: Range<Anchor>,
 9161        display_snapshot: &DisplaySnapshot,
 9162        count: usize,
 9163    ) -> Vec<RangeInclusive<DisplayPoint>> {
 9164        let mut results = Vec::new();
 9165        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
 9166            return vec![];
 9167        };
 9168
 9169        let start_ix = match ranges.binary_search_by(|probe| {
 9170            let cmp = probe
 9171                .end
 9172                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
 9173            if cmp.is_gt() {
 9174                Ordering::Greater
 9175            } else {
 9176                Ordering::Less
 9177            }
 9178        }) {
 9179            Ok(i) | Err(i) => i,
 9180        };
 9181        let mut push_region = |start: Option<Point>, end: Option<Point>| {
 9182            if let (Some(start_display), Some(end_display)) = (start, end) {
 9183                results.push(
 9184                    start_display.to_display_point(display_snapshot)
 9185                        ..=end_display.to_display_point(display_snapshot),
 9186                );
 9187            }
 9188        };
 9189        let mut start_row: Option<Point> = None;
 9190        let mut end_row: Option<Point> = None;
 9191        if ranges.len() > count {
 9192            return Vec::new();
 9193        }
 9194        for range in &ranges[start_ix..] {
 9195            if range
 9196                .start
 9197                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
 9198                .is_ge()
 9199            {
 9200                break;
 9201            }
 9202            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
 9203            if let Some(current_row) = &end_row {
 9204                if end.row == current_row.row {
 9205                    continue;
 9206                }
 9207            }
 9208            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
 9209            if start_row.is_none() {
 9210                assert_eq!(end_row, None);
 9211                start_row = Some(start);
 9212                end_row = Some(end);
 9213                continue;
 9214            }
 9215            if let Some(current_end) = end_row.as_mut() {
 9216                if start.row > current_end.row + 1 {
 9217                    push_region(start_row, end_row);
 9218                    start_row = Some(start);
 9219                    end_row = Some(end);
 9220                } else {
 9221                    // Merge two hunks.
 9222                    *current_end = end;
 9223                }
 9224            } else {
 9225                unreachable!();
 9226            }
 9227        }
 9228        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
 9229        push_region(start_row, end_row);
 9230        results
 9231    }
 9232
 9233    /// Get the text ranges corresponding to the redaction query
 9234    pub fn redacted_ranges(
 9235        &self,
 9236        search_range: Range<Anchor>,
 9237        display_snapshot: &DisplaySnapshot,
 9238        cx: &WindowContext,
 9239    ) -> Vec<Range<DisplayPoint>> {
 9240        display_snapshot
 9241            .buffer_snapshot
 9242            .redacted_ranges(search_range, |file| {
 9243                if let Some(file) = file {
 9244                    file.is_private()
 9245                        && EditorSettings::get(Some((file.worktree_id(), file.path())), cx)
 9246                            .redact_private_values
 9247                } else {
 9248                    false
 9249                }
 9250            })
 9251            .map(|range| {
 9252                range.start.to_display_point(display_snapshot)
 9253                    ..range.end.to_display_point(display_snapshot)
 9254            })
 9255            .collect()
 9256    }
 9257
 9258    pub fn highlight_text<T: 'static>(
 9259        &mut self,
 9260        ranges: Vec<Range<Anchor>>,
 9261        style: HighlightStyle,
 9262        cx: &mut ViewContext<Self>,
 9263    ) {
 9264        self.display_map.update(cx, |map, _| {
 9265            map.highlight_text(TypeId::of::<T>(), ranges, style)
 9266        });
 9267        cx.notify();
 9268    }
 9269
 9270    pub(crate) fn highlight_inlays<T: 'static>(
 9271        &mut self,
 9272        highlights: Vec<InlayHighlight>,
 9273        style: HighlightStyle,
 9274        cx: &mut ViewContext<Self>,
 9275    ) {
 9276        self.display_map.update(cx, |map, _| {
 9277            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
 9278        });
 9279        cx.notify();
 9280    }
 9281
 9282    pub fn text_highlights<'a, T: 'static>(
 9283        &'a self,
 9284        cx: &'a AppContext,
 9285    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
 9286        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
 9287    }
 9288
 9289    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
 9290        let cleared = self
 9291            .display_map
 9292            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
 9293        if cleared {
 9294            cx.notify();
 9295        }
 9296    }
 9297
 9298    pub fn show_local_cursors(&self, cx: &WindowContext) -> bool {
 9299        (self.read_only(cx) || self.blink_manager.read(cx).visible())
 9300            && self.focus_handle.is_focused(cx)
 9301    }
 9302
 9303    fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
 9304        cx.notify();
 9305    }
 9306
 9307    fn on_buffer_event(
 9308        &mut self,
 9309        multibuffer: Model<MultiBuffer>,
 9310        event: &multi_buffer::Event,
 9311        cx: &mut ViewContext<Self>,
 9312    ) {
 9313        match event {
 9314            multi_buffer::Event::Edited {
 9315                singleton_buffer_edited,
 9316            } => {
 9317                self.refresh_active_diagnostics(cx);
 9318                self.refresh_code_actions(cx);
 9319                if self.has_active_copilot_suggestion(cx) {
 9320                    self.update_visible_copilot_suggestion(cx);
 9321                }
 9322                cx.emit(EditorEvent::BufferEdited);
 9323                cx.emit(SearchEvent::MatchesInvalidated);
 9324
 9325                if *singleton_buffer_edited {
 9326                    if let Some(project) = &self.project {
 9327                        let project = project.read(cx);
 9328                        let languages_affected = multibuffer
 9329                            .read(cx)
 9330                            .all_buffers()
 9331                            .into_iter()
 9332                            .filter_map(|buffer| {
 9333                                let buffer = buffer.read(cx);
 9334                                let language = buffer.language()?;
 9335                                if project.is_local()
 9336                                    && project.language_servers_for_buffer(buffer, cx).count() == 0
 9337                                {
 9338                                    None
 9339                                } else {
 9340                                    Some(language)
 9341                                }
 9342                            })
 9343                            .cloned()
 9344                            .collect::<HashSet<_>>();
 9345                        if !languages_affected.is_empty() {
 9346                            self.refresh_inlay_hints(
 9347                                InlayHintRefreshReason::BufferEdited(languages_affected),
 9348                                cx,
 9349                            );
 9350                        }
 9351                    }
 9352                }
 9353
 9354                let Some(project) = &self.project else { return };
 9355                let telemetry = project.read(cx).client().telemetry().clone();
 9356                telemetry.log_edit_event("editor");
 9357            }
 9358            multi_buffer::Event::ExcerptsAdded {
 9359                buffer,
 9360                predecessor,
 9361                excerpts,
 9362            } => {
 9363                cx.emit(EditorEvent::ExcerptsAdded {
 9364                    buffer: buffer.clone(),
 9365                    predecessor: *predecessor,
 9366                    excerpts: excerpts.clone(),
 9367                });
 9368                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 9369            }
 9370            multi_buffer::Event::ExcerptsRemoved { ids } => {
 9371                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
 9372                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
 9373            }
 9374            multi_buffer::Event::Reparsed => cx.emit(EditorEvent::Reparsed),
 9375            multi_buffer::Event::LanguageChanged => {
 9376                cx.emit(EditorEvent::Reparsed);
 9377                cx.notify();
 9378            }
 9379            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
 9380            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
 9381            multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => {
 9382                cx.emit(EditorEvent::TitleChanged)
 9383            }
 9384            multi_buffer::Event::DiffBaseChanged => cx.emit(EditorEvent::DiffBaseChanged),
 9385            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
 9386            multi_buffer::Event::DiagnosticsUpdated => {
 9387                self.refresh_active_diagnostics(cx);
 9388            }
 9389            _ => {}
 9390        };
 9391    }
 9392
 9393    fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
 9394        cx.notify();
 9395    }
 9396
 9397    fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
 9398        self.refresh_copilot_suggestions(true, cx);
 9399        self.refresh_inlay_hints(
 9400            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
 9401                self.selections.newest_anchor().head(),
 9402                &self.buffer.read(cx).snapshot(cx),
 9403                cx,
 9404            )),
 9405            cx,
 9406        );
 9407        let editor_settings = EditorSettings::get_global(cx);
 9408        self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
 9409        self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
 9410        cx.notify();
 9411    }
 9412
 9413    pub fn set_searchable(&mut self, searchable: bool) {
 9414        self.searchable = searchable;
 9415    }
 9416
 9417    pub fn searchable(&self) -> bool {
 9418        self.searchable
 9419    }
 9420
 9421    fn open_excerpts_in_split(&mut self, _: &OpenExcerptsSplit, cx: &mut ViewContext<Self>) {
 9422        self.open_excerpts_common(true, cx)
 9423    }
 9424
 9425    fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext<Self>) {
 9426        self.open_excerpts_common(false, cx)
 9427    }
 9428
 9429    fn open_excerpts_common(&mut self, split: bool, cx: &mut ViewContext<Self>) {
 9430        let buffer = self.buffer.read(cx);
 9431        if buffer.is_singleton() {
 9432            cx.propagate();
 9433            return;
 9434        }
 9435
 9436        let Some(workspace) = self.workspace() else {
 9437            cx.propagate();
 9438            return;
 9439        };
 9440
 9441        let mut new_selections_by_buffer = HashMap::default();
 9442        for selection in self.selections.all::<usize>(cx) {
 9443            for (buffer, mut range, _) in
 9444                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
 9445            {
 9446                if selection.reversed {
 9447                    mem::swap(&mut range.start, &mut range.end);
 9448                }
 9449                new_selections_by_buffer
 9450                    .entry(buffer)
 9451                    .or_insert(Vec::new())
 9452                    .push(range)
 9453            }
 9454        }
 9455
 9456        // We defer the pane interaction because we ourselves are a workspace item
 9457        // and activating a new item causes the pane to call a method on us reentrantly,
 9458        // which panics if we're on the stack.
 9459        cx.window_context().defer(move |cx| {
 9460            workspace.update(cx, |workspace, cx| {
 9461                let pane = if split {
 9462                    workspace.adjacent_pane(cx)
 9463                } else {
 9464                    workspace.active_pane().clone()
 9465                };
 9466                pane.update(cx, |pane, _| pane.disable_history());
 9467
 9468                for (buffer, ranges) in new_selections_by_buffer.into_iter() {
 9469                    let editor = workspace.open_project_item::<Self>(pane.clone(), buffer, cx);
 9470                    editor.update(cx, |editor, cx| {
 9471                        editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
 9472                            s.select_ranges(ranges);
 9473                        });
 9474                    });
 9475                }
 9476
 9477                pane.update(cx, |pane, _| pane.enable_history());
 9478            })
 9479        });
 9480    }
 9481
 9482    fn jump(
 9483        &mut self,
 9484        path: ProjectPath,
 9485        position: Point,
 9486        anchor: language::Anchor,
 9487        cx: &mut ViewContext<Self>,
 9488    ) {
 9489        let workspace = self.workspace();
 9490        cx.spawn(|_, mut cx| async move {
 9491            let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?;
 9492            let editor = workspace.update(&mut cx, |workspace, cx| {
 9493                workspace.open_path(path, None, true, cx)
 9494            })?;
 9495            let editor = editor
 9496                .await?
 9497                .downcast::<Editor>()
 9498                .ok_or_else(|| anyhow!("opened item was not an editor"))?
 9499                .downgrade();
 9500            editor.update(&mut cx, |editor, cx| {
 9501                let buffer = editor
 9502                    .buffer()
 9503                    .read(cx)
 9504                    .as_singleton()
 9505                    .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
 9506                let buffer = buffer.read(cx);
 9507                let cursor = if buffer.can_resolve(&anchor) {
 9508                    language::ToPoint::to_point(&anchor, buffer)
 9509                } else {
 9510                    buffer.clip_point(position, Bias::Left)
 9511                };
 9512
 9513                let nav_history = editor.nav_history.take();
 9514                editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
 9515                    s.select_ranges([cursor..cursor]);
 9516                });
 9517                editor.nav_history = nav_history;
 9518
 9519                anyhow::Ok(())
 9520            })??;
 9521
 9522            anyhow::Ok(())
 9523        })
 9524        .detach_and_log_err(cx);
 9525    }
 9526
 9527    fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
 9528        let snapshot = self.buffer.read(cx).read(cx);
 9529        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
 9530        Some(
 9531            ranges
 9532                .iter()
 9533                .map(move |range| {
 9534                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
 9535                })
 9536                .collect(),
 9537        )
 9538    }
 9539
 9540    fn selection_replacement_ranges(
 9541        &self,
 9542        range: Range<OffsetUtf16>,
 9543        cx: &AppContext,
 9544    ) -> Vec<Range<OffsetUtf16>> {
 9545        let selections = self.selections.all::<OffsetUtf16>(cx);
 9546        let newest_selection = selections
 9547            .iter()
 9548            .max_by_key(|selection| selection.id)
 9549            .unwrap();
 9550        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
 9551        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
 9552        let snapshot = self.buffer.read(cx).read(cx);
 9553        selections
 9554            .into_iter()
 9555            .map(|mut selection| {
 9556                selection.start.0 =
 9557                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
 9558                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
 9559                snapshot.clip_offset_utf16(selection.start, Bias::Left)
 9560                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
 9561            })
 9562            .collect()
 9563    }
 9564
 9565    fn report_copilot_event(
 9566        &self,
 9567        suggestion_id: Option<String>,
 9568        suggestion_accepted: bool,
 9569        cx: &AppContext,
 9570    ) {
 9571        let Some(project) = &self.project else { return };
 9572
 9573        // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension
 9574        let file_extension = self
 9575            .buffer
 9576            .read(cx)
 9577            .as_singleton()
 9578            .and_then(|b| b.read(cx).file())
 9579            .and_then(|file| Path::new(file.file_name(cx)).extension())
 9580            .and_then(|e| e.to_str())
 9581            .map(|a| a.to_string());
 9582
 9583        let telemetry = project.read(cx).client().telemetry().clone();
 9584
 9585        telemetry.report_copilot_event(suggestion_id, suggestion_accepted, file_extension)
 9586    }
 9587
 9588    #[cfg(any(test, feature = "test-support"))]
 9589    fn report_editor_event(
 9590        &self,
 9591        _operation: &'static str,
 9592        _file_extension: Option<String>,
 9593        _cx: &AppContext,
 9594    ) {
 9595    }
 9596
 9597    #[cfg(not(any(test, feature = "test-support")))]
 9598    fn report_editor_event(
 9599        &self,
 9600        operation: &'static str,
 9601        file_extension: Option<String>,
 9602        cx: &AppContext,
 9603    ) {
 9604        let Some(project) = &self.project else { return };
 9605
 9606        // If None, we are in a file without an extension
 9607        let file = self
 9608            .buffer
 9609            .read(cx)
 9610            .as_singleton()
 9611            .and_then(|b| b.read(cx).file());
 9612        let file_extension = file_extension.or(file
 9613            .as_ref()
 9614            .and_then(|file| Path::new(file.file_name(cx)).extension())
 9615            .and_then(|e| e.to_str())
 9616            .map(|a| a.to_string()));
 9617
 9618        let vim_mode = cx
 9619            .global::<SettingsStore>()
 9620            .raw_user_settings()
 9621            .get("vim_mode")
 9622            == Some(&serde_json::Value::Bool(true));
 9623        let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None);
 9624        let copilot_enabled_for_language = self
 9625            .buffer
 9626            .read(cx)
 9627            .settings_at(0, cx)
 9628            .show_copilot_suggestions;
 9629
 9630        let telemetry = project.read(cx).client().telemetry().clone();
 9631        telemetry.report_editor_event(
 9632            file_extension,
 9633            vim_mode,
 9634            operation,
 9635            copilot_enabled,
 9636            copilot_enabled_for_language,
 9637        )
 9638    }
 9639
 9640    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
 9641    /// with each line being an array of {text, highlight} objects.
 9642    fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
 9643        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
 9644            return;
 9645        };
 9646
 9647        #[derive(Serialize)]
 9648        struct Chunk<'a> {
 9649            text: String,
 9650            highlight: Option<&'a str>,
 9651        }
 9652
 9653        let snapshot = buffer.read(cx).snapshot();
 9654        let range = self
 9655            .selected_text_range(cx)
 9656            .and_then(|selected_range| {
 9657                if selected_range.is_empty() {
 9658                    None
 9659                } else {
 9660                    Some(selected_range)
 9661                }
 9662            })
 9663            .unwrap_or_else(|| 0..snapshot.len());
 9664
 9665        let chunks = snapshot.chunks(range, true);
 9666        let mut lines = Vec::new();
 9667        let mut line: VecDeque<Chunk> = VecDeque::new();
 9668
 9669        let Some(style) = self.style.as_ref() else {
 9670            return;
 9671        };
 9672
 9673        for chunk in chunks {
 9674            let highlight = chunk
 9675                .syntax_highlight_id
 9676                .and_then(|id| id.name(&style.syntax));
 9677            let mut chunk_lines = chunk.text.split('\n').peekable();
 9678            while let Some(text) = chunk_lines.next() {
 9679                let mut merged_with_last_token = false;
 9680                if let Some(last_token) = line.back_mut() {
 9681                    if last_token.highlight == highlight {
 9682                        last_token.text.push_str(text);
 9683                        merged_with_last_token = true;
 9684                    }
 9685                }
 9686
 9687                if !merged_with_last_token {
 9688                    line.push_back(Chunk {
 9689                        text: text.into(),
 9690                        highlight,
 9691                    });
 9692                }
 9693
 9694                if chunk_lines.peek().is_some() {
 9695                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
 9696                        line.pop_front();
 9697                    }
 9698                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
 9699                        line.pop_back();
 9700                    }
 9701
 9702                    lines.push(mem::take(&mut line));
 9703                }
 9704            }
 9705        }
 9706
 9707        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
 9708            return;
 9709        };
 9710        cx.write_to_clipboard(ClipboardItem::new(lines));
 9711    }
 9712
 9713    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
 9714        &self.inlay_hint_cache
 9715    }
 9716
 9717    pub fn replay_insert_event(
 9718        &mut self,
 9719        text: &str,
 9720        relative_utf16_range: Option<Range<isize>>,
 9721        cx: &mut ViewContext<Self>,
 9722    ) {
 9723        if !self.input_enabled {
 9724            cx.emit(EditorEvent::InputIgnored { text: text.into() });
 9725            return;
 9726        }
 9727        if let Some(relative_utf16_range) = relative_utf16_range {
 9728            let selections = self.selections.all::<OffsetUtf16>(cx);
 9729            self.change_selections(None, cx, |s| {
 9730                let new_ranges = selections.into_iter().map(|range| {
 9731                    let start = OffsetUtf16(
 9732                        range
 9733                            .head()
 9734                            .0
 9735                            .saturating_add_signed(relative_utf16_range.start),
 9736                    );
 9737                    let end = OffsetUtf16(
 9738                        range
 9739                            .head()
 9740                            .0
 9741                            .saturating_add_signed(relative_utf16_range.end),
 9742                    );
 9743                    start..end
 9744                });
 9745                s.select_ranges(new_ranges);
 9746            });
 9747        }
 9748
 9749        self.handle_input(text, cx);
 9750    }
 9751
 9752    pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
 9753        let Some(project) = self.project.as_ref() else {
 9754            return false;
 9755        };
 9756        let project = project.read(cx);
 9757
 9758        let mut supports = false;
 9759        self.buffer().read(cx).for_each_buffer(|buffer| {
 9760            if !supports {
 9761                supports = project
 9762                    .language_servers_for_buffer(buffer.read(cx), cx)
 9763                    .any(
 9764                        |(_, server)| match server.capabilities().inlay_hint_provider {
 9765                            Some(lsp::OneOf::Left(enabled)) => enabled,
 9766                            Some(lsp::OneOf::Right(_)) => true,
 9767                            None => false,
 9768                        },
 9769                    )
 9770            }
 9771        });
 9772        supports
 9773    }
 9774
 9775    pub fn focus(&self, cx: &mut WindowContext) {
 9776        cx.focus(&self.focus_handle)
 9777    }
 9778
 9779    pub fn is_focused(&self, cx: &WindowContext) -> bool {
 9780        self.focus_handle.is_focused(cx)
 9781    }
 9782
 9783    fn handle_focus(&mut self, cx: &mut ViewContext<Self>) {
 9784        cx.emit(EditorEvent::Focused);
 9785
 9786        if let Some(rename) = self.pending_rename.as_ref() {
 9787            let rename_editor_focus_handle = rename.editor.read(cx).focus_handle.clone();
 9788            cx.focus(&rename_editor_focus_handle);
 9789        } else {
 9790            self.blink_manager.update(cx, BlinkManager::enable);
 9791            self.show_cursor_names(cx);
 9792            self.buffer.update(cx, |buffer, cx| {
 9793                buffer.finalize_last_transaction(cx);
 9794                if self.leader_peer_id.is_none() {
 9795                    buffer.set_active_selections(
 9796                        &self.selections.disjoint_anchors(),
 9797                        self.selections.line_mode,
 9798                        self.cursor_shape,
 9799                        cx,
 9800                    );
 9801                }
 9802            });
 9803        }
 9804    }
 9805
 9806    pub fn handle_blur(&mut self, cx: &mut ViewContext<Self>) {
 9807        self.blink_manager.update(cx, BlinkManager::disable);
 9808        self.buffer
 9809            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 9810        self.hide_context_menu(cx);
 9811        hide_hover(self, cx);
 9812        cx.emit(EditorEvent::Blurred);
 9813        cx.notify();
 9814    }
 9815
 9816    pub fn register_action<A: Action>(
 9817        &mut self,
 9818        listener: impl Fn(&A, &mut WindowContext) + 'static,
 9819    ) -> &mut Self {
 9820        let listener = Arc::new(listener);
 9821
 9822        self.editor_actions.push(Box::new(move |cx| {
 9823            let _view = cx.view().clone();
 9824            let cx = cx.window_context();
 9825            let listener = listener.clone();
 9826            cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
 9827                let action = action.downcast_ref().unwrap();
 9828                if phase == DispatchPhase::Bubble {
 9829                    listener(action, cx)
 9830                }
 9831            })
 9832        }));
 9833        self
 9834    }
 9835}
 9836
 9837pub trait CollaborationHub {
 9838    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
 9839    fn user_participant_indices<'a>(
 9840        &self,
 9841        cx: &'a AppContext,
 9842    ) -> &'a HashMap<u64, ParticipantIndex>;
 9843    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString>;
 9844}
 9845
 9846impl CollaborationHub for Model<Project> {
 9847    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
 9848        self.read(cx).collaborators()
 9849    }
 9850
 9851    fn user_participant_indices<'a>(
 9852        &self,
 9853        cx: &'a AppContext,
 9854    ) -> &'a HashMap<u64, ParticipantIndex> {
 9855        self.read(cx).user_store().read(cx).participant_indices()
 9856    }
 9857
 9858    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString> {
 9859        let this = self.read(cx);
 9860        let user_ids = this.collaborators().values().map(|c| c.user_id);
 9861        this.user_store().read_with(cx, |user_store, cx| {
 9862            user_store.participant_names(user_ids, cx)
 9863        })
 9864    }
 9865}
 9866
 9867pub trait CompletionProvider {
 9868    fn completions(
 9869        &self,
 9870        buffer: &Model<Buffer>,
 9871        buffer_position: text::Anchor,
 9872        cx: &mut ViewContext<Editor>,
 9873    ) -> Task<Result<Vec<Completion>>>;
 9874
 9875    fn resolve_completions(
 9876        &self,
 9877        completion_indices: Vec<usize>,
 9878        completions: Arc<RwLock<Box<[Completion]>>>,
 9879        cx: &mut ViewContext<Editor>,
 9880    ) -> Task<Result<bool>>;
 9881
 9882    fn apply_additional_edits_for_completion(
 9883        &self,
 9884        buffer: Model<Buffer>,
 9885        completion: Completion,
 9886        push_to_history: bool,
 9887        cx: &mut ViewContext<Editor>,
 9888    ) -> Task<Result<Option<language::Transaction>>>;
 9889}
 9890
 9891impl CompletionProvider for Model<Project> {
 9892    fn completions(
 9893        &self,
 9894        buffer: &Model<Buffer>,
 9895        buffer_position: text::Anchor,
 9896        cx: &mut ViewContext<Editor>,
 9897    ) -> Task<Result<Vec<Completion>>> {
 9898        self.update(cx, |project, cx| {
 9899            project.completions(&buffer, buffer_position, cx)
 9900        })
 9901    }
 9902
 9903    fn resolve_completions(
 9904        &self,
 9905        completion_indices: Vec<usize>,
 9906        completions: Arc<RwLock<Box<[Completion]>>>,
 9907        cx: &mut ViewContext<Editor>,
 9908    ) -> Task<Result<bool>> {
 9909        self.update(cx, |project, cx| {
 9910            project.resolve_completions(completion_indices, completions, cx)
 9911        })
 9912    }
 9913
 9914    fn apply_additional_edits_for_completion(
 9915        &self,
 9916        buffer: Model<Buffer>,
 9917        completion: Completion,
 9918        push_to_history: bool,
 9919        cx: &mut ViewContext<Editor>,
 9920    ) -> Task<Result<Option<language::Transaction>>> {
 9921        self.update(cx, |project, cx| {
 9922            project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
 9923        })
 9924    }
 9925}
 9926
 9927fn inlay_hint_settings(
 9928    location: Anchor,
 9929    snapshot: &MultiBufferSnapshot,
 9930    cx: &mut ViewContext<'_, Editor>,
 9931) -> InlayHintSettings {
 9932    let file = snapshot.file_at(location);
 9933    let language = snapshot.language_at(location);
 9934    let settings = all_language_settings(file, cx);
 9935    settings
 9936        .language(language.map(|l| l.name()).as_deref())
 9937        .inlay_hints
 9938}
 9939
 9940fn consume_contiguous_rows(
 9941    contiguous_row_selections: &mut Vec<Selection<Point>>,
 9942    selection: &Selection<Point>,
 9943    display_map: &DisplaySnapshot,
 9944    selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
 9945) -> (u32, u32) {
 9946    contiguous_row_selections.push(selection.clone());
 9947    let start_row = selection.start.row;
 9948    let mut end_row = ending_row(selection, display_map);
 9949
 9950    while let Some(next_selection) = selections.peek() {
 9951        if next_selection.start.row <= end_row {
 9952            end_row = ending_row(next_selection, display_map);
 9953            contiguous_row_selections.push(selections.next().unwrap().clone());
 9954        } else {
 9955            break;
 9956        }
 9957    }
 9958    (start_row, end_row)
 9959}
 9960
 9961fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
 9962    if next_selection.end.column > 0 || next_selection.is_empty() {
 9963        display_map.next_line_boundary(next_selection.end).0.row + 1
 9964    } else {
 9965        next_selection.end.row
 9966    }
 9967}
 9968
 9969impl EditorSnapshot {
 9970    pub fn remote_selections_in_range<'a>(
 9971        &'a self,
 9972        range: &'a Range<Anchor>,
 9973        collaboration_hub: &dyn CollaborationHub,
 9974        cx: &'a AppContext,
 9975    ) -> impl 'a + Iterator<Item = RemoteSelection> {
 9976        let participant_names = collaboration_hub.user_names(cx);
 9977        let participant_indices = collaboration_hub.user_participant_indices(cx);
 9978        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
 9979        let collaborators_by_replica_id = collaborators_by_peer_id
 9980            .iter()
 9981            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
 9982            .collect::<HashMap<_, _>>();
 9983        self.buffer_snapshot
 9984            .remote_selections_in_range(range)
 9985            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
 9986                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
 9987                let participant_index = participant_indices.get(&collaborator.user_id).copied();
 9988                let user_name = participant_names.get(&collaborator.user_id).cloned();
 9989                Some(RemoteSelection {
 9990                    replica_id,
 9991                    selection,
 9992                    cursor_shape,
 9993                    line_mode,
 9994                    participant_index,
 9995                    peer_id: collaborator.peer_id,
 9996                    user_name,
 9997                })
 9998            })
 9999    }
10000
10001    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
10002        self.display_snapshot.buffer_snapshot.language_at(position)
10003    }
10004
10005    pub fn is_focused(&self) -> bool {
10006        self.is_focused
10007    }
10008
10009    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
10010        self.placeholder_text.as_ref()
10011    }
10012
10013    pub fn scroll_position(&self) -> gpui::Point<f32> {
10014        self.scroll_anchor.scroll_position(&self.display_snapshot)
10015    }
10016
10017    pub fn gutter_dimensions(
10018        &self,
10019        font_id: FontId,
10020        font_size: Pixels,
10021        em_width: Pixels,
10022        max_line_number_width: Pixels,
10023        cx: &AppContext,
10024    ) -> GutterDimensions {
10025        if !self.show_gutter {
10026            return GutterDimensions::default();
10027        }
10028        let descent = cx.text_system().descent(font_id, font_size);
10029
10030        let show_git_gutter = matches!(
10031            ProjectSettings::get_global(cx).git.git_gutter,
10032            Some(GitGutterSetting::TrackedFiles)
10033        );
10034        let gutter_settings = EditorSettings::get_global(cx).gutter;
10035
10036        let line_gutter_width = if gutter_settings.line_numbers {
10037            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
10038            let min_width_for_number_on_gutter = em_width * 4.0;
10039            max_line_number_width.max(min_width_for_number_on_gutter)
10040        } else {
10041            0.0.into()
10042        };
10043
10044        let left_padding = if gutter_settings.code_actions {
10045            em_width * 3.0
10046        } else if show_git_gutter && gutter_settings.line_numbers {
10047            em_width * 2.0
10048        } else if show_git_gutter || gutter_settings.line_numbers {
10049            em_width
10050        } else {
10051            px(0.)
10052        };
10053
10054        let right_padding = if gutter_settings.folds && gutter_settings.line_numbers {
10055            em_width * 4.0
10056        } else if gutter_settings.folds {
10057            em_width * 3.0
10058        } else if gutter_settings.line_numbers {
10059            em_width
10060        } else {
10061            px(0.)
10062        };
10063
10064        GutterDimensions {
10065            left_padding,
10066            right_padding,
10067            width: line_gutter_width + left_padding + right_padding,
10068            margin: -descent,
10069        }
10070    }
10071}
10072
10073impl Deref for EditorSnapshot {
10074    type Target = DisplaySnapshot;
10075
10076    fn deref(&self) -> &Self::Target {
10077        &self.display_snapshot
10078    }
10079}
10080
10081#[derive(Clone, Debug, PartialEq, Eq)]
10082pub enum EditorEvent {
10083    InputIgnored {
10084        text: Arc<str>,
10085    },
10086    InputHandled {
10087        utf16_range_to_replace: Option<Range<isize>>,
10088        text: Arc<str>,
10089    },
10090    ExcerptsAdded {
10091        buffer: Model<Buffer>,
10092        predecessor: ExcerptId,
10093        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
10094    },
10095    ExcerptsRemoved {
10096        ids: Vec<ExcerptId>,
10097    },
10098    BufferEdited,
10099    Edited,
10100    Reparsed,
10101    Focused,
10102    Blurred,
10103    DirtyChanged,
10104    Saved,
10105    TitleChanged,
10106    DiffBaseChanged,
10107    SelectionsChanged {
10108        local: bool,
10109    },
10110    ScrollPositionChanged {
10111        local: bool,
10112        autoscroll: bool,
10113    },
10114    Closed,
10115}
10116
10117impl EventEmitter<EditorEvent> for Editor {}
10118
10119impl FocusableView for Editor {
10120    fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
10121        self.focus_handle.clone()
10122    }
10123}
10124
10125impl Render for Editor {
10126    fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
10127        let settings = ThemeSettings::get_global(cx);
10128        let text_style = match self.mode {
10129            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
10130                color: cx.theme().colors().editor_foreground,
10131                font_family: settings.ui_font.family.clone(),
10132                font_features: settings.ui_font.features,
10133                font_size: rems(0.875).into(),
10134                font_weight: FontWeight::NORMAL,
10135                font_style: FontStyle::Normal,
10136                line_height: relative(settings.buffer_line_height.value()),
10137                background_color: None,
10138                underline: None,
10139                strikethrough: None,
10140                white_space: WhiteSpace::Normal,
10141            },
10142
10143            EditorMode::Full => TextStyle {
10144                color: cx.theme().colors().editor_foreground,
10145                font_family: settings.buffer_font.family.clone(),
10146                font_features: settings.buffer_font.features,
10147                font_size: settings.buffer_font_size(cx).into(),
10148                font_weight: FontWeight::NORMAL,
10149                font_style: FontStyle::Normal,
10150                line_height: relative(settings.buffer_line_height.value()),
10151                background_color: None,
10152                underline: None,
10153                strikethrough: None,
10154                white_space: WhiteSpace::Normal,
10155            },
10156        };
10157
10158        let background = match self.mode {
10159            EditorMode::SingleLine => cx.theme().system().transparent,
10160            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
10161            EditorMode::Full => cx.theme().colors().editor_background,
10162        };
10163
10164        EditorElement::new(
10165            cx.view(),
10166            EditorStyle {
10167                background,
10168                local_player: cx.theme().players().local(),
10169                text: text_style,
10170                scrollbar_width: px(12.),
10171                syntax: cx.theme().syntax().clone(),
10172                status: cx.theme().status().clone(),
10173                inlay_hints_style: HighlightStyle {
10174                    color: Some(cx.theme().status().hint),
10175                    ..HighlightStyle::default()
10176                },
10177                suggestions_style: HighlightStyle {
10178                    color: Some(cx.theme().status().predictive),
10179                    ..HighlightStyle::default()
10180                },
10181            },
10182        )
10183    }
10184}
10185
10186impl ViewInputHandler for Editor {
10187    fn text_for_range(
10188        &mut self,
10189        range_utf16: Range<usize>,
10190        cx: &mut ViewContext<Self>,
10191    ) -> Option<String> {
10192        Some(
10193            self.buffer
10194                .read(cx)
10195                .read(cx)
10196                .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
10197                .collect(),
10198        )
10199    }
10200
10201    fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
10202        // Prevent the IME menu from appearing when holding down an alphabetic key
10203        // while input is disabled.
10204        if !self.input_enabled {
10205            return None;
10206        }
10207
10208        let range = self.selections.newest::<OffsetUtf16>(cx).range();
10209        Some(range.start.0..range.end.0)
10210    }
10211
10212    fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
10213        let snapshot = self.buffer.read(cx).read(cx);
10214        let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
10215        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
10216    }
10217
10218    fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
10219        self.clear_highlights::<InputComposition>(cx);
10220        self.ime_transaction.take();
10221    }
10222
10223    fn replace_text_in_range(
10224        &mut self,
10225        range_utf16: Option<Range<usize>>,
10226        text: &str,
10227        cx: &mut ViewContext<Self>,
10228    ) {
10229        if !self.input_enabled {
10230            cx.emit(EditorEvent::InputIgnored { text: text.into() });
10231            return;
10232        }
10233
10234        self.transact(cx, |this, cx| {
10235            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
10236                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
10237                Some(this.selection_replacement_ranges(range_utf16, cx))
10238            } else {
10239                this.marked_text_ranges(cx)
10240            };
10241
10242            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
10243                let newest_selection_id = this.selections.newest_anchor().id;
10244                this.selections
10245                    .all::<OffsetUtf16>(cx)
10246                    .iter()
10247                    .zip(ranges_to_replace.iter())
10248                    .find_map(|(selection, range)| {
10249                        if selection.id == newest_selection_id {
10250                            Some(
10251                                (range.start.0 as isize - selection.head().0 as isize)
10252                                    ..(range.end.0 as isize - selection.head().0 as isize),
10253                            )
10254                        } else {
10255                            None
10256                        }
10257                    })
10258            });
10259
10260            cx.emit(EditorEvent::InputHandled {
10261                utf16_range_to_replace: range_to_replace,
10262                text: text.into(),
10263            });
10264
10265            if let Some(new_selected_ranges) = new_selected_ranges {
10266                this.change_selections(None, cx, |selections| {
10267                    selections.select_ranges(new_selected_ranges)
10268                });
10269                this.backspace(&Default::default(), cx);
10270            }
10271
10272            this.handle_input(text, cx);
10273        });
10274
10275        if let Some(transaction) = self.ime_transaction {
10276            self.buffer.update(cx, |buffer, cx| {
10277                buffer.group_until_transaction(transaction, cx);
10278            });
10279        }
10280
10281        self.unmark_text(cx);
10282    }
10283
10284    fn replace_and_mark_text_in_range(
10285        &mut self,
10286        range_utf16: Option<Range<usize>>,
10287        text: &str,
10288        new_selected_range_utf16: Option<Range<usize>>,
10289        cx: &mut ViewContext<Self>,
10290    ) {
10291        if !self.input_enabled {
10292            cx.emit(EditorEvent::InputIgnored { text: text.into() });
10293            return;
10294        }
10295
10296        let transaction = self.transact(cx, |this, cx| {
10297            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
10298                let snapshot = this.buffer.read(cx).read(cx);
10299                if let Some(relative_range_utf16) = range_utf16.as_ref() {
10300                    for marked_range in &mut marked_ranges {
10301                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
10302                        marked_range.start.0 += relative_range_utf16.start;
10303                        marked_range.start =
10304                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
10305                        marked_range.end =
10306                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
10307                    }
10308                }
10309                Some(marked_ranges)
10310            } else if let Some(range_utf16) = range_utf16 {
10311                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
10312                Some(this.selection_replacement_ranges(range_utf16, cx))
10313            } else {
10314                None
10315            };
10316
10317            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
10318                let newest_selection_id = this.selections.newest_anchor().id;
10319                this.selections
10320                    .all::<OffsetUtf16>(cx)
10321                    .iter()
10322                    .zip(ranges_to_replace.iter())
10323                    .find_map(|(selection, range)| {
10324                        if selection.id == newest_selection_id {
10325                            Some(
10326                                (range.start.0 as isize - selection.head().0 as isize)
10327                                    ..(range.end.0 as isize - selection.head().0 as isize),
10328                            )
10329                        } else {
10330                            None
10331                        }
10332                    })
10333            });
10334
10335            cx.emit(EditorEvent::InputHandled {
10336                utf16_range_to_replace: range_to_replace,
10337                text: text.into(),
10338            });
10339
10340            if let Some(ranges) = ranges_to_replace {
10341                this.change_selections(None, cx, |s| s.select_ranges(ranges));
10342            }
10343
10344            let marked_ranges = {
10345                let snapshot = this.buffer.read(cx).read(cx);
10346                this.selections
10347                    .disjoint_anchors()
10348                    .iter()
10349                    .map(|selection| {
10350                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
10351                    })
10352                    .collect::<Vec<_>>()
10353            };
10354
10355            if text.is_empty() {
10356                this.unmark_text(cx);
10357            } else {
10358                this.highlight_text::<InputComposition>(
10359                    marked_ranges.clone(),
10360                    HighlightStyle {
10361                        underline: Some(UnderlineStyle {
10362                            thickness: px(1.),
10363                            color: None,
10364                            wavy: false,
10365                        }),
10366                        ..Default::default()
10367                    },
10368                    cx,
10369                );
10370            }
10371
10372            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
10373            let use_autoclose = this.use_autoclose;
10374            this.set_use_autoclose(false);
10375            this.handle_input(text, cx);
10376            this.set_use_autoclose(use_autoclose);
10377
10378            if let Some(new_selected_range) = new_selected_range_utf16 {
10379                let snapshot = this.buffer.read(cx).read(cx);
10380                let new_selected_ranges = marked_ranges
10381                    .into_iter()
10382                    .map(|marked_range| {
10383                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
10384                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
10385                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
10386                        snapshot.clip_offset_utf16(new_start, Bias::Left)
10387                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
10388                    })
10389                    .collect::<Vec<_>>();
10390
10391                drop(snapshot);
10392                this.change_selections(None, cx, |selections| {
10393                    selections.select_ranges(new_selected_ranges)
10394                });
10395            }
10396        });
10397
10398        self.ime_transaction = self.ime_transaction.or(transaction);
10399        if let Some(transaction) = self.ime_transaction {
10400            self.buffer.update(cx, |buffer, cx| {
10401                buffer.group_until_transaction(transaction, cx);
10402            });
10403        }
10404
10405        if self.text_highlights::<InputComposition>(cx).is_none() {
10406            self.ime_transaction.take();
10407        }
10408    }
10409
10410    fn bounds_for_range(
10411        &mut self,
10412        range_utf16: Range<usize>,
10413        element_bounds: gpui::Bounds<Pixels>,
10414        cx: &mut ViewContext<Self>,
10415    ) -> Option<gpui::Bounds<Pixels>> {
10416        let text_layout_details = self.text_layout_details(cx);
10417        let style = &text_layout_details.editor_style;
10418        let font_id = cx.text_system().resolve_font(&style.text.font());
10419        let font_size = style.text.font_size.to_pixels(cx.rem_size());
10420        let line_height = style.text.line_height_in_pixels(cx.rem_size());
10421        let em_width = cx
10422            .text_system()
10423            .typographic_bounds(font_id, font_size, 'm')
10424            .unwrap()
10425            .size
10426            .width;
10427
10428        let snapshot = self.snapshot(cx);
10429        let scroll_position = snapshot.scroll_position();
10430        let scroll_left = scroll_position.x * em_width;
10431
10432        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
10433        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
10434            + self.gutter_width;
10435        let y = line_height * (start.row() as f32 - scroll_position.y);
10436
10437        Some(Bounds {
10438            origin: element_bounds.origin + point(x, y),
10439            size: size(em_width, line_height),
10440        })
10441    }
10442}
10443
10444trait SelectionExt {
10445    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
10446    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
10447    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
10448    fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
10449        -> Range<u32>;
10450}
10451
10452impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
10453    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
10454        let start = self.start.to_point(buffer);
10455        let end = self.end.to_point(buffer);
10456        if self.reversed {
10457            end..start
10458        } else {
10459            start..end
10460        }
10461    }
10462
10463    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
10464        let start = self.start.to_offset(buffer);
10465        let end = self.end.to_offset(buffer);
10466        if self.reversed {
10467            end..start
10468        } else {
10469            start..end
10470        }
10471    }
10472
10473    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
10474        let start = self
10475            .start
10476            .to_point(&map.buffer_snapshot)
10477            .to_display_point(map);
10478        let end = self
10479            .end
10480            .to_point(&map.buffer_snapshot)
10481            .to_display_point(map);
10482        if self.reversed {
10483            end..start
10484        } else {
10485            start..end
10486        }
10487    }
10488
10489    fn spanned_rows(
10490        &self,
10491        include_end_if_at_line_start: bool,
10492        map: &DisplaySnapshot,
10493    ) -> Range<u32> {
10494        let start = self.start.to_point(&map.buffer_snapshot);
10495        let mut end = self.end.to_point(&map.buffer_snapshot);
10496        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
10497            end.row -= 1;
10498        }
10499
10500        let buffer_start = map.prev_line_boundary(start).0;
10501        let buffer_end = map.next_line_boundary(end).0;
10502        buffer_start.row..buffer_end.row + 1
10503    }
10504}
10505
10506impl<T: InvalidationRegion> InvalidationStack<T> {
10507    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
10508    where
10509        S: Clone + ToOffset,
10510    {
10511        while let Some(region) = self.last() {
10512            let all_selections_inside_invalidation_ranges =
10513                if selections.len() == region.ranges().len() {
10514                    selections
10515                        .iter()
10516                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
10517                        .all(|(selection, invalidation_range)| {
10518                            let head = selection.head().to_offset(buffer);
10519                            invalidation_range.start <= head && invalidation_range.end >= head
10520                        })
10521                } else {
10522                    false
10523                };
10524
10525            if all_selections_inside_invalidation_ranges {
10526                break;
10527            } else {
10528                self.pop();
10529            }
10530        }
10531    }
10532}
10533
10534impl<T> Default for InvalidationStack<T> {
10535    fn default() -> Self {
10536        Self(Default::default())
10537    }
10538}
10539
10540impl<T> Deref for InvalidationStack<T> {
10541    type Target = Vec<T>;
10542
10543    fn deref(&self) -> &Self::Target {
10544        &self.0
10545    }
10546}
10547
10548impl<T> DerefMut for InvalidationStack<T> {
10549    fn deref_mut(&mut self) -> &mut Self::Target {
10550        &mut self.0
10551    }
10552}
10553
10554impl InvalidationRegion for SnippetState {
10555    fn ranges(&self) -> &[Range<Anchor>] {
10556        &self.ranges[self.active_index]
10557    }
10558}
10559
10560pub fn diagnostic_block_renderer(diagnostic: Diagnostic, _is_valid: bool) -> RenderBlock {
10561    let (text_without_backticks, code_ranges) = highlight_diagnostic_message(&diagnostic);
10562
10563    Arc::new(move |cx: &mut BlockContext| {
10564        let group_id: SharedString = cx.block_id.to_string().into();
10565
10566        let mut text_style = cx.text_style().clone();
10567        text_style.color = diagnostic_style(diagnostic.severity, true, cx.theme().status());
10568
10569        h_flex()
10570            .id(cx.block_id)
10571            .group(group_id.clone())
10572            .relative()
10573            .size_full()
10574            .pl(cx.gutter_dimensions.width)
10575            .w(cx.max_width + cx.gutter_dimensions.width)
10576            .child(
10577                div()
10578                    .flex()
10579                    .w(cx.anchor_x - cx.gutter_dimensions.width)
10580                    .flex_shrink(),
10581            )
10582            .child(div().flex().flex_shrink_0().child(
10583                StyledText::new(text_without_backticks.clone()).with_highlights(
10584                    &text_style,
10585                    code_ranges.iter().map(|range| {
10586                        (
10587                            range.clone(),
10588                            HighlightStyle {
10589                                font_weight: Some(FontWeight::BOLD),
10590                                ..Default::default()
10591                            },
10592                        )
10593                    }),
10594                ),
10595            ))
10596            .child(
10597                IconButton::new(("copy-block", cx.block_id), IconName::Copy)
10598                    .icon_color(Color::Muted)
10599                    .size(ButtonSize::Compact)
10600                    .style(ButtonStyle::Transparent)
10601                    .visible_on_hover(group_id)
10602                    .on_click({
10603                        let message = diagnostic.message.clone();
10604                        move |_click, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone()))
10605                    })
10606                    .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
10607            )
10608            .into_any_element()
10609    })
10610}
10611
10612pub fn highlight_diagnostic_message(diagnostic: &Diagnostic) -> (SharedString, Vec<Range<usize>>) {
10613    let mut text_without_backticks = String::new();
10614    let mut code_ranges = Vec::new();
10615
10616    if let Some(source) = &diagnostic.source {
10617        text_without_backticks.push_str(&source);
10618        code_ranges.push(0..source.len());
10619        text_without_backticks.push_str(": ");
10620    }
10621
10622    let mut prev_offset = 0;
10623    let mut in_code_block = false;
10624    for (ix, _) in diagnostic
10625        .message
10626        .match_indices('`')
10627        .chain([(diagnostic.message.len(), "")])
10628    {
10629        let prev_len = text_without_backticks.len();
10630        text_without_backticks.push_str(&diagnostic.message[prev_offset..ix]);
10631        prev_offset = ix + 1;
10632        if in_code_block {
10633            code_ranges.push(prev_len..text_without_backticks.len());
10634            in_code_block = false;
10635        } else {
10636            in_code_block = true;
10637        }
10638    }
10639
10640    (text_without_backticks.into(), code_ranges)
10641}
10642
10643fn diagnostic_style(severity: DiagnosticSeverity, valid: bool, colors: &StatusColors) -> Hsla {
10644    match (severity, valid) {
10645        (DiagnosticSeverity::ERROR, true) => colors.error,
10646        (DiagnosticSeverity::ERROR, false) => colors.error,
10647        (DiagnosticSeverity::WARNING, true) => colors.warning,
10648        (DiagnosticSeverity::WARNING, false) => colors.warning,
10649        (DiagnosticSeverity::INFORMATION, true) => colors.info,
10650        (DiagnosticSeverity::INFORMATION, false) => colors.info,
10651        (DiagnosticSeverity::HINT, true) => colors.info,
10652        (DiagnosticSeverity::HINT, false) => colors.info,
10653        _ => colors.ignored,
10654    }
10655}
10656
10657pub fn styled_runs_for_code_label<'a>(
10658    label: &'a CodeLabel,
10659    syntax_theme: &'a theme::SyntaxTheme,
10660) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
10661    let fade_out = HighlightStyle {
10662        fade_out: Some(0.35),
10663        ..Default::default()
10664    };
10665
10666    let mut prev_end = label.filter_range.end;
10667    label
10668        .runs
10669        .iter()
10670        .enumerate()
10671        .flat_map(move |(ix, (range, highlight_id))| {
10672            let style = if let Some(style) = highlight_id.style(syntax_theme) {
10673                style
10674            } else {
10675                return Default::default();
10676            };
10677            let mut muted_style = style;
10678            muted_style.highlight(fade_out);
10679
10680            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
10681            if range.start >= label.filter_range.end {
10682                if range.start > prev_end {
10683                    runs.push((prev_end..range.start, fade_out));
10684                }
10685                runs.push((range.clone(), muted_style));
10686            } else if range.end <= label.filter_range.end {
10687                runs.push((range.clone(), style));
10688            } else {
10689                runs.push((range.start..label.filter_range.end, style));
10690                runs.push((label.filter_range.end..range.end, muted_style));
10691            }
10692            prev_end = cmp::max(prev_end, range.end);
10693
10694            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
10695                runs.push((prev_end..label.text.len(), fade_out));
10696            }
10697
10698            runs
10699        })
10700}
10701
10702pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
10703    let mut index = 0;
10704    let mut codepoints = text.char_indices().peekable();
10705
10706    std::iter::from_fn(move || {
10707        let start_index = index;
10708        while let Some((new_index, codepoint)) = codepoints.next() {
10709            index = new_index + codepoint.len_utf8();
10710            let current_upper = codepoint.is_uppercase();
10711            let next_upper = codepoints
10712                .peek()
10713                .map(|(_, c)| c.is_uppercase())
10714                .unwrap_or(false);
10715
10716            if !current_upper && next_upper {
10717                return Some(&text[start_index..index]);
10718            }
10719        }
10720
10721        index = text.len();
10722        if start_index < text.len() {
10723            return Some(&text[start_index..]);
10724        }
10725        None
10726    })
10727    .flat_map(|word| word.split_inclusive('_'))
10728    .flat_map(|word| word.split_inclusive('-'))
10729}
10730
10731trait RangeToAnchorExt {
10732    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
10733}
10734
10735impl<T: ToOffset> RangeToAnchorExt for Range<T> {
10736    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
10737        snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
10738    }
10739}