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//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, LanguageRegistry, OffsetRangeExt, OutlineItem, Point, Runnable,
  121    RunnableRange, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  122    WordsQuery,
  123    language_settings::{
  124        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  125        language_settings,
  126    },
  127    point_from_lsp, point_to_lsp, text_diff_with_options,
  128};
  129use linked_editing_ranges::refresh_linked_ranges;
  130use lsp::{
  131    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  132    LanguageServerId,
  133};
  134use lsp_colors::LspColorData;
  135use markdown::Markdown;
  136use mouse_context_menu::MouseContextMenu;
  137use movement::TextLayoutDetails;
  138use multi_buffer::{
  139    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  140};
  141use parking_lot::Mutex;
  142use persistence::DB;
  143use project::{
  144    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  145    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  146    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  147    ProjectPath, ProjectTransaction, TaskSourceKind,
  148    debugger::{
  149        breakpoint_store::{
  150            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  151            BreakpointStore, BreakpointStoreEvent,
  152        },
  153        session::{Session, SessionEvent},
  154    },
  155    git_store::GitStoreEvent,
  156    lsp_store::{
  157        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  158        OpenLspBufferHandle,
  159    },
  160    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  161};
  162use rand::seq::SliceRandom;
  163use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  164use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  165use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  166use serde::{Deserialize, Serialize};
  167use settings::{
  168    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  169    update_settings_file,
  170};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    inlays::{
  212        InlineValueCache,
  213        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  214    },
  215    scroll::{ScrollOffset, ScrollPixelOffset},
  216    selections_collection::resolve_selections_wrapping_blocks,
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    Closed,
  257}
  258
  259impl ReportEditorEvent {
  260    pub fn event_type(&self) -> &'static str {
  261        match self {
  262            Self::Saved { .. } => "Editor Saved",
  263            Self::EditorOpened => "Editor Opened",
  264            Self::Closed => "Editor Closed",
  265        }
  266    }
  267}
  268
  269pub enum ActiveDebugLine {}
  270pub enum DebugStackFrameLine {}
  271enum DocumentHighlightRead {}
  272enum DocumentHighlightWrite {}
  273enum InputComposition {}
  274pub enum PendingInput {}
  275enum SelectedTextHighlight {}
  276
  277pub enum ConflictsOuter {}
  278pub enum ConflictsOurs {}
  279pub enum ConflictsTheirs {}
  280pub enum ConflictsOursMarker {}
  281pub enum ConflictsTheirsMarker {}
  282
  283#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  284pub enum Navigated {
  285    Yes,
  286    No,
  287}
  288
  289impl Navigated {
  290    pub fn from_bool(yes: bool) -> Navigated {
  291        if yes { Navigated::Yes } else { Navigated::No }
  292    }
  293}
  294
  295#[derive(Debug, Clone, PartialEq, Eq)]
  296enum DisplayDiffHunk {
  297    Folded {
  298        display_row: DisplayRow,
  299    },
  300    Unfolded {
  301        is_created_file: bool,
  302        diff_base_byte_range: Range<usize>,
  303        display_row_range: Range<DisplayRow>,
  304        multi_buffer_range: Range<Anchor>,
  305        status: DiffHunkStatus,
  306    },
  307}
  308
  309pub enum HideMouseCursorOrigin {
  310    TypingAction,
  311    MovementAction,
  312}
  313
  314pub fn init(cx: &mut App) {
  315    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  316
  317    workspace::register_project_item::<Editor>(cx);
  318    workspace::FollowableViewRegistry::register::<Editor>(cx);
  319    workspace::register_serializable_item::<Editor>(cx);
  320
  321    cx.observe_new(
  322        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  323            workspace.register_action(Editor::new_file);
  324            workspace.register_action(Editor::new_file_split);
  325            workspace.register_action(Editor::new_file_vertical);
  326            workspace.register_action(Editor::new_file_horizontal);
  327            workspace.register_action(Editor::cancel_language_server_work);
  328            workspace.register_action(Editor::toggle_focus);
  329        },
  330    )
  331    .detach();
  332
  333    cx.on_action(move |_: &workspace::NewFile, cx| {
  334        let app_state = workspace::AppState::global(cx);
  335        if let Some(app_state) = app_state.upgrade() {
  336            workspace::open_new(
  337                Default::default(),
  338                app_state,
  339                cx,
  340                |workspace, window, cx| {
  341                    Editor::new_file(workspace, &Default::default(), window, cx)
  342                },
  343            )
  344            .detach();
  345        }
  346    });
  347    cx.on_action(move |_: &workspace::NewWindow, cx| {
  348        let app_state = workspace::AppState::global(cx);
  349        if let Some(app_state) = app_state.upgrade() {
  350            workspace::open_new(
  351                Default::default(),
  352                app_state,
  353                cx,
  354                |workspace, window, cx| {
  355                    cx.activate(true);
  356                    Editor::new_file(workspace, &Default::default(), window, cx)
  357                },
  358            )
  359            .detach();
  360        }
  361    });
  362}
  363
  364pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  365    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  366}
  367
  368pub trait DiagnosticRenderer {
  369    fn render_group(
  370        &self,
  371        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  372        buffer_id: BufferId,
  373        snapshot: EditorSnapshot,
  374        editor: WeakEntity<Editor>,
  375        language_registry: Option<Arc<LanguageRegistry>>,
  376        cx: &mut App,
  377    ) -> Vec<BlockProperties<Anchor>>;
  378
  379    fn render_hover(
  380        &self,
  381        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  382        range: Range<Point>,
  383        buffer_id: BufferId,
  384        language_registry: Option<Arc<LanguageRegistry>>,
  385        cx: &mut App,
  386    ) -> Option<Entity<markdown::Markdown>>;
  387
  388    fn open_link(
  389        &self,
  390        editor: &mut Editor,
  391        link: SharedString,
  392        window: &mut Window,
  393        cx: &mut Context<Editor>,
  394    );
  395}
  396
  397pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  398
  399impl GlobalDiagnosticRenderer {
  400    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  401        cx.try_global::<Self>().map(|g| g.0.clone())
  402    }
  403}
  404
  405impl gpui::Global for GlobalDiagnosticRenderer {}
  406pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  408}
  409
  410pub struct SearchWithinRange;
  411
  412trait InvalidationRegion {
  413    fn ranges(&self) -> &[Range<Anchor>];
  414}
  415
  416#[derive(Clone, Debug, PartialEq)]
  417pub enum SelectPhase {
  418    Begin {
  419        position: DisplayPoint,
  420        add: bool,
  421        click_count: usize,
  422    },
  423    BeginColumnar {
  424        position: DisplayPoint,
  425        reset: bool,
  426        mode: ColumnarMode,
  427        goal_column: u32,
  428    },
  429    Extend {
  430        position: DisplayPoint,
  431        click_count: usize,
  432    },
  433    Update {
  434        position: DisplayPoint,
  435        goal_column: u32,
  436        scroll_delta: gpui::Point<f32>,
  437    },
  438    End,
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum ColumnarMode {
  443    FromMouse,
  444    FromSelection,
  445}
  446
  447#[derive(Clone, Debug)]
  448pub enum SelectMode {
  449    Character,
  450    Word(Range<Anchor>),
  451    Line(Range<Anchor>),
  452    All,
  453}
  454
  455#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  456pub enum SizingBehavior {
  457    /// The editor will layout itself using `size_full` and will include the vertical
  458    /// scroll margin as requested by user settings.
  459    #[default]
  460    Default,
  461    /// The editor will layout itself using `size_full`, but will not have any
  462    /// vertical overscroll.
  463    ExcludeOverscrollMargin,
  464    /// The editor will request a vertical size according to its content and will be
  465    /// layouted without a vertical scroll margin.
  466    SizeByContent,
  467}
  468
  469#[derive(Clone, PartialEq, Eq, Debug)]
  470pub enum EditorMode {
  471    SingleLine,
  472    AutoHeight {
  473        min_lines: usize,
  474        max_lines: Option<usize>,
  475    },
  476    Full {
  477        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  478        scale_ui_elements_with_buffer_font_size: bool,
  479        /// When set to `true`, the editor will render a background for the active line.
  480        show_active_line_background: bool,
  481        /// Determines the sizing behavior for this editor
  482        sizing_behavior: SizingBehavior,
  483    },
  484    Minimap {
  485        parent: WeakEntity<Editor>,
  486    },
  487}
  488
  489impl EditorMode {
  490    pub fn full() -> Self {
  491        Self::Full {
  492            scale_ui_elements_with_buffer_font_size: true,
  493            show_active_line_background: true,
  494            sizing_behavior: SizingBehavior::Default,
  495        }
  496    }
  497
  498    #[inline]
  499    pub fn is_full(&self) -> bool {
  500        matches!(self, Self::Full { .. })
  501    }
  502
  503    #[inline]
  504    pub fn is_single_line(&self) -> bool {
  505        matches!(self, Self::SingleLine { .. })
  506    }
  507
  508    #[inline]
  509    fn is_minimap(&self) -> bool {
  510        matches!(self, Self::Minimap { .. })
  511    }
  512}
  513
  514#[derive(Copy, Clone, Debug)]
  515pub enum SoftWrap {
  516    /// Prefer not to wrap at all.
  517    ///
  518    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  519    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  520    GitDiff,
  521    /// Prefer a single line generally, unless an overly long line is encountered.
  522    None,
  523    /// Soft wrap lines that exceed the editor width.
  524    EditorWidth,
  525    /// Soft wrap lines at the preferred line length.
  526    Column(u32),
  527    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  528    Bounded(u32),
  529}
  530
  531#[derive(Clone)]
  532pub struct EditorStyle {
  533    pub background: Hsla,
  534    pub border: Hsla,
  535    pub local_player: PlayerColor,
  536    pub text: TextStyle,
  537    pub scrollbar_width: Pixels,
  538    pub syntax: Arc<SyntaxTheme>,
  539    pub status: StatusColors,
  540    pub inlay_hints_style: HighlightStyle,
  541    pub edit_prediction_styles: EditPredictionStyles,
  542    pub unnecessary_code_fade: f32,
  543    pub show_underlines: bool,
  544}
  545
  546impl Default for EditorStyle {
  547    fn default() -> Self {
  548        Self {
  549            background: Hsla::default(),
  550            border: Hsla::default(),
  551            local_player: PlayerColor::default(),
  552            text: TextStyle::default(),
  553            scrollbar_width: Pixels::default(),
  554            syntax: Default::default(),
  555            // HACK: Status colors don't have a real default.
  556            // We should look into removing the status colors from the editor
  557            // style and retrieve them directly from the theme.
  558            status: StatusColors::dark(),
  559            inlay_hints_style: HighlightStyle::default(),
  560            edit_prediction_styles: EditPredictionStyles {
  561                insertion: HighlightStyle::default(),
  562                whitespace: HighlightStyle::default(),
  563            },
  564            unnecessary_code_fade: Default::default(),
  565            show_underlines: true,
  566        }
  567    }
  568}
  569
  570pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  571    let show_background = language_settings::language_settings(None, None, cx)
  572        .inlay_hints
  573        .show_background;
  574
  575    let mut style = cx.theme().syntax().get("hint");
  576
  577    if style.color.is_none() {
  578        style.color = Some(cx.theme().status().hint);
  579    }
  580
  581    if !show_background {
  582        style.background_color = None;
  583        return style;
  584    }
  585
  586    if style.background_color.is_none() {
  587        style.background_color = Some(cx.theme().status().hint_background);
  588    }
  589
  590    style
  591}
  592
  593pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  594    EditPredictionStyles {
  595        insertion: HighlightStyle {
  596            color: Some(cx.theme().status().predictive),
  597            ..HighlightStyle::default()
  598        },
  599        whitespace: HighlightStyle {
  600            background_color: Some(cx.theme().status().created_background),
  601            ..HighlightStyle::default()
  602        },
  603    }
  604}
  605
  606type CompletionId = usize;
  607
  608pub(crate) enum EditDisplayMode {
  609    TabAccept,
  610    DiffPopover,
  611    Inline,
  612}
  613
  614enum EditPrediction {
  615    Edit {
  616        edits: Vec<(Range<Anchor>, Arc<str>)>,
  617        edit_preview: Option<EditPreview>,
  618        display_mode: EditDisplayMode,
  619        snapshot: BufferSnapshot,
  620    },
  621    /// Move to a specific location in the active editor
  622    MoveWithin {
  623        target: Anchor,
  624        snapshot: BufferSnapshot,
  625    },
  626    /// Move to a specific location in a different editor (not the active one)
  627    MoveOutside {
  628        target: language::Anchor,
  629        snapshot: BufferSnapshot,
  630    },
  631}
  632
  633struct EditPredictionState {
  634    inlay_ids: Vec<InlayId>,
  635    completion: EditPrediction,
  636    completion_id: Option<SharedString>,
  637    invalidation_range: Option<Range<Anchor>>,
  638}
  639
  640enum EditPredictionSettings {
  641    Disabled,
  642    Enabled {
  643        show_in_menu: bool,
  644        preview_requires_modifier: bool,
  645    },
  646}
  647
  648enum EditPredictionHighlight {}
  649
  650#[derive(Debug, Clone)]
  651struct InlineDiagnostic {
  652    message: SharedString,
  653    group_id: usize,
  654    is_primary: bool,
  655    start: Point,
  656    severity: lsp::DiagnosticSeverity,
  657}
  658
  659pub enum MenuEditPredictionsPolicy {
  660    Never,
  661    ByProvider,
  662}
  663
  664pub enum EditPredictionPreview {
  665    /// Modifier is not pressed
  666    Inactive { released_too_fast: bool },
  667    /// Modifier pressed
  668    Active {
  669        since: Instant,
  670        previous_scroll_position: Option<ScrollAnchor>,
  671    },
  672}
  673
  674impl EditPredictionPreview {
  675    pub fn released_too_fast(&self) -> bool {
  676        match self {
  677            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  678            EditPredictionPreview::Active { .. } => false,
  679        }
  680    }
  681
  682    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  683        if let EditPredictionPreview::Active {
  684            previous_scroll_position,
  685            ..
  686        } = self
  687        {
  688            *previous_scroll_position = scroll_position;
  689        }
  690    }
  691}
  692
  693pub struct ContextMenuOptions {
  694    pub min_entries_visible: usize,
  695    pub max_entries_visible: usize,
  696    pub placement: Option<ContextMenuPlacement>,
  697}
  698
  699#[derive(Debug, Clone, PartialEq, Eq)]
  700pub enum ContextMenuPlacement {
  701    Above,
  702    Below,
  703}
  704
  705#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  706struct EditorActionId(usize);
  707
  708impl EditorActionId {
  709    pub fn post_inc(&mut self) -> Self {
  710        let answer = self.0;
  711
  712        *self = Self(answer + 1);
  713
  714        Self(answer)
  715    }
  716}
  717
  718// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  719// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  720
  721type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  722type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  723
  724#[derive(Default)]
  725struct ScrollbarMarkerState {
  726    scrollbar_size: Size<Pixels>,
  727    dirty: bool,
  728    markers: Arc<[PaintQuad]>,
  729    pending_refresh: Option<Task<Result<()>>>,
  730}
  731
  732impl ScrollbarMarkerState {
  733    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  734        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  735    }
  736}
  737
  738#[derive(Clone, Copy, PartialEq, Eq)]
  739pub enum MinimapVisibility {
  740    Disabled,
  741    Enabled {
  742        /// The configuration currently present in the users settings.
  743        setting_configuration: bool,
  744        /// Whether to override the currently set visibility from the users setting.
  745        toggle_override: bool,
  746    },
  747}
  748
  749impl MinimapVisibility {
  750    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  751        if mode.is_full() {
  752            Self::Enabled {
  753                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  754                toggle_override: false,
  755            }
  756        } else {
  757            Self::Disabled
  758        }
  759    }
  760
  761    fn hidden(&self) -> Self {
  762        match *self {
  763            Self::Enabled {
  764                setting_configuration,
  765                ..
  766            } => Self::Enabled {
  767                setting_configuration,
  768                toggle_override: setting_configuration,
  769            },
  770            Self::Disabled => Self::Disabled,
  771        }
  772    }
  773
  774    fn disabled(&self) -> bool {
  775        matches!(*self, Self::Disabled)
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  813pub enum BufferSerialization {
  814    All,
  815    NonDirtyBuffers,
  816}
  817
  818impl BufferSerialization {
  819    fn new(restore_unsaved_buffers: bool) -> Self {
  820        if restore_unsaved_buffers {
  821            Self::All
  822        } else {
  823            Self::NonDirtyBuffers
  824        }
  825    }
  826}
  827
  828#[derive(Clone, Debug)]
  829struct RunnableTasks {
  830    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  831    offset: multi_buffer::Anchor,
  832    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  833    column: u32,
  834    // Values of all named captures, including those starting with '_'
  835    extra_variables: HashMap<String, String>,
  836    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  837    context_range: Range<BufferOffset>,
  838}
  839
  840impl RunnableTasks {
  841    fn resolve<'a>(
  842        &'a self,
  843        cx: &'a task::TaskContext,
  844    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  845        self.templates.iter().filter_map(|(kind, template)| {
  846            template
  847                .resolve_task(&kind.to_id_base(), cx)
  848                .map(|task| (kind.clone(), task))
  849        })
  850    }
  851}
  852
  853#[derive(Clone)]
  854pub struct ResolvedTasks {
  855    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  856    position: Anchor,
  857}
  858
  859#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  860struct BufferOffset(usize);
  861
  862/// Addons allow storing per-editor state in other crates (e.g. Vim)
  863pub trait Addon: 'static {
  864    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  865
  866    fn render_buffer_header_controls(
  867        &self,
  868        _: &ExcerptInfo,
  869        _: &Window,
  870        _: &App,
  871    ) -> Option<AnyElement> {
  872        None
  873    }
  874
  875    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    next_inlay_id: usize,
 1126    next_color_inlay_id: usize,
 1127    _subscriptions: Vec<Subscription>,
 1128    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1129    gutter_dimensions: GutterDimensions,
 1130    style: Option<EditorStyle>,
 1131    text_style_refinement: Option<TextStyleRefinement>,
 1132    next_editor_action_id: EditorActionId,
 1133    editor_actions: Rc<
 1134        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1135    >,
 1136    use_autoclose: bool,
 1137    use_auto_surround: bool,
 1138    auto_replace_emoji_shortcode: bool,
 1139    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1140    show_git_blame_gutter: bool,
 1141    show_git_blame_inline: bool,
 1142    show_git_blame_inline_delay_task: Option<Task<()>>,
 1143    git_blame_inline_enabled: bool,
 1144    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1145    buffer_serialization: Option<BufferSerialization>,
 1146    show_selection_menu: Option<bool>,
 1147    blame: Option<Entity<GitBlame>>,
 1148    blame_subscription: Option<Subscription>,
 1149    custom_context_menu: Option<
 1150        Box<
 1151            dyn 'static
 1152                + Fn(
 1153                    &mut Self,
 1154                    DisplayPoint,
 1155                    &mut Window,
 1156                    &mut Context<Self>,
 1157                ) -> Option<Entity<ui::ContextMenu>>,
 1158        >,
 1159    >,
 1160    last_bounds: Option<Bounds<Pixels>>,
 1161    last_position_map: Option<Rc<PositionMap>>,
 1162    expect_bounds_change: Option<Bounds<Pixels>>,
 1163    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1164    tasks_update_task: Option<Task<()>>,
 1165    breakpoint_store: Option<Entity<BreakpointStore>>,
 1166    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1167    hovered_diff_hunk_row: Option<DisplayRow>,
 1168    pull_diagnostics_task: Task<()>,
 1169    in_project_search: bool,
 1170    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1171    breadcrumb_header: Option<String>,
 1172    focused_block: Option<FocusedBlock>,
 1173    next_scroll_position: NextScrollCursorCenterTopBottom,
 1174    addons: HashMap<TypeId, Box<dyn Addon>>,
 1175    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1176    load_diff_task: Option<Shared<Task<()>>>,
 1177    /// Whether we are temporarily displaying a diff other than git's
 1178    temporary_diff_override: bool,
 1179    selection_mark_mode: bool,
 1180    toggle_fold_multiple_buffers: Task<()>,
 1181    _scroll_cursor_center_top_bottom_task: Task<()>,
 1182    serialize_selections: Task<()>,
 1183    serialize_folds: Task<()>,
 1184    mouse_cursor_hidden: bool,
 1185    minimap: Option<Entity<Self>>,
 1186    hide_mouse_mode: HideMouseMode,
 1187    pub change_list: ChangeList,
 1188    inline_value_cache: InlineValueCache,
 1189
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    post_scroll_update: Task<()>,
 1193    refresh_colors_task: Task<()>,
 1194    inlay_hints: Option<LspInlayHintData>,
 1195    folding_newlines: Task<()>,
 1196    select_next_is_case_sensitive: Option<bool>,
 1197    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1198}
 1199
 1200fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1201    if debounce_ms > 0 {
 1202        Some(Duration::from_millis(debounce_ms))
 1203    } else {
 1204        None
 1205    }
 1206}
 1207
 1208#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1209enum NextScrollCursorCenterTopBottom {
 1210    #[default]
 1211    Center,
 1212    Top,
 1213    Bottom,
 1214}
 1215
 1216impl NextScrollCursorCenterTopBottom {
 1217    fn next(&self) -> Self {
 1218        match self {
 1219            Self::Center => Self::Top,
 1220            Self::Top => Self::Bottom,
 1221            Self::Bottom => Self::Center,
 1222        }
 1223    }
 1224}
 1225
 1226#[derive(Clone)]
 1227pub struct EditorSnapshot {
 1228    pub mode: EditorMode,
 1229    show_gutter: bool,
 1230    show_line_numbers: Option<bool>,
 1231    show_git_diff_gutter: Option<bool>,
 1232    show_code_actions: Option<bool>,
 1233    show_runnables: Option<bool>,
 1234    show_breakpoints: Option<bool>,
 1235    git_blame_gutter_max_author_length: Option<usize>,
 1236    pub display_snapshot: DisplaySnapshot,
 1237    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1238    is_focused: bool,
 1239    scroll_anchor: ScrollAnchor,
 1240    ongoing_scroll: OngoingScroll,
 1241    current_line_highlight: CurrentLineHighlight,
 1242    gutter_hovered: bool,
 1243}
 1244
 1245#[derive(Default, Debug, Clone, Copy)]
 1246pub struct GutterDimensions {
 1247    pub left_padding: Pixels,
 1248    pub right_padding: Pixels,
 1249    pub width: Pixels,
 1250    pub margin: Pixels,
 1251    pub git_blame_entries_width: Option<Pixels>,
 1252}
 1253
 1254impl GutterDimensions {
 1255    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1256        Self {
 1257            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1258            ..Default::default()
 1259        }
 1260    }
 1261
 1262    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1263        -cx.text_system().descent(font_id, font_size)
 1264    }
 1265    /// The full width of the space taken up by the gutter.
 1266    pub fn full_width(&self) -> Pixels {
 1267        self.margin + self.width
 1268    }
 1269
 1270    /// The width of the space reserved for the fold indicators,
 1271    /// use alongside 'justify_end' and `gutter_width` to
 1272    /// right align content with the line numbers
 1273    pub fn fold_area_width(&self) -> Pixels {
 1274        self.margin + self.right_padding
 1275    }
 1276}
 1277
 1278struct CharacterDimensions {
 1279    em_width: Pixels,
 1280    em_advance: Pixels,
 1281    line_height: Pixels,
 1282}
 1283
 1284#[derive(Debug)]
 1285pub struct RemoteSelection {
 1286    pub replica_id: ReplicaId,
 1287    pub selection: Selection<Anchor>,
 1288    pub cursor_shape: CursorShape,
 1289    pub collaborator_id: CollaboratorId,
 1290    pub line_mode: bool,
 1291    pub user_name: Option<SharedString>,
 1292    pub color: PlayerColor,
 1293}
 1294
 1295#[derive(Clone, Debug)]
 1296struct SelectionHistoryEntry {
 1297    selections: Arc<[Selection<Anchor>]>,
 1298    select_next_state: Option<SelectNextState>,
 1299    select_prev_state: Option<SelectNextState>,
 1300    add_selections_state: Option<AddSelectionsState>,
 1301}
 1302
 1303#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1304enum SelectionHistoryMode {
 1305    #[default]
 1306    Normal,
 1307    Undoing,
 1308    Redoing,
 1309    Skipping,
 1310}
 1311
 1312#[derive(Clone, PartialEq, Eq, Hash)]
 1313struct HoveredCursor {
 1314    replica_id: ReplicaId,
 1315    selection_id: usize,
 1316}
 1317
 1318#[derive(Debug)]
 1319/// SelectionEffects controls the side-effects of updating the selection.
 1320///
 1321/// The default behaviour does "what you mostly want":
 1322/// - it pushes to the nav history if the cursor moved by >10 lines
 1323/// - it re-triggers completion requests
 1324/// - it scrolls to fit
 1325///
 1326/// You might want to modify these behaviours. For example when doing a "jump"
 1327/// like go to definition, we always want to add to nav history; but when scrolling
 1328/// in vim mode we never do.
 1329///
 1330/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1331/// move.
 1332#[derive(Clone)]
 1333pub struct SelectionEffects {
 1334    nav_history: Option<bool>,
 1335    completions: bool,
 1336    scroll: Option<Autoscroll>,
 1337}
 1338
 1339impl Default for SelectionEffects {
 1340    fn default() -> Self {
 1341        Self {
 1342            nav_history: None,
 1343            completions: true,
 1344            scroll: Some(Autoscroll::fit()),
 1345        }
 1346    }
 1347}
 1348impl SelectionEffects {
 1349    pub fn scroll(scroll: Autoscroll) -> Self {
 1350        Self {
 1351            scroll: Some(scroll),
 1352            ..Default::default()
 1353        }
 1354    }
 1355
 1356    pub fn no_scroll() -> Self {
 1357        Self {
 1358            scroll: None,
 1359            ..Default::default()
 1360        }
 1361    }
 1362
 1363    pub fn completions(self, completions: bool) -> Self {
 1364        Self {
 1365            completions,
 1366            ..self
 1367        }
 1368    }
 1369
 1370    pub fn nav_history(self, nav_history: bool) -> Self {
 1371        Self {
 1372            nav_history: Some(nav_history),
 1373            ..self
 1374        }
 1375    }
 1376}
 1377
 1378struct DeferredSelectionEffectsState {
 1379    changed: bool,
 1380    effects: SelectionEffects,
 1381    old_cursor_position: Anchor,
 1382    history_entry: SelectionHistoryEntry,
 1383}
 1384
 1385#[derive(Default)]
 1386struct SelectionHistory {
 1387    #[allow(clippy::type_complexity)]
 1388    selections_by_transaction:
 1389        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1390    mode: SelectionHistoryMode,
 1391    undo_stack: VecDeque<SelectionHistoryEntry>,
 1392    redo_stack: VecDeque<SelectionHistoryEntry>,
 1393}
 1394
 1395impl SelectionHistory {
 1396    #[track_caller]
 1397    fn insert_transaction(
 1398        &mut self,
 1399        transaction_id: TransactionId,
 1400        selections: Arc<[Selection<Anchor>]>,
 1401    ) {
 1402        if selections.is_empty() {
 1403            log::error!(
 1404                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1405                std::panic::Location::caller()
 1406            );
 1407            return;
 1408        }
 1409        self.selections_by_transaction
 1410            .insert(transaction_id, (selections, None));
 1411    }
 1412
 1413    #[allow(clippy::type_complexity)]
 1414    fn transaction(
 1415        &self,
 1416        transaction_id: TransactionId,
 1417    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1418        self.selections_by_transaction.get(&transaction_id)
 1419    }
 1420
 1421    #[allow(clippy::type_complexity)]
 1422    fn transaction_mut(
 1423        &mut self,
 1424        transaction_id: TransactionId,
 1425    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1426        self.selections_by_transaction.get_mut(&transaction_id)
 1427    }
 1428
 1429    fn push(&mut self, entry: SelectionHistoryEntry) {
 1430        if !entry.selections.is_empty() {
 1431            match self.mode {
 1432                SelectionHistoryMode::Normal => {
 1433                    self.push_undo(entry);
 1434                    self.redo_stack.clear();
 1435                }
 1436                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1437                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1438                SelectionHistoryMode::Skipping => {}
 1439            }
 1440        }
 1441    }
 1442
 1443    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1444        if self
 1445            .undo_stack
 1446            .back()
 1447            .is_none_or(|e| e.selections != entry.selections)
 1448        {
 1449            self.undo_stack.push_back(entry);
 1450            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1451                self.undo_stack.pop_front();
 1452            }
 1453        }
 1454    }
 1455
 1456    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1457        if self
 1458            .redo_stack
 1459            .back()
 1460            .is_none_or(|e| e.selections != entry.selections)
 1461        {
 1462            self.redo_stack.push_back(entry);
 1463            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1464                self.redo_stack.pop_front();
 1465            }
 1466        }
 1467    }
 1468}
 1469
 1470#[derive(Clone, Copy)]
 1471pub struct RowHighlightOptions {
 1472    pub autoscroll: bool,
 1473    pub include_gutter: bool,
 1474}
 1475
 1476impl Default for RowHighlightOptions {
 1477    fn default() -> Self {
 1478        Self {
 1479            autoscroll: Default::default(),
 1480            include_gutter: true,
 1481        }
 1482    }
 1483}
 1484
 1485struct RowHighlight {
 1486    index: usize,
 1487    range: Range<Anchor>,
 1488    color: Hsla,
 1489    options: RowHighlightOptions,
 1490    type_id: TypeId,
 1491}
 1492
 1493#[derive(Clone, Debug)]
 1494struct AddSelectionsState {
 1495    groups: Vec<AddSelectionsGroup>,
 1496}
 1497
 1498#[derive(Clone, Debug)]
 1499struct AddSelectionsGroup {
 1500    above: bool,
 1501    stack: Vec<usize>,
 1502}
 1503
 1504#[derive(Clone)]
 1505struct SelectNextState {
 1506    query: AhoCorasick,
 1507    wordwise: bool,
 1508    done: bool,
 1509}
 1510
 1511impl std::fmt::Debug for SelectNextState {
 1512    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1513        f.debug_struct(std::any::type_name::<Self>())
 1514            .field("wordwise", &self.wordwise)
 1515            .field("done", &self.done)
 1516            .finish()
 1517    }
 1518}
 1519
 1520#[derive(Debug)]
 1521struct AutocloseRegion {
 1522    selection_id: usize,
 1523    range: Range<Anchor>,
 1524    pair: BracketPair,
 1525}
 1526
 1527#[derive(Debug)]
 1528struct SnippetState {
 1529    ranges: Vec<Vec<Range<Anchor>>>,
 1530    active_index: usize,
 1531    choices: Vec<Option<Vec<String>>>,
 1532}
 1533
 1534#[doc(hidden)]
 1535pub struct RenameState {
 1536    pub range: Range<Anchor>,
 1537    pub old_name: Arc<str>,
 1538    pub editor: Entity<Editor>,
 1539    block_id: CustomBlockId,
 1540}
 1541
 1542struct InvalidationStack<T>(Vec<T>);
 1543
 1544struct RegisteredEditPredictionProvider {
 1545    provider: Arc<dyn EditPredictionProviderHandle>,
 1546    _subscription: Subscription,
 1547}
 1548
 1549#[derive(Debug, PartialEq, Eq)]
 1550pub struct ActiveDiagnosticGroup {
 1551    pub active_range: Range<Anchor>,
 1552    pub active_message: String,
 1553    pub group_id: usize,
 1554    pub blocks: HashSet<CustomBlockId>,
 1555}
 1556
 1557#[derive(Debug, PartialEq, Eq)]
 1558
 1559pub(crate) enum ActiveDiagnostic {
 1560    None,
 1561    All,
 1562    Group(ActiveDiagnosticGroup),
 1563}
 1564
 1565#[derive(Serialize, Deserialize, Clone, Debug)]
 1566pub struct ClipboardSelection {
 1567    /// The number of bytes in this selection.
 1568    pub len: usize,
 1569    /// Whether this was a full-line selection.
 1570    pub is_entire_line: bool,
 1571    /// The indentation of the first line when this content was originally copied.
 1572    pub first_line_indent: u32,
 1573}
 1574
 1575// selections, scroll behavior, was newest selection reversed
 1576type SelectSyntaxNodeHistoryState = (
 1577    Box<[Selection<usize>]>,
 1578    SelectSyntaxNodeScrollBehavior,
 1579    bool,
 1580);
 1581
 1582#[derive(Default)]
 1583struct SelectSyntaxNodeHistory {
 1584    stack: Vec<SelectSyntaxNodeHistoryState>,
 1585    // disable temporarily to allow changing selections without losing the stack
 1586    pub disable_clearing: bool,
 1587}
 1588
 1589impl SelectSyntaxNodeHistory {
 1590    pub fn try_clear(&mut self) {
 1591        if !self.disable_clearing {
 1592            self.stack.clear();
 1593        }
 1594    }
 1595
 1596    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1597        self.stack.push(selection);
 1598    }
 1599
 1600    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1601        self.stack.pop()
 1602    }
 1603}
 1604
 1605enum SelectSyntaxNodeScrollBehavior {
 1606    CursorTop,
 1607    FitSelection,
 1608    CursorBottom,
 1609}
 1610
 1611#[derive(Debug)]
 1612pub(crate) struct NavigationData {
 1613    cursor_anchor: Anchor,
 1614    cursor_position: Point,
 1615    scroll_anchor: ScrollAnchor,
 1616    scroll_top_row: u32,
 1617}
 1618
 1619#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1620pub enum GotoDefinitionKind {
 1621    Symbol,
 1622    Declaration,
 1623    Type,
 1624    Implementation,
 1625}
 1626
 1627pub enum FormatTarget {
 1628    Buffers(HashSet<Entity<Buffer>>),
 1629    Ranges(Vec<Range<MultiBufferPoint>>),
 1630}
 1631
 1632pub(crate) struct FocusedBlock {
 1633    id: BlockId,
 1634    focus_handle: WeakFocusHandle,
 1635}
 1636
 1637#[derive(Clone)]
 1638enum JumpData {
 1639    MultiBufferRow {
 1640        row: MultiBufferRow,
 1641        line_offset_from_top: u32,
 1642    },
 1643    MultiBufferPoint {
 1644        excerpt_id: ExcerptId,
 1645        position: Point,
 1646        anchor: text::Anchor,
 1647        line_offset_from_top: u32,
 1648    },
 1649}
 1650
 1651pub enum MultibufferSelectionMode {
 1652    First,
 1653    All,
 1654}
 1655
 1656#[derive(Clone, Copy, Debug, Default)]
 1657pub struct RewrapOptions {
 1658    pub override_language_settings: bool,
 1659    pub preserve_existing_whitespace: bool,
 1660}
 1661
 1662impl Editor {
 1663    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::full(), buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn auto_height(
 1676        min_lines: usize,
 1677        max_lines: usize,
 1678        window: &mut Window,
 1679        cx: &mut Context<Self>,
 1680    ) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::AutoHeight {
 1685                min_lines,
 1686                max_lines: Some(max_lines),
 1687            },
 1688            buffer,
 1689            None,
 1690            window,
 1691            cx,
 1692        )
 1693    }
 1694
 1695    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1696    /// The editor grows as tall as needed to fit its content.
 1697    pub fn auto_height_unbounded(
 1698        min_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: None,
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    pub fn for_buffer(
 1717        buffer: Entity<Buffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1723        Self::new(EditorMode::full(), buffer, project, window, cx)
 1724    }
 1725
 1726    pub fn for_multibuffer(
 1727        buffer: Entity<MultiBuffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        Self::new(EditorMode::full(), buffer, project, window, cx)
 1733    }
 1734
 1735    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1736        let mut clone = Self::new(
 1737            self.mode.clone(),
 1738            self.buffer.clone(),
 1739            self.project.clone(),
 1740            window,
 1741            cx,
 1742        );
 1743        self.display_map.update(cx, |display_map, cx| {
 1744            let snapshot = display_map.snapshot(cx);
 1745            clone.display_map.update(cx, |display_map, cx| {
 1746                display_map.set_state(&snapshot, cx);
 1747            });
 1748        });
 1749        clone.folds_did_change(cx);
 1750        clone.selections.clone_state(&self.selections);
 1751        clone.scroll_manager.clone_state(&self.scroll_manager);
 1752        clone.searchable = self.searchable;
 1753        clone.read_only = self.read_only;
 1754        clone
 1755    }
 1756
 1757    pub fn new(
 1758        mode: EditorMode,
 1759        buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        Editor::new_internal(mode, buffer, project, None, window, cx)
 1765    }
 1766
 1767    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1768        let multi_buffer = self.buffer().read(cx);
 1769        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1770        let multi_buffer_visible_start = self
 1771            .scroll_manager
 1772            .anchor()
 1773            .anchor
 1774            .to_point(&multi_buffer_snapshot);
 1775        let max_row = multi_buffer_snapshot.max_point().row;
 1776
 1777        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1778        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1779
 1780        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1781            let outline_items = buffer
 1782                .outline_items_containing(
 1783                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1784                    true,
 1785                    self.style().map(|style| style.syntax.as_ref()),
 1786                )
 1787                .into_iter()
 1788                .map(|outline_item| OutlineItem {
 1789                    depth: outline_item.depth,
 1790                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1791                    source_range_for_text: Anchor::range_in_buffer(
 1792                        *excerpt_id,
 1793                        buffer_id,
 1794                        outline_item.source_range_for_text,
 1795                    ),
 1796                    text: outline_item.text,
 1797                    highlight_ranges: outline_item.highlight_ranges,
 1798                    name_ranges: outline_item.name_ranges,
 1799                    body_range: outline_item
 1800                        .body_range
 1801                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1802                    annotation_range: outline_item
 1803                        .annotation_range
 1804                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1805                });
 1806            return Some(outline_items.collect());
 1807        }
 1808
 1809        None
 1810    }
 1811
 1812    fn new_internal(
 1813        mode: EditorMode,
 1814        multi_buffer: Entity<MultiBuffer>,
 1815        project: Option<Entity<Project>>,
 1816        display_map: Option<Entity<DisplayMap>>,
 1817        window: &mut Window,
 1818        cx: &mut Context<Self>,
 1819    ) -> Self {
 1820        debug_assert!(
 1821            display_map.is_none() || mode.is_minimap(),
 1822            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1823        );
 1824
 1825        let full_mode = mode.is_full();
 1826        let is_minimap = mode.is_minimap();
 1827        let diagnostics_max_severity = if full_mode {
 1828            EditorSettings::get_global(cx)
 1829                .diagnostics_max_severity
 1830                .unwrap_or(DiagnosticSeverity::Hint)
 1831        } else {
 1832            DiagnosticSeverity::Off
 1833        };
 1834        let style = window.text_style();
 1835        let font_size = style.font_size.to_pixels(window.rem_size());
 1836        let editor = cx.entity().downgrade();
 1837        let fold_placeholder = FoldPlaceholder {
 1838            constrain_width: false,
 1839            render: Arc::new(move |fold_id, fold_range, cx| {
 1840                let editor = editor.clone();
 1841                div()
 1842                    .id(fold_id)
 1843                    .bg(cx.theme().colors().ghost_element_background)
 1844                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1845                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1846                    .rounded_xs()
 1847                    .size_full()
 1848                    .cursor_pointer()
 1849                    .child("")
 1850                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1851                    .on_click(move |_, _window, cx| {
 1852                        editor
 1853                            .update(cx, |editor, cx| {
 1854                                editor.unfold_ranges(
 1855                                    &[fold_range.start..fold_range.end],
 1856                                    true,
 1857                                    false,
 1858                                    cx,
 1859                                );
 1860                                cx.stop_propagation();
 1861                            })
 1862                            .ok();
 1863                    })
 1864                    .into_any()
 1865            }),
 1866            merge_adjacent: true,
 1867            ..FoldPlaceholder::default()
 1868        };
 1869        let display_map = display_map.unwrap_or_else(|| {
 1870            cx.new(|cx| {
 1871                DisplayMap::new(
 1872                    multi_buffer.clone(),
 1873                    style.font(),
 1874                    font_size,
 1875                    None,
 1876                    FILE_HEADER_HEIGHT,
 1877                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1878                    fold_placeholder,
 1879                    diagnostics_max_severity,
 1880                    cx,
 1881                )
 1882            })
 1883        });
 1884
 1885        let selections = SelectionsCollection::new();
 1886
 1887        let blink_manager = cx.new(|cx| {
 1888            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1889            if is_minimap {
 1890                blink_manager.disable(cx);
 1891            }
 1892            blink_manager
 1893        });
 1894
 1895        let soft_wrap_mode_override =
 1896            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1897
 1898        let mut project_subscriptions = Vec::new();
 1899        if full_mode && let Some(project) = project.as_ref() {
 1900            project_subscriptions.push(cx.subscribe_in(
 1901                project,
 1902                window,
 1903                |editor, _, event, window, cx| match event {
 1904                    project::Event::RefreshCodeLens => {
 1905                        // we always query lens with actions, without storing them, always refreshing them
 1906                    }
 1907                    project::Event::RefreshInlayHints {
 1908                        server_id,
 1909                        request_id,
 1910                    } => {
 1911                        editor.refresh_inlay_hints(
 1912                            InlayHintRefreshReason::RefreshRequested {
 1913                                server_id: *server_id,
 1914                                request_id: *request_id,
 1915                            },
 1916                            cx,
 1917                        );
 1918                    }
 1919                    project::Event::LanguageServerRemoved(..) => {
 1920                        if editor.tasks_update_task.is_none() {
 1921                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1922                        }
 1923                        editor.registered_buffers.clear();
 1924                        editor.register_visible_buffers(cx);
 1925                    }
 1926                    project::Event::LanguageServerAdded(..) => {
 1927                        if editor.tasks_update_task.is_none() {
 1928                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1929                        }
 1930                    }
 1931                    project::Event::SnippetEdit(id, snippet_edits) => {
 1932                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1933                            let focus_handle = editor.focus_handle(cx);
 1934                            if focus_handle.is_focused(window) {
 1935                                let snapshot = buffer.read(cx).snapshot();
 1936                                for (range, snippet) in snippet_edits {
 1937                                    let editor_range =
 1938                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1939                                    editor
 1940                                        .insert_snippet(
 1941                                            &[editor_range],
 1942                                            snippet.clone(),
 1943                                            window,
 1944                                            cx,
 1945                                        )
 1946                                        .ok();
 1947                                }
 1948                            }
 1949                        }
 1950                    }
 1951                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1952                        let buffer_id = *buffer_id;
 1953                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1954                            editor.register_buffer(buffer_id, cx);
 1955                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1956                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1957                            refresh_linked_ranges(editor, window, cx);
 1958                            editor.refresh_code_actions(window, cx);
 1959                            editor.refresh_document_highlights(cx);
 1960                        }
 1961                    }
 1962
 1963                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1964                        let Some(workspace) = editor.workspace() else {
 1965                            return;
 1966                        };
 1967                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1968                        else {
 1969                            return;
 1970                        };
 1971
 1972                        if active_editor.entity_id() == cx.entity_id() {
 1973                            let entity_id = cx.entity_id();
 1974                            workspace.update(cx, |this, cx| {
 1975                                this.panes_mut()
 1976                                    .iter_mut()
 1977                                    .filter(|pane| pane.entity_id() != entity_id)
 1978                                    .for_each(|p| {
 1979                                        p.update(cx, |pane, _| {
 1980                                            pane.nav_history_mut().rename_item(
 1981                                                entity_id,
 1982                                                project_path.clone(),
 1983                                                abs_path.clone().into(),
 1984                                            );
 1985                                        })
 1986                                    });
 1987                            });
 1988                            let edited_buffers_already_open = {
 1989                                let other_editors: Vec<Entity<Editor>> = workspace
 1990                                    .read(cx)
 1991                                    .panes()
 1992                                    .iter()
 1993                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1994                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1995                                    .collect();
 1996
 1997                                transaction.0.keys().all(|buffer| {
 1998                                    other_editors.iter().any(|editor| {
 1999                                        let multi_buffer = editor.read(cx).buffer();
 2000                                        multi_buffer.read(cx).is_singleton()
 2001                                            && multi_buffer.read(cx).as_singleton().map_or(
 2002                                                false,
 2003                                                |singleton| {
 2004                                                    singleton.entity_id() == buffer.entity_id()
 2005                                                },
 2006                                            )
 2007                                    })
 2008                                })
 2009                            };
 2010                            if !edited_buffers_already_open {
 2011                                let workspace = workspace.downgrade();
 2012                                let transaction = transaction.clone();
 2013                                cx.defer_in(window, move |_, window, cx| {
 2014                                    cx.spawn_in(window, async move |editor, cx| {
 2015                                        Self::open_project_transaction(
 2016                                            &editor,
 2017                                            workspace,
 2018                                            transaction,
 2019                                            "Rename".to_string(),
 2020                                            cx,
 2021                                        )
 2022                                        .await
 2023                                        .ok()
 2024                                    })
 2025                                    .detach();
 2026                                });
 2027                            }
 2028                        }
 2029                    }
 2030
 2031                    _ => {}
 2032                },
 2033            ));
 2034            if let Some(task_inventory) = project
 2035                .read(cx)
 2036                .task_store()
 2037                .read(cx)
 2038                .task_inventory()
 2039                .cloned()
 2040            {
 2041                project_subscriptions.push(cx.observe_in(
 2042                    &task_inventory,
 2043                    window,
 2044                    |editor, _, window, cx| {
 2045                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2046                    },
 2047                ));
 2048            };
 2049
 2050            project_subscriptions.push(cx.subscribe_in(
 2051                &project.read(cx).breakpoint_store(),
 2052                window,
 2053                |editor, _, event, window, cx| match event {
 2054                    BreakpointStoreEvent::ClearDebugLines => {
 2055                        editor.clear_row_highlights::<ActiveDebugLine>();
 2056                        editor.refresh_inline_values(cx);
 2057                    }
 2058                    BreakpointStoreEvent::SetDebugLine => {
 2059                        if editor.go_to_active_debug_line(window, cx) {
 2060                            cx.stop_propagation();
 2061                        }
 2062
 2063                        editor.refresh_inline_values(cx);
 2064                    }
 2065                    _ => {}
 2066                },
 2067            ));
 2068            let git_store = project.read(cx).git_store().clone();
 2069            let project = project.clone();
 2070            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2071                if let GitStoreEvent::RepositoryAdded = event {
 2072                    this.load_diff_task = Some(
 2073                        update_uncommitted_diff_for_buffer(
 2074                            cx.entity(),
 2075                            &project,
 2076                            this.buffer.read(cx).all_buffers(),
 2077                            this.buffer.clone(),
 2078                            cx,
 2079                        )
 2080                        .shared(),
 2081                    );
 2082                }
 2083            }));
 2084        }
 2085
 2086        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2087
 2088        let inlay_hint_settings =
 2089            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2090        let focus_handle = cx.focus_handle();
 2091        if !is_minimap {
 2092            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2093                .detach();
 2094            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2095                .detach();
 2096            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2097                .detach();
 2098            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2099                .detach();
 2100            cx.observe_pending_input(window, Self::observe_pending_input)
 2101                .detach();
 2102        }
 2103
 2104        let show_indent_guides =
 2105            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2106                Some(false)
 2107            } else {
 2108                None
 2109            };
 2110
 2111        let breakpoint_store = match (&mode, project.as_ref()) {
 2112            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2113            _ => None,
 2114        };
 2115
 2116        let mut code_action_providers = Vec::new();
 2117        let mut load_uncommitted_diff = None;
 2118        if let Some(project) = project.clone() {
 2119            load_uncommitted_diff = Some(
 2120                update_uncommitted_diff_for_buffer(
 2121                    cx.entity(),
 2122                    &project,
 2123                    multi_buffer.read(cx).all_buffers(),
 2124                    multi_buffer.clone(),
 2125                    cx,
 2126                )
 2127                .shared(),
 2128            );
 2129            code_action_providers.push(Rc::new(project) as Rc<_>);
 2130        }
 2131
 2132        let mut editor = Self {
 2133            focus_handle,
 2134            show_cursor_when_unfocused: false,
 2135            last_focused_descendant: None,
 2136            buffer: multi_buffer.clone(),
 2137            display_map: display_map.clone(),
 2138            placeholder_display_map: None,
 2139            selections,
 2140            scroll_manager: ScrollManager::new(cx),
 2141            columnar_selection_state: None,
 2142            add_selections_state: None,
 2143            select_next_state: None,
 2144            select_prev_state: None,
 2145            selection_history: SelectionHistory::default(),
 2146            defer_selection_effects: false,
 2147            deferred_selection_effects_state: None,
 2148            autoclose_regions: Vec::new(),
 2149            snippet_stack: InvalidationStack::default(),
 2150            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2151            ime_transaction: None,
 2152            active_diagnostics: ActiveDiagnostic::None,
 2153            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2154            inline_diagnostics_update: Task::ready(()),
 2155            inline_diagnostics: Vec::new(),
 2156            soft_wrap_mode_override,
 2157            diagnostics_max_severity,
 2158            hard_wrap: None,
 2159            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2160            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2161            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2162            project,
 2163            blink_manager: blink_manager.clone(),
 2164            show_local_selections: true,
 2165            show_scrollbars: ScrollbarAxes {
 2166                horizontal: full_mode,
 2167                vertical: full_mode,
 2168            },
 2169            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2170            offset_content: !matches!(mode, EditorMode::SingleLine),
 2171            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2172            show_gutter: full_mode,
 2173            show_line_numbers: (!full_mode).then_some(false),
 2174            use_relative_line_numbers: None,
 2175            disable_expand_excerpt_buttons: !full_mode,
 2176            show_git_diff_gutter: None,
 2177            show_code_actions: None,
 2178            show_runnables: None,
 2179            show_breakpoints: None,
 2180            show_wrap_guides: None,
 2181            show_indent_guides,
 2182            highlight_order: 0,
 2183            highlighted_rows: HashMap::default(),
 2184            background_highlights: HashMap::default(),
 2185            gutter_highlights: HashMap::default(),
 2186            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2187            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2188            nav_history: None,
 2189            context_menu: RefCell::new(None),
 2190            context_menu_options: None,
 2191            mouse_context_menu: None,
 2192            completion_tasks: Vec::new(),
 2193            inline_blame_popover: None,
 2194            inline_blame_popover_show_task: None,
 2195            signature_help_state: SignatureHelpState::default(),
 2196            auto_signature_help: None,
 2197            find_all_references_task_sources: Vec::new(),
 2198            next_completion_id: 0,
 2199            next_inlay_id: 0,
 2200            code_action_providers,
 2201            available_code_actions: None,
 2202            code_actions_task: None,
 2203            quick_selection_highlight_task: None,
 2204            debounced_selection_highlight_task: None,
 2205            document_highlights_task: None,
 2206            linked_editing_range_task: None,
 2207            pending_rename: None,
 2208            searchable: !is_minimap,
 2209            cursor_shape: EditorSettings::get_global(cx)
 2210                .cursor_shape
 2211                .unwrap_or_default(),
 2212            current_line_highlight: None,
 2213            autoindent_mode: Some(AutoindentMode::EachLine),
 2214
 2215            workspace: None,
 2216            input_enabled: !is_minimap,
 2217            use_modal_editing: full_mode,
 2218            read_only: is_minimap,
 2219            use_autoclose: true,
 2220            use_auto_surround: true,
 2221            auto_replace_emoji_shortcode: false,
 2222            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2223            leader_id: None,
 2224            remote_id: None,
 2225            hover_state: HoverState::default(),
 2226            pending_mouse_down: None,
 2227            hovered_link_state: None,
 2228            edit_prediction_provider: None,
 2229            active_edit_prediction: None,
 2230            stale_edit_prediction_in_menu: None,
 2231            edit_prediction_preview: EditPredictionPreview::Inactive {
 2232                released_too_fast: false,
 2233            },
 2234            inline_diagnostics_enabled: full_mode,
 2235            diagnostics_enabled: full_mode,
 2236            word_completions_enabled: full_mode,
 2237            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2238            gutter_hovered: false,
 2239            pixel_position_of_newest_cursor: None,
 2240            last_bounds: None,
 2241            last_position_map: None,
 2242            expect_bounds_change: None,
 2243            gutter_dimensions: GutterDimensions::default(),
 2244            style: None,
 2245            show_cursor_names: false,
 2246            hovered_cursors: HashMap::default(),
 2247            next_editor_action_id: EditorActionId::default(),
 2248            editor_actions: Rc::default(),
 2249            edit_predictions_hidden_for_vim_mode: false,
 2250            show_edit_predictions_override: None,
 2251            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2252            edit_prediction_settings: EditPredictionSettings::Disabled,
 2253            edit_prediction_indent_conflict: false,
 2254            edit_prediction_requires_modifier_in_indent_conflict: true,
 2255            custom_context_menu: None,
 2256            show_git_blame_gutter: false,
 2257            show_git_blame_inline: false,
 2258            show_selection_menu: None,
 2259            show_git_blame_inline_delay_task: None,
 2260            git_blame_inline_enabled: full_mode
 2261                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2262            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2263            buffer_serialization: is_minimap.not().then(|| {
 2264                BufferSerialization::new(
 2265                    ProjectSettings::get_global(cx)
 2266                        .session
 2267                        .restore_unsaved_buffers,
 2268                )
 2269            }),
 2270            blame: None,
 2271            blame_subscription: None,
 2272            tasks: BTreeMap::default(),
 2273
 2274            breakpoint_store,
 2275            gutter_breakpoint_indicator: (None, None),
 2276            hovered_diff_hunk_row: None,
 2277            _subscriptions: (!is_minimap)
 2278                .then(|| {
 2279                    vec![
 2280                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2281                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2282                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2283                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2284                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2285                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2286                        cx.observe_window_activation(window, |editor, window, cx| {
 2287                            let active = window.is_window_active();
 2288                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2289                                if active {
 2290                                    blink_manager.enable(cx);
 2291                                } else {
 2292                                    blink_manager.disable(cx);
 2293                                }
 2294                            });
 2295                            if active {
 2296                                editor.show_mouse_cursor(cx);
 2297                            }
 2298                        }),
 2299                    ]
 2300                })
 2301                .unwrap_or_default(),
 2302            tasks_update_task: None,
 2303            pull_diagnostics_task: Task::ready(()),
 2304            colors: None,
 2305            refresh_colors_task: Task::ready(()),
 2306            inlay_hints: None,
 2307            next_color_inlay_id: 0,
 2308            post_scroll_update: Task::ready(()),
 2309            linked_edit_ranges: Default::default(),
 2310            in_project_search: false,
 2311            previous_search_ranges: None,
 2312            breadcrumb_header: None,
 2313            focused_block: None,
 2314            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2315            addons: HashMap::default(),
 2316            registered_buffers: HashMap::default(),
 2317            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2318            selection_mark_mode: false,
 2319            toggle_fold_multiple_buffers: Task::ready(()),
 2320            serialize_selections: Task::ready(()),
 2321            serialize_folds: Task::ready(()),
 2322            text_style_refinement: None,
 2323            load_diff_task: load_uncommitted_diff,
 2324            temporary_diff_override: false,
 2325            mouse_cursor_hidden: false,
 2326            minimap: None,
 2327            hide_mouse_mode: EditorSettings::get_global(cx)
 2328                .hide_mouse
 2329                .unwrap_or_default(),
 2330            change_list: ChangeList::new(),
 2331            mode,
 2332            selection_drag_state: SelectionDragState::None,
 2333            folding_newlines: Task::ready(()),
 2334            lookup_key: None,
 2335            select_next_is_case_sensitive: None,
 2336        };
 2337
 2338        if is_minimap {
 2339            return editor;
 2340        }
 2341
 2342        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2343            editor
 2344                ._subscriptions
 2345                .push(cx.observe(breakpoints, |_, _, cx| {
 2346                    cx.notify();
 2347                }));
 2348        }
 2349        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2350        editor._subscriptions.extend(project_subscriptions);
 2351
 2352        editor._subscriptions.push(cx.subscribe_in(
 2353            &cx.entity(),
 2354            window,
 2355            |editor, _, e: &EditorEvent, window, cx| match e {
 2356                EditorEvent::ScrollPositionChanged { local, .. } => {
 2357                    if *local {
 2358                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2359                        editor.inline_blame_popover.take();
 2360                        let new_anchor = editor.scroll_manager.anchor();
 2361                        let snapshot = editor.snapshot(window, cx);
 2362                        editor.update_restoration_data(cx, move |data| {
 2363                            data.scroll_position = (
 2364                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2365                                new_anchor.offset,
 2366                            );
 2367                        });
 2368
 2369                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2370                            cx.background_executor()
 2371                                .timer(Duration::from_millis(50))
 2372                                .await;
 2373                            editor
 2374                                .update_in(cx, |editor, window, cx| {
 2375                                    editor.register_visible_buffers(cx);
 2376                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2377                                    editor.refresh_inlay_hints(
 2378                                        InlayHintRefreshReason::NewLinesShown,
 2379                                        cx,
 2380                                    );
 2381                                })
 2382                                .ok();
 2383                        });
 2384                    }
 2385                }
 2386                EditorEvent::Edited { .. } => {
 2387                    if vim_flavor(cx).is_none() {
 2388                        let display_map = editor.display_snapshot(cx);
 2389                        let selections = editor.selections.all_adjusted_display(&display_map);
 2390                        let pop_state = editor
 2391                            .change_list
 2392                            .last()
 2393                            .map(|previous| {
 2394                                previous.len() == selections.len()
 2395                                    && previous.iter().enumerate().all(|(ix, p)| {
 2396                                        p.to_display_point(&display_map).row()
 2397                                            == selections[ix].head().row()
 2398                                    })
 2399                            })
 2400                            .unwrap_or(false);
 2401                        let new_positions = selections
 2402                            .into_iter()
 2403                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2404                            .collect();
 2405                        editor
 2406                            .change_list
 2407                            .push_to_change_list(pop_state, new_positions);
 2408                    }
 2409                }
 2410                _ => (),
 2411            },
 2412        ));
 2413
 2414        if let Some(dap_store) = editor
 2415            .project
 2416            .as_ref()
 2417            .map(|project| project.read(cx).dap_store())
 2418        {
 2419            let weak_editor = cx.weak_entity();
 2420
 2421            editor
 2422                ._subscriptions
 2423                .push(
 2424                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2425                        let session_entity = cx.entity();
 2426                        weak_editor
 2427                            .update(cx, |editor, cx| {
 2428                                editor._subscriptions.push(
 2429                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2430                                );
 2431                            })
 2432                            .ok();
 2433                    }),
 2434                );
 2435
 2436            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2437                editor
 2438                    ._subscriptions
 2439                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2440            }
 2441        }
 2442
 2443        // skip adding the initial selection to selection history
 2444        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2445        editor.end_selection(window, cx);
 2446        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2447
 2448        editor.scroll_manager.show_scrollbars(window, cx);
 2449        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2450
 2451        if full_mode {
 2452            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2453            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2454
 2455            if editor.git_blame_inline_enabled {
 2456                editor.start_git_blame_inline(false, window, cx);
 2457            }
 2458
 2459            editor.go_to_active_debug_line(window, cx);
 2460
 2461            editor.minimap =
 2462                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2463            editor.colors = Some(LspColorData::new(cx));
 2464            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2465
 2466            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2467                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2468            }
 2469            editor.update_lsp_data(None, window, cx);
 2470            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2471        }
 2472
 2473        editor
 2474    }
 2475
 2476    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2477        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2478    }
 2479
 2480    pub fn deploy_mouse_context_menu(
 2481        &mut self,
 2482        position: gpui::Point<Pixels>,
 2483        context_menu: Entity<ContextMenu>,
 2484        window: &mut Window,
 2485        cx: &mut Context<Self>,
 2486    ) {
 2487        self.mouse_context_menu = Some(MouseContextMenu::new(
 2488            self,
 2489            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2490            context_menu,
 2491            window,
 2492            cx,
 2493        ));
 2494    }
 2495
 2496    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2497        self.mouse_context_menu
 2498            .as_ref()
 2499            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2500    }
 2501
 2502    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2503        if self
 2504            .selections
 2505            .pending_anchor()
 2506            .is_some_and(|pending_selection| {
 2507                let snapshot = self.buffer().read(cx).snapshot(cx);
 2508                pending_selection.range().includes(range, &snapshot)
 2509            })
 2510        {
 2511            return true;
 2512        }
 2513
 2514        self.selections
 2515            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2516            .into_iter()
 2517            .any(|selection| {
 2518                // This is needed to cover a corner case, if we just check for an existing
 2519                // selection in the fold range, having a cursor at the start of the fold
 2520                // marks it as selected. Non-empty selections don't cause this.
 2521                let length = selection.end - selection.start;
 2522                length > 0
 2523            })
 2524    }
 2525
 2526    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2527        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2528    }
 2529
 2530    fn key_context_internal(
 2531        &self,
 2532        has_active_edit_prediction: bool,
 2533        window: &mut Window,
 2534        cx: &mut App,
 2535    ) -> KeyContext {
 2536        let mut key_context = KeyContext::new_with_defaults();
 2537        key_context.add("Editor");
 2538        let mode = match self.mode {
 2539            EditorMode::SingleLine => "single_line",
 2540            EditorMode::AutoHeight { .. } => "auto_height",
 2541            EditorMode::Minimap { .. } => "minimap",
 2542            EditorMode::Full { .. } => "full",
 2543        };
 2544
 2545        if EditorSettings::jupyter_enabled(cx) {
 2546            key_context.add("jupyter");
 2547        }
 2548
 2549        key_context.set("mode", mode);
 2550        if self.pending_rename.is_some() {
 2551            key_context.add("renaming");
 2552        }
 2553
 2554        if let Some(snippet_stack) = self.snippet_stack.last() {
 2555            key_context.add("in_snippet");
 2556
 2557            if snippet_stack.active_index > 0 {
 2558                key_context.add("has_previous_tabstop");
 2559            }
 2560
 2561            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2562                key_context.add("has_next_tabstop");
 2563            }
 2564        }
 2565
 2566        match self.context_menu.borrow().as_ref() {
 2567            Some(CodeContextMenu::Completions(menu)) => {
 2568                if menu.visible() {
 2569                    key_context.add("menu");
 2570                    key_context.add("showing_completions");
 2571                }
 2572            }
 2573            Some(CodeContextMenu::CodeActions(menu)) => {
 2574                if menu.visible() {
 2575                    key_context.add("menu");
 2576                    key_context.add("showing_code_actions")
 2577                }
 2578            }
 2579            None => {}
 2580        }
 2581
 2582        if self.signature_help_state.has_multiple_signatures() {
 2583            key_context.add("showing_signature_help");
 2584        }
 2585
 2586        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2587        if !self.focus_handle(cx).contains_focused(window, cx)
 2588            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2589        {
 2590            for addon in self.addons.values() {
 2591                addon.extend_key_context(&mut key_context, cx)
 2592            }
 2593        }
 2594
 2595        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2596            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2597                Some(
 2598                    file.full_path(cx)
 2599                        .extension()?
 2600                        .to_string_lossy()
 2601                        .into_owned(),
 2602                )
 2603            }) {
 2604                key_context.set("extension", extension);
 2605            }
 2606        } else {
 2607            key_context.add("multibuffer");
 2608        }
 2609
 2610        if has_active_edit_prediction {
 2611            if self.edit_prediction_in_conflict() {
 2612                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2613            } else {
 2614                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2615                key_context.add("copilot_suggestion");
 2616            }
 2617        }
 2618
 2619        if self.selection_mark_mode {
 2620            key_context.add("selection_mode");
 2621        }
 2622
 2623        let disjoint = self.selections.disjoint_anchors();
 2624        let snapshot = self.snapshot(window, cx);
 2625        let snapshot = snapshot.buffer_snapshot();
 2626        if self.mode == EditorMode::SingleLine
 2627            && let [selection] = disjoint
 2628            && selection.start == selection.end
 2629            && selection.end.to_offset(snapshot) == snapshot.len()
 2630        {
 2631            key_context.add("end_of_input");
 2632        }
 2633
 2634        key_context
 2635    }
 2636
 2637    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2638        self.last_bounds.as_ref()
 2639    }
 2640
 2641    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2642        if self.mouse_cursor_hidden {
 2643            self.mouse_cursor_hidden = false;
 2644            cx.notify();
 2645        }
 2646    }
 2647
 2648    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2649        let hide_mouse_cursor = match origin {
 2650            HideMouseCursorOrigin::TypingAction => {
 2651                matches!(
 2652                    self.hide_mouse_mode,
 2653                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2654                )
 2655            }
 2656            HideMouseCursorOrigin::MovementAction => {
 2657                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2658            }
 2659        };
 2660        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2661            self.mouse_cursor_hidden = hide_mouse_cursor;
 2662            cx.notify();
 2663        }
 2664    }
 2665
 2666    pub fn edit_prediction_in_conflict(&self) -> bool {
 2667        if !self.show_edit_predictions_in_menu() {
 2668            return false;
 2669        }
 2670
 2671        let showing_completions = self
 2672            .context_menu
 2673            .borrow()
 2674            .as_ref()
 2675            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2676
 2677        showing_completions
 2678            || self.edit_prediction_requires_modifier()
 2679            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2680            // bindings to insert tab characters.
 2681            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2682    }
 2683
 2684    pub fn accept_edit_prediction_keybind(
 2685        &self,
 2686        accept_partial: bool,
 2687        window: &mut Window,
 2688        cx: &mut App,
 2689    ) -> AcceptEditPredictionBinding {
 2690        let key_context = self.key_context_internal(true, window, cx);
 2691        let in_conflict = self.edit_prediction_in_conflict();
 2692
 2693        let bindings = if accept_partial {
 2694            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2695        } else {
 2696            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2697        };
 2698
 2699        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2700        // just the first one.
 2701        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2702            !in_conflict
 2703                || binding
 2704                    .keystrokes()
 2705                    .first()
 2706                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2707        }))
 2708    }
 2709
 2710    pub fn new_file(
 2711        workspace: &mut Workspace,
 2712        _: &workspace::NewFile,
 2713        window: &mut Window,
 2714        cx: &mut Context<Workspace>,
 2715    ) {
 2716        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2717            "Failed to create buffer",
 2718            window,
 2719            cx,
 2720            |e, _, _| match e.error_code() {
 2721                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2722                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2723                e.error_tag("required").unwrap_or("the latest version")
 2724            )),
 2725                _ => None,
 2726            },
 2727        );
 2728    }
 2729
 2730    pub fn new_in_workspace(
 2731        workspace: &mut Workspace,
 2732        window: &mut Window,
 2733        cx: &mut Context<Workspace>,
 2734    ) -> Task<Result<Entity<Editor>>> {
 2735        let project = workspace.project().clone();
 2736        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2737
 2738        cx.spawn_in(window, async move |workspace, cx| {
 2739            let buffer = create.await?;
 2740            workspace.update_in(cx, |workspace, window, cx| {
 2741                let editor =
 2742                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2743                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2744                editor
 2745            })
 2746        })
 2747    }
 2748
 2749    fn new_file_vertical(
 2750        workspace: &mut Workspace,
 2751        _: &workspace::NewFileSplitVertical,
 2752        window: &mut Window,
 2753        cx: &mut Context<Workspace>,
 2754    ) {
 2755        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2756    }
 2757
 2758    fn new_file_horizontal(
 2759        workspace: &mut Workspace,
 2760        _: &workspace::NewFileSplitHorizontal,
 2761        window: &mut Window,
 2762        cx: &mut Context<Workspace>,
 2763    ) {
 2764        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2765    }
 2766
 2767    fn new_file_split(
 2768        workspace: &mut Workspace,
 2769        action: &workspace::NewFileSplit,
 2770        window: &mut Window,
 2771        cx: &mut Context<Workspace>,
 2772    ) {
 2773        Self::new_file_in_direction(workspace, action.0, window, cx)
 2774    }
 2775
 2776    fn new_file_in_direction(
 2777        workspace: &mut Workspace,
 2778        direction: SplitDirection,
 2779        window: &mut Window,
 2780        cx: &mut Context<Workspace>,
 2781    ) {
 2782        let project = workspace.project().clone();
 2783        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2784
 2785        cx.spawn_in(window, async move |workspace, cx| {
 2786            let buffer = create.await?;
 2787            workspace.update_in(cx, move |workspace, window, cx| {
 2788                workspace.split_item(
 2789                    direction,
 2790                    Box::new(
 2791                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2792                    ),
 2793                    window,
 2794                    cx,
 2795                )
 2796            })?;
 2797            anyhow::Ok(())
 2798        })
 2799        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2800            match e.error_code() {
 2801                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2802                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2803                e.error_tag("required").unwrap_or("the latest version")
 2804            )),
 2805                _ => None,
 2806            }
 2807        });
 2808    }
 2809
 2810    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2811        self.leader_id
 2812    }
 2813
 2814    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2815        &self.buffer
 2816    }
 2817
 2818    pub fn project(&self) -> Option<&Entity<Project>> {
 2819        self.project.as_ref()
 2820    }
 2821
 2822    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2823        self.workspace.as_ref()?.0.upgrade()
 2824    }
 2825
 2826    /// Returns the workspace serialization ID if this editor should be serialized.
 2827    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2828        self.workspace
 2829            .as_ref()
 2830            .filter(|_| self.should_serialize_buffer())
 2831            .and_then(|workspace| workspace.1)
 2832    }
 2833
 2834    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2835        self.buffer().read(cx).title(cx)
 2836    }
 2837
 2838    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2839        let git_blame_gutter_max_author_length = self
 2840            .render_git_blame_gutter(cx)
 2841            .then(|| {
 2842                if let Some(blame) = self.blame.as_ref() {
 2843                    let max_author_length =
 2844                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2845                    Some(max_author_length)
 2846                } else {
 2847                    None
 2848                }
 2849            })
 2850            .flatten();
 2851
 2852        EditorSnapshot {
 2853            mode: self.mode.clone(),
 2854            show_gutter: self.show_gutter,
 2855            show_line_numbers: self.show_line_numbers,
 2856            show_git_diff_gutter: self.show_git_diff_gutter,
 2857            show_code_actions: self.show_code_actions,
 2858            show_runnables: self.show_runnables,
 2859            show_breakpoints: self.show_breakpoints,
 2860            git_blame_gutter_max_author_length,
 2861            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2862            placeholder_display_snapshot: self
 2863                .placeholder_display_map
 2864                .as_ref()
 2865                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2866            scroll_anchor: self.scroll_manager.anchor(),
 2867            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2868            is_focused: self.focus_handle.is_focused(window),
 2869            current_line_highlight: self
 2870                .current_line_highlight
 2871                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2872            gutter_hovered: self.gutter_hovered,
 2873        }
 2874    }
 2875
 2876    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2877        self.buffer.read(cx).language_at(point, cx)
 2878    }
 2879
 2880    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2881        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2882    }
 2883
 2884    pub fn active_excerpt(
 2885        &self,
 2886        cx: &App,
 2887    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2888        self.buffer
 2889            .read(cx)
 2890            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2891    }
 2892
 2893    pub fn mode(&self) -> &EditorMode {
 2894        &self.mode
 2895    }
 2896
 2897    pub fn set_mode(&mut self, mode: EditorMode) {
 2898        self.mode = mode;
 2899    }
 2900
 2901    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2902        self.collaboration_hub.as_deref()
 2903    }
 2904
 2905    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2906        self.collaboration_hub = Some(hub);
 2907    }
 2908
 2909    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2910        self.in_project_search = in_project_search;
 2911    }
 2912
 2913    pub fn set_custom_context_menu(
 2914        &mut self,
 2915        f: impl 'static
 2916        + Fn(
 2917            &mut Self,
 2918            DisplayPoint,
 2919            &mut Window,
 2920            &mut Context<Self>,
 2921        ) -> Option<Entity<ui::ContextMenu>>,
 2922    ) {
 2923        self.custom_context_menu = Some(Box::new(f))
 2924    }
 2925
 2926    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2927        self.completion_provider = provider;
 2928    }
 2929
 2930    #[cfg(any(test, feature = "test-support"))]
 2931    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2932        self.completion_provider.clone()
 2933    }
 2934
 2935    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2936        self.semantics_provider.clone()
 2937    }
 2938
 2939    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2940        self.semantics_provider = provider;
 2941    }
 2942
 2943    pub fn set_edit_prediction_provider<T>(
 2944        &mut self,
 2945        provider: Option<Entity<T>>,
 2946        window: &mut Window,
 2947        cx: &mut Context<Self>,
 2948    ) where
 2949        T: EditPredictionProvider,
 2950    {
 2951        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2952            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2953                if this.focus_handle.is_focused(window) {
 2954                    this.update_visible_edit_prediction(window, cx);
 2955                }
 2956            }),
 2957            provider: Arc::new(provider),
 2958        });
 2959        self.update_edit_prediction_settings(cx);
 2960        self.refresh_edit_prediction(false, false, window, cx);
 2961    }
 2962
 2963    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2964        self.placeholder_display_map
 2965            .as_ref()
 2966            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2967    }
 2968
 2969    pub fn set_placeholder_text(
 2970        &mut self,
 2971        placeholder_text: &str,
 2972        window: &mut Window,
 2973        cx: &mut Context<Self>,
 2974    ) {
 2975        let multibuffer = cx
 2976            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2977
 2978        let style = window.text_style();
 2979
 2980        self.placeholder_display_map = Some(cx.new(|cx| {
 2981            DisplayMap::new(
 2982                multibuffer,
 2983                style.font(),
 2984                style.font_size.to_pixels(window.rem_size()),
 2985                None,
 2986                FILE_HEADER_HEIGHT,
 2987                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2988                Default::default(),
 2989                DiagnosticSeverity::Off,
 2990                cx,
 2991            )
 2992        }));
 2993        cx.notify();
 2994    }
 2995
 2996    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2997        self.cursor_shape = cursor_shape;
 2998
 2999        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3000        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3001
 3002        cx.notify();
 3003    }
 3004
 3005    pub fn set_current_line_highlight(
 3006        &mut self,
 3007        current_line_highlight: Option<CurrentLineHighlight>,
 3008    ) {
 3009        self.current_line_highlight = current_line_highlight;
 3010    }
 3011
 3012    pub fn range_for_match<T: std::marker::Copy>(
 3013        &self,
 3014        range: &Range<T>,
 3015        collapse: bool,
 3016    ) -> Range<T> {
 3017        if collapse {
 3018            return range.start..range.start;
 3019        }
 3020        range.clone()
 3021    }
 3022
 3023    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3024        if self.display_map.read(cx).clip_at_line_ends != clip {
 3025            self.display_map
 3026                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3027        }
 3028    }
 3029
 3030    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3031        self.input_enabled = input_enabled;
 3032    }
 3033
 3034    pub fn set_edit_predictions_hidden_for_vim_mode(
 3035        &mut self,
 3036        hidden: bool,
 3037        window: &mut Window,
 3038        cx: &mut Context<Self>,
 3039    ) {
 3040        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3041            self.edit_predictions_hidden_for_vim_mode = hidden;
 3042            if hidden {
 3043                self.update_visible_edit_prediction(window, cx);
 3044            } else {
 3045                self.refresh_edit_prediction(true, false, window, cx);
 3046            }
 3047        }
 3048    }
 3049
 3050    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3051        self.menu_edit_predictions_policy = value;
 3052    }
 3053
 3054    pub fn set_autoindent(&mut self, autoindent: bool) {
 3055        if autoindent {
 3056            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3057        } else {
 3058            self.autoindent_mode = None;
 3059        }
 3060    }
 3061
 3062    pub fn read_only(&self, cx: &App) -> bool {
 3063        self.read_only || self.buffer.read(cx).read_only()
 3064    }
 3065
 3066    pub fn set_read_only(&mut self, read_only: bool) {
 3067        self.read_only = read_only;
 3068    }
 3069
 3070    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3071        self.use_autoclose = autoclose;
 3072    }
 3073
 3074    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3075        self.use_auto_surround = auto_surround;
 3076    }
 3077
 3078    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3079        self.auto_replace_emoji_shortcode = auto_replace;
 3080    }
 3081
 3082    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3083        self.buffer_serialization = should_serialize.then(|| {
 3084            BufferSerialization::new(
 3085                ProjectSettings::get_global(cx)
 3086                    .session
 3087                    .restore_unsaved_buffers,
 3088            )
 3089        })
 3090    }
 3091
 3092    fn should_serialize_buffer(&self) -> bool {
 3093        self.buffer_serialization.is_some()
 3094    }
 3095
 3096    pub fn toggle_edit_predictions(
 3097        &mut self,
 3098        _: &ToggleEditPrediction,
 3099        window: &mut Window,
 3100        cx: &mut Context<Self>,
 3101    ) {
 3102        if self.show_edit_predictions_override.is_some() {
 3103            self.set_show_edit_predictions(None, window, cx);
 3104        } else {
 3105            let show_edit_predictions = !self.edit_predictions_enabled();
 3106            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3107        }
 3108    }
 3109
 3110    pub fn set_show_edit_predictions(
 3111        &mut self,
 3112        show_edit_predictions: Option<bool>,
 3113        window: &mut Window,
 3114        cx: &mut Context<Self>,
 3115    ) {
 3116        self.show_edit_predictions_override = show_edit_predictions;
 3117        self.update_edit_prediction_settings(cx);
 3118
 3119        if let Some(false) = show_edit_predictions {
 3120            self.discard_edit_prediction(false, cx);
 3121        } else {
 3122            self.refresh_edit_prediction(false, true, window, cx);
 3123        }
 3124    }
 3125
 3126    fn edit_predictions_disabled_in_scope(
 3127        &self,
 3128        buffer: &Entity<Buffer>,
 3129        buffer_position: language::Anchor,
 3130        cx: &App,
 3131    ) -> bool {
 3132        let snapshot = buffer.read(cx).snapshot();
 3133        let settings = snapshot.settings_at(buffer_position, cx);
 3134
 3135        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3136            return false;
 3137        };
 3138
 3139        scope.override_name().is_some_and(|scope_name| {
 3140            settings
 3141                .edit_predictions_disabled_in
 3142                .iter()
 3143                .any(|s| s == scope_name)
 3144        })
 3145    }
 3146
 3147    pub fn set_use_modal_editing(&mut self, to: bool) {
 3148        self.use_modal_editing = to;
 3149    }
 3150
 3151    pub fn use_modal_editing(&self) -> bool {
 3152        self.use_modal_editing
 3153    }
 3154
 3155    fn selections_did_change(
 3156        &mut self,
 3157        local: bool,
 3158        old_cursor_position: &Anchor,
 3159        effects: SelectionEffects,
 3160        window: &mut Window,
 3161        cx: &mut Context<Self>,
 3162    ) {
 3163        window.invalidate_character_coordinates();
 3164
 3165        // Copy selections to primary selection buffer
 3166        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3167        if local {
 3168            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3169            let buffer_handle = self.buffer.read(cx).read(cx);
 3170
 3171            let mut text = String::new();
 3172            for (index, selection) in selections.iter().enumerate() {
 3173                let text_for_selection = buffer_handle
 3174                    .text_for_range(selection.start..selection.end)
 3175                    .collect::<String>();
 3176
 3177                text.push_str(&text_for_selection);
 3178                if index != selections.len() - 1 {
 3179                    text.push('\n');
 3180                }
 3181            }
 3182
 3183            if !text.is_empty() {
 3184                cx.write_to_primary(ClipboardItem::new_string(text));
 3185            }
 3186        }
 3187
 3188        let selection_anchors = self.selections.disjoint_anchors_arc();
 3189
 3190        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3191            self.buffer.update(cx, |buffer, cx| {
 3192                buffer.set_active_selections(
 3193                    &selection_anchors,
 3194                    self.selections.line_mode(),
 3195                    self.cursor_shape,
 3196                    cx,
 3197                )
 3198            });
 3199        }
 3200        let display_map = self
 3201            .display_map
 3202            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3203        let buffer = display_map.buffer_snapshot();
 3204        if self.selections.count() == 1 {
 3205            self.add_selections_state = None;
 3206        }
 3207        self.select_next_state = None;
 3208        self.select_prev_state = None;
 3209        self.select_syntax_node_history.try_clear();
 3210        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3211        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3212        self.take_rename(false, window, cx);
 3213
 3214        let newest_selection = self.selections.newest_anchor();
 3215        let new_cursor_position = newest_selection.head();
 3216        let selection_start = newest_selection.start;
 3217
 3218        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3219            self.push_to_nav_history(
 3220                *old_cursor_position,
 3221                Some(new_cursor_position.to_point(buffer)),
 3222                false,
 3223                effects.nav_history == Some(true),
 3224                cx,
 3225            );
 3226        }
 3227
 3228        if local {
 3229            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3230                self.register_buffer(buffer_id, cx);
 3231            }
 3232
 3233            let mut context_menu = self.context_menu.borrow_mut();
 3234            let completion_menu = match context_menu.as_ref() {
 3235                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3236                Some(CodeContextMenu::CodeActions(_)) => {
 3237                    *context_menu = None;
 3238                    None
 3239                }
 3240                None => None,
 3241            };
 3242            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3243            drop(context_menu);
 3244
 3245            if effects.completions
 3246                && let Some(completion_position) = completion_position
 3247            {
 3248                let start_offset = selection_start.to_offset(buffer);
 3249                let position_matches = start_offset == completion_position.to_offset(buffer);
 3250                let continue_showing = if position_matches {
 3251                    if self.snippet_stack.is_empty() {
 3252                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3253                            == Some(CharKind::Word)
 3254                    } else {
 3255                        // Snippet choices can be shown even when the cursor is in whitespace.
 3256                        // Dismissing the menu with actions like backspace is handled by
 3257                        // invalidation regions.
 3258                        true
 3259                    }
 3260                } else {
 3261                    false
 3262                };
 3263
 3264                if continue_showing {
 3265                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3266                } else {
 3267                    self.hide_context_menu(window, cx);
 3268                }
 3269            }
 3270
 3271            hide_hover(self, cx);
 3272
 3273            if old_cursor_position.to_display_point(&display_map).row()
 3274                != new_cursor_position.to_display_point(&display_map).row()
 3275            {
 3276                self.available_code_actions.take();
 3277            }
 3278            self.refresh_code_actions(window, cx);
 3279            self.refresh_document_highlights(cx);
 3280            refresh_linked_ranges(self, window, cx);
 3281
 3282            self.refresh_selected_text_highlights(false, window, cx);
 3283            self.refresh_matching_bracket_highlights(window, cx);
 3284            self.update_visible_edit_prediction(window, cx);
 3285            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3286            self.inline_blame_popover.take();
 3287            if self.git_blame_inline_enabled {
 3288                self.start_inline_blame_timer(window, cx);
 3289            }
 3290        }
 3291
 3292        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3293        cx.emit(EditorEvent::SelectionsChanged { local });
 3294
 3295        let selections = &self.selections.disjoint_anchors_arc();
 3296        if selections.len() == 1 {
 3297            cx.emit(SearchEvent::ActiveMatchChanged)
 3298        }
 3299        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3300            let inmemory_selections = selections
 3301                .iter()
 3302                .map(|s| {
 3303                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3304                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3305                })
 3306                .collect();
 3307            self.update_restoration_data(cx, |data| {
 3308                data.selections = inmemory_selections;
 3309            });
 3310
 3311            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3312                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3313            {
 3314                let snapshot = self.buffer().read(cx).snapshot(cx);
 3315                let selections = selections.clone();
 3316                let background_executor = cx.background_executor().clone();
 3317                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3318                self.serialize_selections = cx.background_spawn(async move {
 3319                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3320                    let db_selections = selections
 3321                        .iter()
 3322                        .map(|selection| {
 3323                            (
 3324                                selection.start.to_offset(&snapshot),
 3325                                selection.end.to_offset(&snapshot),
 3326                            )
 3327                        })
 3328                        .collect();
 3329
 3330                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3331                        .await
 3332                        .with_context(|| {
 3333                            format!(
 3334                                "persisting editor selections for editor {editor_id}, \
 3335                                workspace {workspace_id:?}"
 3336                            )
 3337                        })
 3338                        .log_err();
 3339                });
 3340            }
 3341        }
 3342
 3343        cx.notify();
 3344    }
 3345
 3346    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3347        use text::ToOffset as _;
 3348        use text::ToPoint as _;
 3349
 3350        if self.mode.is_minimap()
 3351            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3352        {
 3353            return;
 3354        }
 3355
 3356        if !self.buffer().read(cx).is_singleton() {
 3357            return;
 3358        }
 3359
 3360        let display_snapshot = self
 3361            .display_map
 3362            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3363        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3364            return;
 3365        };
 3366        let inmemory_folds = display_snapshot
 3367            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3368            .map(|fold| {
 3369                fold.range.start.text_anchor.to_point(&snapshot)
 3370                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3371            })
 3372            .collect();
 3373        self.update_restoration_data(cx, |data| {
 3374            data.folds = inmemory_folds;
 3375        });
 3376
 3377        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3378            return;
 3379        };
 3380        let background_executor = cx.background_executor().clone();
 3381        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3382        let db_folds = display_snapshot
 3383            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3384            .map(|fold| {
 3385                (
 3386                    fold.range.start.text_anchor.to_offset(&snapshot),
 3387                    fold.range.end.text_anchor.to_offset(&snapshot),
 3388                )
 3389            })
 3390            .collect();
 3391        self.serialize_folds = cx.background_spawn(async move {
 3392            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3393            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3394                .await
 3395                .with_context(|| {
 3396                    format!(
 3397                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3398                    )
 3399                })
 3400                .log_err();
 3401        });
 3402    }
 3403
 3404    pub fn sync_selections(
 3405        &mut self,
 3406        other: Entity<Editor>,
 3407        cx: &mut Context<Self>,
 3408    ) -> gpui::Subscription {
 3409        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3410        if !other_selections.is_empty() {
 3411            self.selections
 3412                .change_with(&self.display_snapshot(cx), |selections| {
 3413                    selections.select_anchors(other_selections);
 3414                });
 3415        }
 3416
 3417        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3418            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3419                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3420                if other_selections.is_empty() {
 3421                    return;
 3422                }
 3423                let snapshot = this.display_snapshot(cx);
 3424                this.selections.change_with(&snapshot, |selections| {
 3425                    selections.select_anchors(other_selections);
 3426                });
 3427            }
 3428        });
 3429
 3430        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3431            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3432                let these_selections = this.selections.disjoint_anchors().to_vec();
 3433                if these_selections.is_empty() {
 3434                    return;
 3435                }
 3436                other.update(cx, |other_editor, cx| {
 3437                    let snapshot = other_editor.display_snapshot(cx);
 3438                    other_editor
 3439                        .selections
 3440                        .change_with(&snapshot, |selections| {
 3441                            selections.select_anchors(these_selections);
 3442                        })
 3443                });
 3444            }
 3445        });
 3446
 3447        Subscription::join(other_subscription, this_subscription)
 3448    }
 3449
 3450    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3451        if self.buffer().read(cx).is_singleton() {
 3452            return;
 3453        }
 3454        let snapshot = self.buffer.read(cx).snapshot(cx);
 3455        let buffer_ids: HashSet<BufferId> = self
 3456            .selections
 3457            .disjoint_anchor_ranges()
 3458            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3459            .collect();
 3460        for buffer_id in buffer_ids {
 3461            self.unfold_buffer(buffer_id, cx);
 3462        }
 3463    }
 3464
 3465    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3466    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3467    /// effects of selection change occur at the end of the transaction.
 3468    pub fn change_selections<R>(
 3469        &mut self,
 3470        effects: SelectionEffects,
 3471        window: &mut Window,
 3472        cx: &mut Context<Self>,
 3473        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3474    ) -> R {
 3475        let snapshot = self.display_snapshot(cx);
 3476        if let Some(state) = &mut self.deferred_selection_effects_state {
 3477            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3478            state.effects.completions = effects.completions;
 3479            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3480            let (changed, result) = self.selections.change_with(&snapshot, change);
 3481            state.changed |= changed;
 3482            return result;
 3483        }
 3484        let mut state = DeferredSelectionEffectsState {
 3485            changed: false,
 3486            effects,
 3487            old_cursor_position: self.selections.newest_anchor().head(),
 3488            history_entry: SelectionHistoryEntry {
 3489                selections: self.selections.disjoint_anchors_arc(),
 3490                select_next_state: self.select_next_state.clone(),
 3491                select_prev_state: self.select_prev_state.clone(),
 3492                add_selections_state: self.add_selections_state.clone(),
 3493            },
 3494        };
 3495        let (changed, result) = self.selections.change_with(&snapshot, change);
 3496        state.changed = state.changed || changed;
 3497        if self.defer_selection_effects {
 3498            self.deferred_selection_effects_state = Some(state);
 3499        } else {
 3500            self.apply_selection_effects(state, window, cx);
 3501        }
 3502        result
 3503    }
 3504
 3505    /// Defers the effects of selection change, so that the effects of multiple calls to
 3506    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3507    /// to selection history and the state of popovers based on selection position aren't
 3508    /// erroneously updated.
 3509    pub fn with_selection_effects_deferred<R>(
 3510        &mut self,
 3511        window: &mut Window,
 3512        cx: &mut Context<Self>,
 3513        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3514    ) -> R {
 3515        let already_deferred = self.defer_selection_effects;
 3516        self.defer_selection_effects = true;
 3517        let result = update(self, window, cx);
 3518        if !already_deferred {
 3519            self.defer_selection_effects = false;
 3520            if let Some(state) = self.deferred_selection_effects_state.take() {
 3521                self.apply_selection_effects(state, window, cx);
 3522            }
 3523        }
 3524        result
 3525    }
 3526
 3527    fn apply_selection_effects(
 3528        &mut self,
 3529        state: DeferredSelectionEffectsState,
 3530        window: &mut Window,
 3531        cx: &mut Context<Self>,
 3532    ) {
 3533        if state.changed {
 3534            self.selection_history.push(state.history_entry);
 3535
 3536            if let Some(autoscroll) = state.effects.scroll {
 3537                self.request_autoscroll(autoscroll, cx);
 3538            }
 3539
 3540            let old_cursor_position = &state.old_cursor_position;
 3541
 3542            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3543
 3544            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3545                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3546            }
 3547        }
 3548    }
 3549
 3550    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3551    where
 3552        I: IntoIterator<Item = (Range<S>, T)>,
 3553        S: ToOffset,
 3554        T: Into<Arc<str>>,
 3555    {
 3556        if self.read_only(cx) {
 3557            return;
 3558        }
 3559
 3560        self.buffer
 3561            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3562    }
 3563
 3564    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3565    where
 3566        I: IntoIterator<Item = (Range<S>, T)>,
 3567        S: ToOffset,
 3568        T: Into<Arc<str>>,
 3569    {
 3570        if self.read_only(cx) {
 3571            return;
 3572        }
 3573
 3574        self.buffer.update(cx, |buffer, cx| {
 3575            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3576        });
 3577    }
 3578
 3579    pub fn edit_with_block_indent<I, S, T>(
 3580        &mut self,
 3581        edits: I,
 3582        original_indent_columns: Vec<Option<u32>>,
 3583        cx: &mut Context<Self>,
 3584    ) where
 3585        I: IntoIterator<Item = (Range<S>, T)>,
 3586        S: ToOffset,
 3587        T: Into<Arc<str>>,
 3588    {
 3589        if self.read_only(cx) {
 3590            return;
 3591        }
 3592
 3593        self.buffer.update(cx, |buffer, cx| {
 3594            buffer.edit(
 3595                edits,
 3596                Some(AutoindentMode::Block {
 3597                    original_indent_columns,
 3598                }),
 3599                cx,
 3600            )
 3601        });
 3602    }
 3603
 3604    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3605        self.hide_context_menu(window, cx);
 3606
 3607        match phase {
 3608            SelectPhase::Begin {
 3609                position,
 3610                add,
 3611                click_count,
 3612            } => self.begin_selection(position, add, click_count, window, cx),
 3613            SelectPhase::BeginColumnar {
 3614                position,
 3615                goal_column,
 3616                reset,
 3617                mode,
 3618            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3619            SelectPhase::Extend {
 3620                position,
 3621                click_count,
 3622            } => self.extend_selection(position, click_count, window, cx),
 3623            SelectPhase::Update {
 3624                position,
 3625                goal_column,
 3626                scroll_delta,
 3627            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3628            SelectPhase::End => self.end_selection(window, cx),
 3629        }
 3630    }
 3631
 3632    fn extend_selection(
 3633        &mut self,
 3634        position: DisplayPoint,
 3635        click_count: usize,
 3636        window: &mut Window,
 3637        cx: &mut Context<Self>,
 3638    ) {
 3639        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3640        let tail = self.selections.newest::<usize>(&display_map).tail();
 3641        let click_count = click_count.max(match self.selections.select_mode() {
 3642            SelectMode::Character => 1,
 3643            SelectMode::Word(_) => 2,
 3644            SelectMode::Line(_) => 3,
 3645            SelectMode::All => 4,
 3646        });
 3647        self.begin_selection(position, false, click_count, window, cx);
 3648
 3649        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3650
 3651        let current_selection = match self.selections.select_mode() {
 3652            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3653            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3654        };
 3655
 3656        let mut pending_selection = self
 3657            .selections
 3658            .pending_anchor()
 3659            .cloned()
 3660            .expect("extend_selection not called with pending selection");
 3661
 3662        if pending_selection
 3663            .start
 3664            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3665            == Ordering::Greater
 3666        {
 3667            pending_selection.start = current_selection.start;
 3668        }
 3669        if pending_selection
 3670            .end
 3671            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3672            == Ordering::Less
 3673        {
 3674            pending_selection.end = current_selection.end;
 3675            pending_selection.reversed = true;
 3676        }
 3677
 3678        let mut pending_mode = self.selections.pending_mode().unwrap();
 3679        match &mut pending_mode {
 3680            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3681            _ => {}
 3682        }
 3683
 3684        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3685            SelectionEffects::scroll(Autoscroll::fit())
 3686        } else {
 3687            SelectionEffects::no_scroll()
 3688        };
 3689
 3690        self.change_selections(effects, window, cx, |s| {
 3691            s.set_pending(pending_selection.clone(), pending_mode);
 3692            s.set_is_extending(true);
 3693        });
 3694    }
 3695
 3696    fn begin_selection(
 3697        &mut self,
 3698        position: DisplayPoint,
 3699        add: bool,
 3700        click_count: usize,
 3701        window: &mut Window,
 3702        cx: &mut Context<Self>,
 3703    ) {
 3704        if !self.focus_handle.is_focused(window) {
 3705            self.last_focused_descendant = None;
 3706            window.focus(&self.focus_handle);
 3707        }
 3708
 3709        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3710        let buffer = display_map.buffer_snapshot();
 3711        let position = display_map.clip_point(position, Bias::Left);
 3712
 3713        let start;
 3714        let end;
 3715        let mode;
 3716        let mut auto_scroll;
 3717        match click_count {
 3718            1 => {
 3719                start = buffer.anchor_before(position.to_point(&display_map));
 3720                end = start;
 3721                mode = SelectMode::Character;
 3722                auto_scroll = true;
 3723            }
 3724            2 => {
 3725                let position = display_map
 3726                    .clip_point(position, Bias::Left)
 3727                    .to_offset(&display_map, Bias::Left);
 3728                let (range, _) = buffer.surrounding_word(position, None);
 3729                start = buffer.anchor_before(range.start);
 3730                end = buffer.anchor_before(range.end);
 3731                mode = SelectMode::Word(start..end);
 3732                auto_scroll = true;
 3733            }
 3734            3 => {
 3735                let position = display_map
 3736                    .clip_point(position, Bias::Left)
 3737                    .to_point(&display_map);
 3738                let line_start = display_map.prev_line_boundary(position).0;
 3739                let next_line_start = buffer.clip_point(
 3740                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3741                    Bias::Left,
 3742                );
 3743                start = buffer.anchor_before(line_start);
 3744                end = buffer.anchor_before(next_line_start);
 3745                mode = SelectMode::Line(start..end);
 3746                auto_scroll = true;
 3747            }
 3748            _ => {
 3749                start = buffer.anchor_before(0);
 3750                end = buffer.anchor_before(buffer.len());
 3751                mode = SelectMode::All;
 3752                auto_scroll = false;
 3753            }
 3754        }
 3755        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3756
 3757        let point_to_delete: Option<usize> = {
 3758            let selected_points: Vec<Selection<Point>> =
 3759                self.selections.disjoint_in_range(start..end, &display_map);
 3760
 3761            if !add || click_count > 1 {
 3762                None
 3763            } else if !selected_points.is_empty() {
 3764                Some(selected_points[0].id)
 3765            } else {
 3766                let clicked_point_already_selected =
 3767                    self.selections.disjoint_anchors().iter().find(|selection| {
 3768                        selection.start.to_point(buffer) == start.to_point(buffer)
 3769                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3770                    });
 3771
 3772                clicked_point_already_selected.map(|selection| selection.id)
 3773            }
 3774        };
 3775
 3776        let selections_count = self.selections.count();
 3777        let effects = if auto_scroll {
 3778            SelectionEffects::default()
 3779        } else {
 3780            SelectionEffects::no_scroll()
 3781        };
 3782
 3783        self.change_selections(effects, window, cx, |s| {
 3784            if let Some(point_to_delete) = point_to_delete {
 3785                s.delete(point_to_delete);
 3786
 3787                if selections_count == 1 {
 3788                    s.set_pending_anchor_range(start..end, mode);
 3789                }
 3790            } else {
 3791                if !add {
 3792                    s.clear_disjoint();
 3793                }
 3794
 3795                s.set_pending_anchor_range(start..end, mode);
 3796            }
 3797        });
 3798    }
 3799
 3800    fn begin_columnar_selection(
 3801        &mut self,
 3802        position: DisplayPoint,
 3803        goal_column: u32,
 3804        reset: bool,
 3805        mode: ColumnarMode,
 3806        window: &mut Window,
 3807        cx: &mut Context<Self>,
 3808    ) {
 3809        if !self.focus_handle.is_focused(window) {
 3810            self.last_focused_descendant = None;
 3811            window.focus(&self.focus_handle);
 3812        }
 3813
 3814        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3815
 3816        if reset {
 3817            let pointer_position = display_map
 3818                .buffer_snapshot()
 3819                .anchor_before(position.to_point(&display_map));
 3820
 3821            self.change_selections(
 3822                SelectionEffects::scroll(Autoscroll::newest()),
 3823                window,
 3824                cx,
 3825                |s| {
 3826                    s.clear_disjoint();
 3827                    s.set_pending_anchor_range(
 3828                        pointer_position..pointer_position,
 3829                        SelectMode::Character,
 3830                    );
 3831                },
 3832            );
 3833        };
 3834
 3835        let tail = self.selections.newest::<Point>(&display_map).tail();
 3836        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3837        self.columnar_selection_state = match mode {
 3838            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3839                selection_tail: selection_anchor,
 3840                display_point: if reset {
 3841                    if position.column() != goal_column {
 3842                        Some(DisplayPoint::new(position.row(), goal_column))
 3843                    } else {
 3844                        None
 3845                    }
 3846                } else {
 3847                    None
 3848                },
 3849            }),
 3850            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3851                selection_tail: selection_anchor,
 3852            }),
 3853        };
 3854
 3855        if !reset {
 3856            self.select_columns(position, goal_column, &display_map, window, cx);
 3857        }
 3858    }
 3859
 3860    fn update_selection(
 3861        &mut self,
 3862        position: DisplayPoint,
 3863        goal_column: u32,
 3864        scroll_delta: gpui::Point<f32>,
 3865        window: &mut Window,
 3866        cx: &mut Context<Self>,
 3867    ) {
 3868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3869
 3870        if self.columnar_selection_state.is_some() {
 3871            self.select_columns(position, goal_column, &display_map, window, cx);
 3872        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3873            let buffer = display_map.buffer_snapshot();
 3874            let head;
 3875            let tail;
 3876            let mode = self.selections.pending_mode().unwrap();
 3877            match &mode {
 3878                SelectMode::Character => {
 3879                    head = position.to_point(&display_map);
 3880                    tail = pending.tail().to_point(buffer);
 3881                }
 3882                SelectMode::Word(original_range) => {
 3883                    let offset = display_map
 3884                        .clip_point(position, Bias::Left)
 3885                        .to_offset(&display_map, Bias::Left);
 3886                    let original_range = original_range.to_offset(buffer);
 3887
 3888                    let head_offset = if buffer.is_inside_word(offset, None)
 3889                        || original_range.contains(&offset)
 3890                    {
 3891                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3892                        if word_range.start < original_range.start {
 3893                            word_range.start
 3894                        } else {
 3895                            word_range.end
 3896                        }
 3897                    } else {
 3898                        offset
 3899                    };
 3900
 3901                    head = head_offset.to_point(buffer);
 3902                    if head_offset <= original_range.start {
 3903                        tail = original_range.end.to_point(buffer);
 3904                    } else {
 3905                        tail = original_range.start.to_point(buffer);
 3906                    }
 3907                }
 3908                SelectMode::Line(original_range) => {
 3909                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3910
 3911                    let position = display_map
 3912                        .clip_point(position, Bias::Left)
 3913                        .to_point(&display_map);
 3914                    let line_start = display_map.prev_line_boundary(position).0;
 3915                    let next_line_start = buffer.clip_point(
 3916                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3917                        Bias::Left,
 3918                    );
 3919
 3920                    if line_start < original_range.start {
 3921                        head = line_start
 3922                    } else {
 3923                        head = next_line_start
 3924                    }
 3925
 3926                    if head <= original_range.start {
 3927                        tail = original_range.end;
 3928                    } else {
 3929                        tail = original_range.start;
 3930                    }
 3931                }
 3932                SelectMode::All => {
 3933                    return;
 3934                }
 3935            };
 3936
 3937            if head < tail {
 3938                pending.start = buffer.anchor_before(head);
 3939                pending.end = buffer.anchor_before(tail);
 3940                pending.reversed = true;
 3941            } else {
 3942                pending.start = buffer.anchor_before(tail);
 3943                pending.end = buffer.anchor_before(head);
 3944                pending.reversed = false;
 3945            }
 3946
 3947            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3948                s.set_pending(pending.clone(), mode);
 3949            });
 3950        } else {
 3951            log::error!("update_selection dispatched with no pending selection");
 3952            return;
 3953        }
 3954
 3955        self.apply_scroll_delta(scroll_delta, window, cx);
 3956        cx.notify();
 3957    }
 3958
 3959    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3960        self.columnar_selection_state.take();
 3961        if let Some(pending_mode) = self.selections.pending_mode() {
 3962            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3963            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3964                s.select(selections);
 3965                s.clear_pending();
 3966                if s.is_extending() {
 3967                    s.set_is_extending(false);
 3968                } else {
 3969                    s.set_select_mode(pending_mode);
 3970                }
 3971            });
 3972        }
 3973    }
 3974
 3975    fn select_columns(
 3976        &mut self,
 3977        head: DisplayPoint,
 3978        goal_column: u32,
 3979        display_map: &DisplaySnapshot,
 3980        window: &mut Window,
 3981        cx: &mut Context<Self>,
 3982    ) {
 3983        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3984            return;
 3985        };
 3986
 3987        let tail = match columnar_state {
 3988            ColumnarSelectionState::FromMouse {
 3989                selection_tail,
 3990                display_point,
 3991            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3992            ColumnarSelectionState::FromSelection { selection_tail } => {
 3993                selection_tail.to_display_point(display_map)
 3994            }
 3995        };
 3996
 3997        let start_row = cmp::min(tail.row(), head.row());
 3998        let end_row = cmp::max(tail.row(), head.row());
 3999        let start_column = cmp::min(tail.column(), goal_column);
 4000        let end_column = cmp::max(tail.column(), goal_column);
 4001        let reversed = start_column < tail.column();
 4002
 4003        let selection_ranges = (start_row.0..=end_row.0)
 4004            .map(DisplayRow)
 4005            .filter_map(|row| {
 4006                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4007                    || start_column <= display_map.line_len(row))
 4008                    && !display_map.is_block_line(row)
 4009                {
 4010                    let start = display_map
 4011                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4012                        .to_point(display_map);
 4013                    let end = display_map
 4014                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4015                        .to_point(display_map);
 4016                    if reversed {
 4017                        Some(end..start)
 4018                    } else {
 4019                        Some(start..end)
 4020                    }
 4021                } else {
 4022                    None
 4023                }
 4024            })
 4025            .collect::<Vec<_>>();
 4026        if selection_ranges.is_empty() {
 4027            return;
 4028        }
 4029
 4030        let ranges = match columnar_state {
 4031            ColumnarSelectionState::FromMouse { .. } => {
 4032                let mut non_empty_ranges = selection_ranges
 4033                    .iter()
 4034                    .filter(|selection_range| selection_range.start != selection_range.end)
 4035                    .peekable();
 4036                if non_empty_ranges.peek().is_some() {
 4037                    non_empty_ranges.cloned().collect()
 4038                } else {
 4039                    selection_ranges
 4040                }
 4041            }
 4042            _ => selection_ranges,
 4043        };
 4044
 4045        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4046            s.select_ranges(ranges);
 4047        });
 4048        cx.notify();
 4049    }
 4050
 4051    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4052        self.selections
 4053            .all_adjusted(snapshot)
 4054            .iter()
 4055            .any(|selection| !selection.is_empty())
 4056    }
 4057
 4058    pub fn has_pending_nonempty_selection(&self) -> bool {
 4059        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4060            Some(Selection { start, end, .. }) => start != end,
 4061            None => false,
 4062        };
 4063
 4064        pending_nonempty_selection
 4065            || (self.columnar_selection_state.is_some()
 4066                && self.selections.disjoint_anchors().len() > 1)
 4067    }
 4068
 4069    pub fn has_pending_selection(&self) -> bool {
 4070        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4071    }
 4072
 4073    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4074        self.selection_mark_mode = false;
 4075        self.selection_drag_state = SelectionDragState::None;
 4076
 4077        if self.dismiss_menus_and_popups(true, window, cx) {
 4078            cx.notify();
 4079            return;
 4080        }
 4081        if self.clear_expanded_diff_hunks(cx) {
 4082            cx.notify();
 4083            return;
 4084        }
 4085        if self.show_git_blame_gutter {
 4086            self.show_git_blame_gutter = false;
 4087            cx.notify();
 4088            return;
 4089        }
 4090
 4091        if self.mode.is_full()
 4092            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4093        {
 4094            cx.notify();
 4095            return;
 4096        }
 4097
 4098        cx.propagate();
 4099    }
 4100
 4101    pub fn dismiss_menus_and_popups(
 4102        &mut self,
 4103        is_user_requested: bool,
 4104        window: &mut Window,
 4105        cx: &mut Context<Self>,
 4106    ) -> bool {
 4107        if self.take_rename(false, window, cx).is_some() {
 4108            return true;
 4109        }
 4110
 4111        if self.hide_blame_popover(true, cx) {
 4112            return true;
 4113        }
 4114
 4115        if hide_hover(self, cx) {
 4116            return true;
 4117        }
 4118
 4119        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4120            return true;
 4121        }
 4122
 4123        if self.hide_context_menu(window, cx).is_some() {
 4124            return true;
 4125        }
 4126
 4127        if self.mouse_context_menu.take().is_some() {
 4128            return true;
 4129        }
 4130
 4131        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4132            return true;
 4133        }
 4134
 4135        if self.snippet_stack.pop().is_some() {
 4136            return true;
 4137        }
 4138
 4139        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4140            self.dismiss_diagnostics(cx);
 4141            return true;
 4142        }
 4143
 4144        false
 4145    }
 4146
 4147    fn linked_editing_ranges_for(
 4148        &self,
 4149        selection: Range<text::Anchor>,
 4150        cx: &App,
 4151    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4152        if self.linked_edit_ranges.is_empty() {
 4153            return None;
 4154        }
 4155        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4156            selection.end.buffer_id.and_then(|end_buffer_id| {
 4157                if selection.start.buffer_id != Some(end_buffer_id) {
 4158                    return None;
 4159                }
 4160                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4161                let snapshot = buffer.read(cx).snapshot();
 4162                self.linked_edit_ranges
 4163                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4164                    .map(|ranges| (ranges, snapshot, buffer))
 4165            })?;
 4166        use text::ToOffset as TO;
 4167        // find offset from the start of current range to current cursor position
 4168        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4169
 4170        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4171        let start_difference = start_offset - start_byte_offset;
 4172        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4173        let end_difference = end_offset - start_byte_offset;
 4174        // Current range has associated linked ranges.
 4175        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4176        for range in linked_ranges.iter() {
 4177            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4178            let end_offset = start_offset + end_difference;
 4179            let start_offset = start_offset + start_difference;
 4180            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4181                continue;
 4182            }
 4183            if self.selections.disjoint_anchor_ranges().any(|s| {
 4184                if s.start.buffer_id != selection.start.buffer_id
 4185                    || s.end.buffer_id != selection.end.buffer_id
 4186                {
 4187                    return false;
 4188                }
 4189                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4190                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4191            }) {
 4192                continue;
 4193            }
 4194            let start = buffer_snapshot.anchor_after(start_offset);
 4195            let end = buffer_snapshot.anchor_after(end_offset);
 4196            linked_edits
 4197                .entry(buffer.clone())
 4198                .or_default()
 4199                .push(start..end);
 4200        }
 4201        Some(linked_edits)
 4202    }
 4203
 4204    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4205        let text: Arc<str> = text.into();
 4206
 4207        if self.read_only(cx) {
 4208            return;
 4209        }
 4210
 4211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4212
 4213        self.unfold_buffers_with_selections(cx);
 4214
 4215        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4216        let mut bracket_inserted = false;
 4217        let mut edits = Vec::new();
 4218        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4219        let mut new_selections = Vec::with_capacity(selections.len());
 4220        let mut new_autoclose_regions = Vec::new();
 4221        let snapshot = self.buffer.read(cx).read(cx);
 4222        let mut clear_linked_edit_ranges = false;
 4223
 4224        for (selection, autoclose_region) in
 4225            self.selections_with_autoclose_regions(selections, &snapshot)
 4226        {
 4227            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4228                // Determine if the inserted text matches the opening or closing
 4229                // bracket of any of this language's bracket pairs.
 4230                let mut bracket_pair = None;
 4231                let mut is_bracket_pair_start = false;
 4232                let mut is_bracket_pair_end = false;
 4233                if !text.is_empty() {
 4234                    let mut bracket_pair_matching_end = None;
 4235                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4236                    //  and they are removing the character that triggered IME popup.
 4237                    for (pair, enabled) in scope.brackets() {
 4238                        if !pair.close && !pair.surround {
 4239                            continue;
 4240                        }
 4241
 4242                        if enabled && pair.start.ends_with(text.as_ref()) {
 4243                            let prefix_len = pair.start.len() - text.len();
 4244                            let preceding_text_matches_prefix = prefix_len == 0
 4245                                || (selection.start.column >= (prefix_len as u32)
 4246                                    && snapshot.contains_str_at(
 4247                                        Point::new(
 4248                                            selection.start.row,
 4249                                            selection.start.column - (prefix_len as u32),
 4250                                        ),
 4251                                        &pair.start[..prefix_len],
 4252                                    ));
 4253                            if preceding_text_matches_prefix {
 4254                                bracket_pair = Some(pair.clone());
 4255                                is_bracket_pair_start = true;
 4256                                break;
 4257                            }
 4258                        }
 4259                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4260                        {
 4261                            // take first bracket pair matching end, but don't break in case a later bracket
 4262                            // pair matches start
 4263                            bracket_pair_matching_end = Some(pair.clone());
 4264                        }
 4265                    }
 4266                    if let Some(end) = bracket_pair_matching_end
 4267                        && bracket_pair.is_none()
 4268                    {
 4269                        bracket_pair = Some(end);
 4270                        is_bracket_pair_end = true;
 4271                    }
 4272                }
 4273
 4274                if let Some(bracket_pair) = bracket_pair {
 4275                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4276                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4277                    let auto_surround =
 4278                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4279                    if selection.is_empty() {
 4280                        if is_bracket_pair_start {
 4281                            // If the inserted text is a suffix of an opening bracket and the
 4282                            // selection is preceded by the rest of the opening bracket, then
 4283                            // insert the closing bracket.
 4284                            let following_text_allows_autoclose = snapshot
 4285                                .chars_at(selection.start)
 4286                                .next()
 4287                                .is_none_or(|c| scope.should_autoclose_before(c));
 4288
 4289                            let preceding_text_allows_autoclose = selection.start.column == 0
 4290                                || snapshot
 4291                                    .reversed_chars_at(selection.start)
 4292                                    .next()
 4293                                    .is_none_or(|c| {
 4294                                        bracket_pair.start != bracket_pair.end
 4295                                            || !snapshot
 4296                                                .char_classifier_at(selection.start)
 4297                                                .is_word(c)
 4298                                    });
 4299
 4300                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4301                                && bracket_pair.start.len() == 1
 4302                            {
 4303                                let target = bracket_pair.start.chars().next().unwrap();
 4304                                let current_line_count = snapshot
 4305                                    .reversed_chars_at(selection.start)
 4306                                    .take_while(|&c| c != '\n')
 4307                                    .filter(|&c| c == target)
 4308                                    .count();
 4309                                current_line_count % 2 == 1
 4310                            } else {
 4311                                false
 4312                            };
 4313
 4314                            if autoclose
 4315                                && bracket_pair.close
 4316                                && following_text_allows_autoclose
 4317                                && preceding_text_allows_autoclose
 4318                                && !is_closing_quote
 4319                            {
 4320                                let anchor = snapshot.anchor_before(selection.end);
 4321                                new_selections.push((selection.map(|_| anchor), text.len()));
 4322                                new_autoclose_regions.push((
 4323                                    anchor,
 4324                                    text.len(),
 4325                                    selection.id,
 4326                                    bracket_pair.clone(),
 4327                                ));
 4328                                edits.push((
 4329                                    selection.range(),
 4330                                    format!("{}{}", text, bracket_pair.end).into(),
 4331                                ));
 4332                                bracket_inserted = true;
 4333                                continue;
 4334                            }
 4335                        }
 4336
 4337                        if let Some(region) = autoclose_region {
 4338                            // If the selection is followed by an auto-inserted closing bracket,
 4339                            // then don't insert that closing bracket again; just move the selection
 4340                            // past the closing bracket.
 4341                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4342                                && text.as_ref() == region.pair.end.as_str()
 4343                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4344                            if should_skip {
 4345                                let anchor = snapshot.anchor_after(selection.end);
 4346                                new_selections
 4347                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4348                                continue;
 4349                            }
 4350                        }
 4351
 4352                        let always_treat_brackets_as_autoclosed = snapshot
 4353                            .language_settings_at(selection.start, cx)
 4354                            .always_treat_brackets_as_autoclosed;
 4355                        if always_treat_brackets_as_autoclosed
 4356                            && is_bracket_pair_end
 4357                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4358                        {
 4359                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4360                            // and the inserted text is a closing bracket and the selection is followed
 4361                            // by the closing bracket then move the selection past the closing bracket.
 4362                            let anchor = snapshot.anchor_after(selection.end);
 4363                            new_selections.push((selection.map(|_| anchor), text.len()));
 4364                            continue;
 4365                        }
 4366                    }
 4367                    // If an opening bracket is 1 character long and is typed while
 4368                    // text is selected, then surround that text with the bracket pair.
 4369                    else if auto_surround
 4370                        && bracket_pair.surround
 4371                        && is_bracket_pair_start
 4372                        && bracket_pair.start.chars().count() == 1
 4373                    {
 4374                        edits.push((selection.start..selection.start, text.clone()));
 4375                        edits.push((
 4376                            selection.end..selection.end,
 4377                            bracket_pair.end.as_str().into(),
 4378                        ));
 4379                        bracket_inserted = true;
 4380                        new_selections.push((
 4381                            Selection {
 4382                                id: selection.id,
 4383                                start: snapshot.anchor_after(selection.start),
 4384                                end: snapshot.anchor_before(selection.end),
 4385                                reversed: selection.reversed,
 4386                                goal: selection.goal,
 4387                            },
 4388                            0,
 4389                        ));
 4390                        continue;
 4391                    }
 4392                }
 4393            }
 4394
 4395            if self.auto_replace_emoji_shortcode
 4396                && selection.is_empty()
 4397                && text.as_ref().ends_with(':')
 4398                && let Some(possible_emoji_short_code) =
 4399                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4400                && !possible_emoji_short_code.is_empty()
 4401                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4402            {
 4403                let emoji_shortcode_start = Point::new(
 4404                    selection.start.row,
 4405                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4406                );
 4407
 4408                // Remove shortcode from buffer
 4409                edits.push((
 4410                    emoji_shortcode_start..selection.start,
 4411                    "".to_string().into(),
 4412                ));
 4413                new_selections.push((
 4414                    Selection {
 4415                        id: selection.id,
 4416                        start: snapshot.anchor_after(emoji_shortcode_start),
 4417                        end: snapshot.anchor_before(selection.start),
 4418                        reversed: selection.reversed,
 4419                        goal: selection.goal,
 4420                    },
 4421                    0,
 4422                ));
 4423
 4424                // Insert emoji
 4425                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4426                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4427                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4428
 4429                continue;
 4430            }
 4431
 4432            // If not handling any auto-close operation, then just replace the selected
 4433            // text with the given input and move the selection to the end of the
 4434            // newly inserted text.
 4435            let anchor = snapshot.anchor_after(selection.end);
 4436            if !self.linked_edit_ranges.is_empty() {
 4437                let start_anchor = snapshot.anchor_before(selection.start);
 4438
 4439                let is_word_char = text.chars().next().is_none_or(|char| {
 4440                    let classifier = snapshot
 4441                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4442                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4443                    classifier.is_word(char)
 4444                });
 4445
 4446                if is_word_char {
 4447                    if let Some(ranges) = self
 4448                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4449                    {
 4450                        for (buffer, edits) in ranges {
 4451                            linked_edits
 4452                                .entry(buffer.clone())
 4453                                .or_default()
 4454                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4455                        }
 4456                    }
 4457                } else {
 4458                    clear_linked_edit_ranges = true;
 4459                }
 4460            }
 4461
 4462            new_selections.push((selection.map(|_| anchor), 0));
 4463            edits.push((selection.start..selection.end, text.clone()));
 4464        }
 4465
 4466        drop(snapshot);
 4467
 4468        self.transact(window, cx, |this, window, cx| {
 4469            if clear_linked_edit_ranges {
 4470                this.linked_edit_ranges.clear();
 4471            }
 4472            let initial_buffer_versions =
 4473                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4474
 4475            this.buffer.update(cx, |buffer, cx| {
 4476                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4477            });
 4478            for (buffer, edits) in linked_edits {
 4479                buffer.update(cx, |buffer, cx| {
 4480                    let snapshot = buffer.snapshot();
 4481                    let edits = edits
 4482                        .into_iter()
 4483                        .map(|(range, text)| {
 4484                            use text::ToPoint as TP;
 4485                            let end_point = TP::to_point(&range.end, &snapshot);
 4486                            let start_point = TP::to_point(&range.start, &snapshot);
 4487                            (start_point..end_point, text)
 4488                        })
 4489                        .sorted_by_key(|(range, _)| range.start);
 4490                    buffer.edit(edits, None, cx);
 4491                })
 4492            }
 4493            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4494            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4495            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4496            let new_selections =
 4497                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4498                    .zip(new_selection_deltas)
 4499                    .map(|(selection, delta)| Selection {
 4500                        id: selection.id,
 4501                        start: selection.start + delta,
 4502                        end: selection.end + delta,
 4503                        reversed: selection.reversed,
 4504                        goal: SelectionGoal::None,
 4505                    })
 4506                    .collect::<Vec<_>>();
 4507
 4508            let mut i = 0;
 4509            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4510                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4511                let start = map.buffer_snapshot().anchor_before(position);
 4512                let end = map.buffer_snapshot().anchor_after(position);
 4513                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4514                    match existing_state
 4515                        .range
 4516                        .start
 4517                        .cmp(&start, map.buffer_snapshot())
 4518                    {
 4519                        Ordering::Less => i += 1,
 4520                        Ordering::Greater => break,
 4521                        Ordering::Equal => {
 4522                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4523                                Ordering::Less => i += 1,
 4524                                Ordering::Equal => break,
 4525                                Ordering::Greater => break,
 4526                            }
 4527                        }
 4528                    }
 4529                }
 4530                this.autoclose_regions.insert(
 4531                    i,
 4532                    AutocloseRegion {
 4533                        selection_id,
 4534                        range: start..end,
 4535                        pair,
 4536                    },
 4537                );
 4538            }
 4539
 4540            let had_active_edit_prediction = this.has_active_edit_prediction();
 4541            this.change_selections(
 4542                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4543                window,
 4544                cx,
 4545                |s| s.select(new_selections),
 4546            );
 4547
 4548            if !bracket_inserted
 4549                && let Some(on_type_format_task) =
 4550                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4551            {
 4552                on_type_format_task.detach_and_log_err(cx);
 4553            }
 4554
 4555            let editor_settings = EditorSettings::get_global(cx);
 4556            if bracket_inserted
 4557                && (editor_settings.auto_signature_help
 4558                    || editor_settings.show_signature_help_after_edits)
 4559            {
 4560                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4561            }
 4562
 4563            let trigger_in_words =
 4564                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4565            if this.hard_wrap.is_some() {
 4566                let latest: Range<Point> = this.selections.newest(&map).range();
 4567                if latest.is_empty()
 4568                    && this
 4569                        .buffer()
 4570                        .read(cx)
 4571                        .snapshot(cx)
 4572                        .line_len(MultiBufferRow(latest.start.row))
 4573                        == latest.start.column
 4574                {
 4575                    this.rewrap_impl(
 4576                        RewrapOptions {
 4577                            override_language_settings: true,
 4578                            preserve_existing_whitespace: true,
 4579                        },
 4580                        cx,
 4581                    )
 4582                }
 4583            }
 4584            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4585            refresh_linked_ranges(this, window, cx);
 4586            this.refresh_edit_prediction(true, false, window, cx);
 4587            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4588        });
 4589    }
 4590
 4591    fn find_possible_emoji_shortcode_at_position(
 4592        snapshot: &MultiBufferSnapshot,
 4593        position: Point,
 4594    ) -> Option<String> {
 4595        let mut chars = Vec::new();
 4596        let mut found_colon = false;
 4597        for char in snapshot.reversed_chars_at(position).take(100) {
 4598            // Found a possible emoji shortcode in the middle of the buffer
 4599            if found_colon {
 4600                if char.is_whitespace() {
 4601                    chars.reverse();
 4602                    return Some(chars.iter().collect());
 4603                }
 4604                // If the previous character is not a whitespace, we are in the middle of a word
 4605                // and we only want to complete the shortcode if the word is made up of other emojis
 4606                let mut containing_word = String::new();
 4607                for ch in snapshot
 4608                    .reversed_chars_at(position)
 4609                    .skip(chars.len() + 1)
 4610                    .take(100)
 4611                {
 4612                    if ch.is_whitespace() {
 4613                        break;
 4614                    }
 4615                    containing_word.push(ch);
 4616                }
 4617                let containing_word = containing_word.chars().rev().collect::<String>();
 4618                if util::word_consists_of_emojis(containing_word.as_str()) {
 4619                    chars.reverse();
 4620                    return Some(chars.iter().collect());
 4621                }
 4622            }
 4623
 4624            if char.is_whitespace() || !char.is_ascii() {
 4625                return None;
 4626            }
 4627            if char == ':' {
 4628                found_colon = true;
 4629            } else {
 4630                chars.push(char);
 4631            }
 4632        }
 4633        // Found a possible emoji shortcode at the beginning of the buffer
 4634        chars.reverse();
 4635        Some(chars.iter().collect())
 4636    }
 4637
 4638    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4640        self.transact(window, cx, |this, window, cx| {
 4641            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4642                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4643                let multi_buffer = this.buffer.read(cx);
 4644                let buffer = multi_buffer.snapshot(cx);
 4645                selections
 4646                    .iter()
 4647                    .map(|selection| {
 4648                        let start_point = selection.start.to_point(&buffer);
 4649                        let mut existing_indent =
 4650                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4651                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4652                        let start = selection.start;
 4653                        let end = selection.end;
 4654                        let selection_is_empty = start == end;
 4655                        let language_scope = buffer.language_scope_at(start);
 4656                        let (
 4657                            comment_delimiter,
 4658                            doc_delimiter,
 4659                            insert_extra_newline,
 4660                            indent_on_newline,
 4661                            indent_on_extra_newline,
 4662                        ) = if let Some(language) = &language_scope {
 4663                            let mut insert_extra_newline =
 4664                                insert_extra_newline_brackets(&buffer, start..end, language)
 4665                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4666
 4667                            // Comment extension on newline is allowed only for cursor selections
 4668                            let comment_delimiter = maybe!({
 4669                                if !selection_is_empty {
 4670                                    return None;
 4671                                }
 4672
 4673                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4674                                    return None;
 4675                                }
 4676
 4677                                let delimiters = language.line_comment_prefixes();
 4678                                let max_len_of_delimiter =
 4679                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4680                                let (snapshot, range) =
 4681                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4682
 4683                                let num_of_whitespaces = snapshot
 4684                                    .chars_for_range(range.clone())
 4685                                    .take_while(|c| c.is_whitespace())
 4686                                    .count();
 4687                                let comment_candidate = snapshot
 4688                                    .chars_for_range(range.clone())
 4689                                    .skip(num_of_whitespaces)
 4690                                    .take(max_len_of_delimiter)
 4691                                    .collect::<String>();
 4692                                let (delimiter, trimmed_len) = delimiters
 4693                                    .iter()
 4694                                    .filter_map(|delimiter| {
 4695                                        let prefix = delimiter.trim_end();
 4696                                        if comment_candidate.starts_with(prefix) {
 4697                                            Some((delimiter, prefix.len()))
 4698                                        } else {
 4699                                            None
 4700                                        }
 4701                                    })
 4702                                    .max_by_key(|(_, len)| *len)?;
 4703
 4704                                if let Some(BlockCommentConfig {
 4705                                    start: block_start, ..
 4706                                }) = language.block_comment()
 4707                                {
 4708                                    let block_start_trimmed = block_start.trim_end();
 4709                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4710                                        let line_content = snapshot
 4711                                            .chars_for_range(range)
 4712                                            .skip(num_of_whitespaces)
 4713                                            .take(block_start_trimmed.len())
 4714                                            .collect::<String>();
 4715
 4716                                        if line_content.starts_with(block_start_trimmed) {
 4717                                            return None;
 4718                                        }
 4719                                    }
 4720                                }
 4721
 4722                                let cursor_is_placed_after_comment_marker =
 4723                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4724                                if cursor_is_placed_after_comment_marker {
 4725                                    Some(delimiter.clone())
 4726                                } else {
 4727                                    None
 4728                                }
 4729                            });
 4730
 4731                            let mut indent_on_newline = IndentSize::spaces(0);
 4732                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4733
 4734                            let doc_delimiter = maybe!({
 4735                                if !selection_is_empty {
 4736                                    return None;
 4737                                }
 4738
 4739                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4740                                    return None;
 4741                                }
 4742
 4743                                let BlockCommentConfig {
 4744                                    start: start_tag,
 4745                                    end: end_tag,
 4746                                    prefix: delimiter,
 4747                                    tab_size: len,
 4748                                } = language.documentation_comment()?;
 4749                                let is_within_block_comment = buffer
 4750                                    .language_scope_at(start_point)
 4751                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4752                                if !is_within_block_comment {
 4753                                    return None;
 4754                                }
 4755
 4756                                let (snapshot, range) =
 4757                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4758
 4759                                let num_of_whitespaces = snapshot
 4760                                    .chars_for_range(range.clone())
 4761                                    .take_while(|c| c.is_whitespace())
 4762                                    .count();
 4763
 4764                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4765                                let column = start_point.column;
 4766                                let cursor_is_after_start_tag = {
 4767                                    let start_tag_len = start_tag.len();
 4768                                    let start_tag_line = snapshot
 4769                                        .chars_for_range(range.clone())
 4770                                        .skip(num_of_whitespaces)
 4771                                        .take(start_tag_len)
 4772                                        .collect::<String>();
 4773                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4774                                        num_of_whitespaces + start_tag_len <= column as usize
 4775                                    } else {
 4776                                        false
 4777                                    }
 4778                                };
 4779
 4780                                let cursor_is_after_delimiter = {
 4781                                    let delimiter_trim = delimiter.trim_end();
 4782                                    let delimiter_line = snapshot
 4783                                        .chars_for_range(range.clone())
 4784                                        .skip(num_of_whitespaces)
 4785                                        .take(delimiter_trim.len())
 4786                                        .collect::<String>();
 4787                                    if delimiter_line.starts_with(delimiter_trim) {
 4788                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4789                                    } else {
 4790                                        false
 4791                                    }
 4792                                };
 4793
 4794                                let cursor_is_before_end_tag_if_exists = {
 4795                                    let mut char_position = 0u32;
 4796                                    let mut end_tag_offset = None;
 4797
 4798                                    'outer: for chunk in snapshot.text_for_range(range) {
 4799                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4800                                            let chars_before_match =
 4801                                                chunk[..byte_pos].chars().count() as u32;
 4802                                            end_tag_offset =
 4803                                                Some(char_position + chars_before_match);
 4804                                            break 'outer;
 4805                                        }
 4806                                        char_position += chunk.chars().count() as u32;
 4807                                    }
 4808
 4809                                    if let Some(end_tag_offset) = end_tag_offset {
 4810                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4811                                        if cursor_is_after_start_tag {
 4812                                            if cursor_is_before_end_tag {
 4813                                                insert_extra_newline = true;
 4814                                            }
 4815                                            let cursor_is_at_start_of_end_tag =
 4816                                                column == end_tag_offset;
 4817                                            if cursor_is_at_start_of_end_tag {
 4818                                                indent_on_extra_newline.len = *len;
 4819                                            }
 4820                                        }
 4821                                        cursor_is_before_end_tag
 4822                                    } else {
 4823                                        true
 4824                                    }
 4825                                };
 4826
 4827                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4828                                    && cursor_is_before_end_tag_if_exists
 4829                                {
 4830                                    if cursor_is_after_start_tag {
 4831                                        indent_on_newline.len = *len;
 4832                                    }
 4833                                    Some(delimiter.clone())
 4834                                } else {
 4835                                    None
 4836                                }
 4837                            });
 4838
 4839                            (
 4840                                comment_delimiter,
 4841                                doc_delimiter,
 4842                                insert_extra_newline,
 4843                                indent_on_newline,
 4844                                indent_on_extra_newline,
 4845                            )
 4846                        } else {
 4847                            (
 4848                                None,
 4849                                None,
 4850                                false,
 4851                                IndentSize::default(),
 4852                                IndentSize::default(),
 4853                            )
 4854                        };
 4855
 4856                        let prevent_auto_indent = doc_delimiter.is_some();
 4857                        let delimiter = comment_delimiter.or(doc_delimiter);
 4858
 4859                        let capacity_for_delimiter =
 4860                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4861                        let mut new_text = String::with_capacity(
 4862                            1 + capacity_for_delimiter
 4863                                + existing_indent.len as usize
 4864                                + indent_on_newline.len as usize
 4865                                + indent_on_extra_newline.len as usize,
 4866                        );
 4867                        new_text.push('\n');
 4868                        new_text.extend(existing_indent.chars());
 4869                        new_text.extend(indent_on_newline.chars());
 4870
 4871                        if let Some(delimiter) = &delimiter {
 4872                            new_text.push_str(delimiter);
 4873                        }
 4874
 4875                        if insert_extra_newline {
 4876                            new_text.push('\n');
 4877                            new_text.extend(existing_indent.chars());
 4878                            new_text.extend(indent_on_extra_newline.chars());
 4879                        }
 4880
 4881                        let anchor = buffer.anchor_after(end);
 4882                        let new_selection = selection.map(|_| anchor);
 4883                        (
 4884                            ((start..end, new_text), prevent_auto_indent),
 4885                            (insert_extra_newline, new_selection),
 4886                        )
 4887                    })
 4888                    .unzip()
 4889            };
 4890
 4891            let mut auto_indent_edits = Vec::new();
 4892            let mut edits = Vec::new();
 4893            for (edit, prevent_auto_indent) in edits_with_flags {
 4894                if prevent_auto_indent {
 4895                    edits.push(edit);
 4896                } else {
 4897                    auto_indent_edits.push(edit);
 4898                }
 4899            }
 4900            if !edits.is_empty() {
 4901                this.edit(edits, cx);
 4902            }
 4903            if !auto_indent_edits.is_empty() {
 4904                this.edit_with_autoindent(auto_indent_edits, cx);
 4905            }
 4906
 4907            let buffer = this.buffer.read(cx).snapshot(cx);
 4908            let new_selections = selection_info
 4909                .into_iter()
 4910                .map(|(extra_newline_inserted, new_selection)| {
 4911                    let mut cursor = new_selection.end.to_point(&buffer);
 4912                    if extra_newline_inserted {
 4913                        cursor.row -= 1;
 4914                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4915                    }
 4916                    new_selection.map(|_| cursor)
 4917                })
 4918                .collect();
 4919
 4920            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4921            this.refresh_edit_prediction(true, false, window, cx);
 4922        });
 4923    }
 4924
 4925    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4927
 4928        let buffer = self.buffer.read(cx);
 4929        let snapshot = buffer.snapshot(cx);
 4930
 4931        let mut edits = Vec::new();
 4932        let mut rows = Vec::new();
 4933
 4934        for (rows_inserted, selection) in self
 4935            .selections
 4936            .all_adjusted(&self.display_snapshot(cx))
 4937            .into_iter()
 4938            .enumerate()
 4939        {
 4940            let cursor = selection.head();
 4941            let row = cursor.row;
 4942
 4943            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4944
 4945            let newline = "\n".to_string();
 4946            edits.push((start_of_line..start_of_line, newline));
 4947
 4948            rows.push(row + rows_inserted as u32);
 4949        }
 4950
 4951        self.transact(window, cx, |editor, window, cx| {
 4952            editor.edit(edits, cx);
 4953
 4954            editor.change_selections(Default::default(), window, cx, |s| {
 4955                let mut index = 0;
 4956                s.move_cursors_with(|map, _, _| {
 4957                    let row = rows[index];
 4958                    index += 1;
 4959
 4960                    let point = Point::new(row, 0);
 4961                    let boundary = map.next_line_boundary(point).1;
 4962                    let clipped = map.clip_point(boundary, Bias::Left);
 4963
 4964                    (clipped, SelectionGoal::None)
 4965                });
 4966            });
 4967
 4968            let mut indent_edits = Vec::new();
 4969            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4970            for row in rows {
 4971                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4972                for (row, indent) in indents {
 4973                    if indent.len == 0 {
 4974                        continue;
 4975                    }
 4976
 4977                    let text = match indent.kind {
 4978                        IndentKind::Space => " ".repeat(indent.len as usize),
 4979                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4980                    };
 4981                    let point = Point::new(row.0, 0);
 4982                    indent_edits.push((point..point, text));
 4983                }
 4984            }
 4985            editor.edit(indent_edits, cx);
 4986        });
 4987    }
 4988
 4989    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4990        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4991
 4992        let buffer = self.buffer.read(cx);
 4993        let snapshot = buffer.snapshot(cx);
 4994
 4995        let mut edits = Vec::new();
 4996        let mut rows = Vec::new();
 4997        let mut rows_inserted = 0;
 4998
 4999        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5000            let cursor = selection.head();
 5001            let row = cursor.row;
 5002
 5003            let point = Point::new(row + 1, 0);
 5004            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5005
 5006            let newline = "\n".to_string();
 5007            edits.push((start_of_line..start_of_line, newline));
 5008
 5009            rows_inserted += 1;
 5010            rows.push(row + rows_inserted);
 5011        }
 5012
 5013        self.transact(window, cx, |editor, window, cx| {
 5014            editor.edit(edits, cx);
 5015
 5016            editor.change_selections(Default::default(), window, cx, |s| {
 5017                let mut index = 0;
 5018                s.move_cursors_with(|map, _, _| {
 5019                    let row = rows[index];
 5020                    index += 1;
 5021
 5022                    let point = Point::new(row, 0);
 5023                    let boundary = map.next_line_boundary(point).1;
 5024                    let clipped = map.clip_point(boundary, Bias::Left);
 5025
 5026                    (clipped, SelectionGoal::None)
 5027                });
 5028            });
 5029
 5030            let mut indent_edits = Vec::new();
 5031            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5032            for row in rows {
 5033                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5034                for (row, indent) in indents {
 5035                    if indent.len == 0 {
 5036                        continue;
 5037                    }
 5038
 5039                    let text = match indent.kind {
 5040                        IndentKind::Space => " ".repeat(indent.len as usize),
 5041                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5042                    };
 5043                    let point = Point::new(row.0, 0);
 5044                    indent_edits.push((point..point, text));
 5045                }
 5046            }
 5047            editor.edit(indent_edits, cx);
 5048        });
 5049    }
 5050
 5051    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5052        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5053            original_indent_columns: Vec::new(),
 5054        });
 5055        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5056    }
 5057
 5058    fn insert_with_autoindent_mode(
 5059        &mut self,
 5060        text: &str,
 5061        autoindent_mode: Option<AutoindentMode>,
 5062        window: &mut Window,
 5063        cx: &mut Context<Self>,
 5064    ) {
 5065        if self.read_only(cx) {
 5066            return;
 5067        }
 5068
 5069        let text: Arc<str> = text.into();
 5070        self.transact(window, cx, |this, window, cx| {
 5071            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5072            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5073                let anchors = {
 5074                    let snapshot = buffer.read(cx);
 5075                    old_selections
 5076                        .iter()
 5077                        .map(|s| {
 5078                            let anchor = snapshot.anchor_after(s.head());
 5079                            s.map(|_| anchor)
 5080                        })
 5081                        .collect::<Vec<_>>()
 5082                };
 5083                buffer.edit(
 5084                    old_selections
 5085                        .iter()
 5086                        .map(|s| (s.start..s.end, text.clone())),
 5087                    autoindent_mode,
 5088                    cx,
 5089                );
 5090                anchors
 5091            });
 5092
 5093            this.change_selections(Default::default(), window, cx, |s| {
 5094                s.select_anchors(selection_anchors);
 5095            });
 5096
 5097            cx.notify();
 5098        });
 5099    }
 5100
 5101    fn trigger_completion_on_input(
 5102        &mut self,
 5103        text: &str,
 5104        trigger_in_words: bool,
 5105        window: &mut Window,
 5106        cx: &mut Context<Self>,
 5107    ) {
 5108        let completions_source = self
 5109            .context_menu
 5110            .borrow()
 5111            .as_ref()
 5112            .and_then(|menu| match menu {
 5113                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5114                CodeContextMenu::CodeActions(_) => None,
 5115            });
 5116
 5117        match completions_source {
 5118            Some(CompletionsMenuSource::Words { .. }) => {
 5119                self.open_or_update_completions_menu(
 5120                    Some(CompletionsMenuSource::Words {
 5121                        ignore_threshold: false,
 5122                    }),
 5123                    None,
 5124                    trigger_in_words,
 5125                    window,
 5126                    cx,
 5127                );
 5128            }
 5129            _ => self.open_or_update_completions_menu(
 5130                None,
 5131                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5132                true,
 5133                window,
 5134                cx,
 5135            ),
 5136        }
 5137    }
 5138
 5139    /// If any empty selections is touching the start of its innermost containing autoclose
 5140    /// region, expand it to select the brackets.
 5141    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5142        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5143        let buffer = self.buffer.read(cx).read(cx);
 5144        let new_selections = self
 5145            .selections_with_autoclose_regions(selections, &buffer)
 5146            .map(|(mut selection, region)| {
 5147                if !selection.is_empty() {
 5148                    return selection;
 5149                }
 5150
 5151                if let Some(region) = region {
 5152                    let mut range = region.range.to_offset(&buffer);
 5153                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5154                        range.start -= region.pair.start.len();
 5155                        if buffer.contains_str_at(range.start, &region.pair.start)
 5156                            && buffer.contains_str_at(range.end, &region.pair.end)
 5157                        {
 5158                            range.end += region.pair.end.len();
 5159                            selection.start = range.start;
 5160                            selection.end = range.end;
 5161
 5162                            return selection;
 5163                        }
 5164                    }
 5165                }
 5166
 5167                let always_treat_brackets_as_autoclosed = buffer
 5168                    .language_settings_at(selection.start, cx)
 5169                    .always_treat_brackets_as_autoclosed;
 5170
 5171                if !always_treat_brackets_as_autoclosed {
 5172                    return selection;
 5173                }
 5174
 5175                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5176                    for (pair, enabled) in scope.brackets() {
 5177                        if !enabled || !pair.close {
 5178                            continue;
 5179                        }
 5180
 5181                        if buffer.contains_str_at(selection.start, &pair.end) {
 5182                            let pair_start_len = pair.start.len();
 5183                            if buffer.contains_str_at(
 5184                                selection.start.saturating_sub(pair_start_len),
 5185                                &pair.start,
 5186                            ) {
 5187                                selection.start -= pair_start_len;
 5188                                selection.end += pair.end.len();
 5189
 5190                                return selection;
 5191                            }
 5192                        }
 5193                    }
 5194                }
 5195
 5196                selection
 5197            })
 5198            .collect();
 5199
 5200        drop(buffer);
 5201        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5202            selections.select(new_selections)
 5203        });
 5204    }
 5205
 5206    /// Iterate the given selections, and for each one, find the smallest surrounding
 5207    /// autoclose region. This uses the ordering of the selections and the autoclose
 5208    /// regions to avoid repeated comparisons.
 5209    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5210        &'a self,
 5211        selections: impl IntoIterator<Item = Selection<D>>,
 5212        buffer: &'a MultiBufferSnapshot,
 5213    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5214        let mut i = 0;
 5215        let mut regions = self.autoclose_regions.as_slice();
 5216        selections.into_iter().map(move |selection| {
 5217            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5218
 5219            let mut enclosing = None;
 5220            while let Some(pair_state) = regions.get(i) {
 5221                if pair_state.range.end.to_offset(buffer) < range.start {
 5222                    regions = &regions[i + 1..];
 5223                    i = 0;
 5224                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5225                    break;
 5226                } else {
 5227                    if pair_state.selection_id == selection.id {
 5228                        enclosing = Some(pair_state);
 5229                    }
 5230                    i += 1;
 5231                }
 5232            }
 5233
 5234            (selection, enclosing)
 5235        })
 5236    }
 5237
 5238    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5239    fn invalidate_autoclose_regions(
 5240        &mut self,
 5241        mut selections: &[Selection<Anchor>],
 5242        buffer: &MultiBufferSnapshot,
 5243    ) {
 5244        self.autoclose_regions.retain(|state| {
 5245            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5246                return false;
 5247            }
 5248
 5249            let mut i = 0;
 5250            while let Some(selection) = selections.get(i) {
 5251                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5252                    selections = &selections[1..];
 5253                    continue;
 5254                }
 5255                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5256                    break;
 5257                }
 5258                if selection.id == state.selection_id {
 5259                    return true;
 5260                } else {
 5261                    i += 1;
 5262                }
 5263            }
 5264            false
 5265        });
 5266    }
 5267
 5268    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5269        let offset = position.to_offset(buffer);
 5270        let (word_range, kind) =
 5271            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5272        if offset > word_range.start && kind == Some(CharKind::Word) {
 5273            Some(
 5274                buffer
 5275                    .text_for_range(word_range.start..offset)
 5276                    .collect::<String>(),
 5277            )
 5278        } else {
 5279            None
 5280        }
 5281    }
 5282
 5283    pub fn visible_excerpts(
 5284        &self,
 5285        cx: &mut Context<Editor>,
 5286    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5287        let Some(project) = self.project() else {
 5288            return HashMap::default();
 5289        };
 5290        let project = project.read(cx);
 5291        let multi_buffer = self.buffer().read(cx);
 5292        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5293        let multi_buffer_visible_start = self
 5294            .scroll_manager
 5295            .anchor()
 5296            .anchor
 5297            .to_point(&multi_buffer_snapshot);
 5298        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5299            multi_buffer_visible_start
 5300                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5301            Bias::Left,
 5302        );
 5303        multi_buffer_snapshot
 5304            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5305            .into_iter()
 5306            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5307            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5308                let buffer_file = project::File::from_dyn(buffer.file())?;
 5309                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5310                let worktree_entry = buffer_worktree
 5311                    .read(cx)
 5312                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5313                if worktree_entry.is_ignored {
 5314                    None
 5315                } else {
 5316                    Some((
 5317                        excerpt_id,
 5318                        (
 5319                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5320                            buffer.version().clone(),
 5321                            excerpt_visible_range,
 5322                        ),
 5323                    ))
 5324                }
 5325            })
 5326            .collect()
 5327    }
 5328
 5329    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5330        TextLayoutDetails {
 5331            text_system: window.text_system().clone(),
 5332            editor_style: self.style.clone().unwrap(),
 5333            rem_size: window.rem_size(),
 5334            scroll_anchor: self.scroll_manager.anchor(),
 5335            visible_rows: self.visible_line_count(),
 5336            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5337        }
 5338    }
 5339
 5340    fn trigger_on_type_formatting(
 5341        &self,
 5342        input: String,
 5343        window: &mut Window,
 5344        cx: &mut Context<Self>,
 5345    ) -> Option<Task<Result<()>>> {
 5346        if input.len() != 1 {
 5347            return None;
 5348        }
 5349
 5350        let project = self.project()?;
 5351        let position = self.selections.newest_anchor().head();
 5352        let (buffer, buffer_position) = self
 5353            .buffer
 5354            .read(cx)
 5355            .text_anchor_for_position(position, cx)?;
 5356
 5357        let settings = language_settings::language_settings(
 5358            buffer
 5359                .read(cx)
 5360                .language_at(buffer_position)
 5361                .map(|l| l.name()),
 5362            buffer.read(cx).file(),
 5363            cx,
 5364        );
 5365        if !settings.use_on_type_format {
 5366            return None;
 5367        }
 5368
 5369        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5370        // hence we do LSP request & edit on host side only — add formats to host's history.
 5371        let push_to_lsp_host_history = true;
 5372        // If this is not the host, append its history with new edits.
 5373        let push_to_client_history = project.read(cx).is_via_collab();
 5374
 5375        let on_type_formatting = project.update(cx, |project, cx| {
 5376            project.on_type_format(
 5377                buffer.clone(),
 5378                buffer_position,
 5379                input,
 5380                push_to_lsp_host_history,
 5381                cx,
 5382            )
 5383        });
 5384        Some(cx.spawn_in(window, async move |editor, cx| {
 5385            if let Some(transaction) = on_type_formatting.await? {
 5386                if push_to_client_history {
 5387                    buffer
 5388                        .update(cx, |buffer, _| {
 5389                            buffer.push_transaction(transaction, Instant::now());
 5390                            buffer.finalize_last_transaction();
 5391                        })
 5392                        .ok();
 5393                }
 5394                editor.update(cx, |editor, cx| {
 5395                    editor.refresh_document_highlights(cx);
 5396                })?;
 5397            }
 5398            Ok(())
 5399        }))
 5400    }
 5401
 5402    pub fn show_word_completions(
 5403        &mut self,
 5404        _: &ShowWordCompletions,
 5405        window: &mut Window,
 5406        cx: &mut Context<Self>,
 5407    ) {
 5408        self.open_or_update_completions_menu(
 5409            Some(CompletionsMenuSource::Words {
 5410                ignore_threshold: true,
 5411            }),
 5412            None,
 5413            false,
 5414            window,
 5415            cx,
 5416        );
 5417    }
 5418
 5419    pub fn show_completions(
 5420        &mut self,
 5421        _: &ShowCompletions,
 5422        window: &mut Window,
 5423        cx: &mut Context<Self>,
 5424    ) {
 5425        self.open_or_update_completions_menu(None, None, false, window, cx);
 5426    }
 5427
 5428    fn open_or_update_completions_menu(
 5429        &mut self,
 5430        requested_source: Option<CompletionsMenuSource>,
 5431        trigger: Option<String>,
 5432        trigger_in_words: bool,
 5433        window: &mut Window,
 5434        cx: &mut Context<Self>,
 5435    ) {
 5436        if self.pending_rename.is_some() {
 5437            return;
 5438        }
 5439
 5440        let completions_source = self
 5441            .context_menu
 5442            .borrow()
 5443            .as_ref()
 5444            .and_then(|menu| match menu {
 5445                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5446                CodeContextMenu::CodeActions(_) => None,
 5447            });
 5448
 5449        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5450
 5451        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5452        // inserted and selected. To handle that case, the start of the selection is used so that
 5453        // the menu starts with all choices.
 5454        let position = self
 5455            .selections
 5456            .newest_anchor()
 5457            .start
 5458            .bias_right(&multibuffer_snapshot);
 5459        if position.diff_base_anchor.is_some() {
 5460            return;
 5461        }
 5462        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5463        let Some(buffer) = buffer_position
 5464            .buffer_id
 5465            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5466        else {
 5467            return;
 5468        };
 5469        let buffer_snapshot = buffer.read(cx).snapshot();
 5470
 5471        let query: Option<Arc<String>> =
 5472            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5473                .map(|query| query.into());
 5474
 5475        drop(multibuffer_snapshot);
 5476
 5477        // Hide the current completions menu when query is empty. Without this, cached
 5478        // completions from before the trigger char may be reused (#32774).
 5479        if query.is_none() {
 5480            let menu_is_open = matches!(
 5481                self.context_menu.borrow().as_ref(),
 5482                Some(CodeContextMenu::Completions(_))
 5483            );
 5484            if menu_is_open {
 5485                self.hide_context_menu(window, cx);
 5486            }
 5487        }
 5488
 5489        let mut ignore_word_threshold = false;
 5490        let provider = match requested_source {
 5491            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5492            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5493                ignore_word_threshold = ignore_threshold;
 5494                None
 5495            }
 5496            Some(CompletionsMenuSource::SnippetChoices)
 5497            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5498                log::error!("bug: SnippetChoices requested_source is not handled");
 5499                None
 5500            }
 5501        };
 5502
 5503        let sort_completions = provider
 5504            .as_ref()
 5505            .is_some_and(|provider| provider.sort_completions());
 5506
 5507        let filter_completions = provider
 5508            .as_ref()
 5509            .is_none_or(|provider| provider.filter_completions());
 5510
 5511        let was_snippets_only = matches!(
 5512            completions_source,
 5513            Some(CompletionsMenuSource::SnippetsOnly)
 5514        );
 5515
 5516        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5517            if filter_completions {
 5518                menu.filter(
 5519                    query.clone().unwrap_or_default(),
 5520                    buffer_position.text_anchor,
 5521                    &buffer,
 5522                    provider.clone(),
 5523                    window,
 5524                    cx,
 5525                );
 5526            }
 5527            // When `is_incomplete` is false, no need to re-query completions when the current query
 5528            // is a suffix of the initial query.
 5529            let was_complete = !menu.is_incomplete;
 5530            if was_complete && !was_snippets_only {
 5531                // If the new query is a suffix of the old query (typing more characters) and
 5532                // the previous result was complete, the existing completions can be filtered.
 5533                //
 5534                // Note that snippet completions are always complete.
 5535                let query_matches = match (&menu.initial_query, &query) {
 5536                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5537                    (None, _) => true,
 5538                    _ => false,
 5539                };
 5540                if query_matches {
 5541                    let position_matches = if menu.initial_position == position {
 5542                        true
 5543                    } else {
 5544                        let snapshot = self.buffer.read(cx).read(cx);
 5545                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5546                    };
 5547                    if position_matches {
 5548                        return;
 5549                    }
 5550                }
 5551            }
 5552        };
 5553
 5554        let Anchor {
 5555            excerpt_id: buffer_excerpt_id,
 5556            text_anchor: buffer_position,
 5557            ..
 5558        } = buffer_position;
 5559
 5560        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5561            buffer_snapshot.surrounding_word(buffer_position, None)
 5562        {
 5563            let word_to_exclude = buffer_snapshot
 5564                .text_for_range(word_range.clone())
 5565                .collect::<String>();
 5566            (
 5567                buffer_snapshot.anchor_before(word_range.start)
 5568                    ..buffer_snapshot.anchor_after(buffer_position),
 5569                Some(word_to_exclude),
 5570            )
 5571        } else {
 5572            (buffer_position..buffer_position, None)
 5573        };
 5574
 5575        let language = buffer_snapshot
 5576            .language_at(buffer_position)
 5577            .map(|language| language.name());
 5578
 5579        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5580            .completions
 5581            .clone();
 5582
 5583        let show_completion_documentation = buffer_snapshot
 5584            .settings_at(buffer_position, cx)
 5585            .show_completion_documentation;
 5586
 5587        // The document can be large, so stay in reasonable bounds when searching for words,
 5588        // otherwise completion pop-up might be slow to appear.
 5589        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5590        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5591        let min_word_search = buffer_snapshot.clip_point(
 5592            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5593            Bias::Left,
 5594        );
 5595        let max_word_search = buffer_snapshot.clip_point(
 5596            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5597            Bias::Right,
 5598        );
 5599        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5600            ..buffer_snapshot.point_to_offset(max_word_search);
 5601
 5602        let skip_digits = query
 5603            .as_ref()
 5604            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5605
 5606        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5607            trigger.as_ref().is_none_or(|trigger| {
 5608                provider.is_completion_trigger(
 5609                    &buffer,
 5610                    position.text_anchor,
 5611                    trigger,
 5612                    trigger_in_words,
 5613                    completions_source.is_some(),
 5614                    cx,
 5615                )
 5616            })
 5617        });
 5618
 5619        let provider_responses = if let Some(provider) = &provider
 5620            && load_provider_completions
 5621        {
 5622            let trigger_character =
 5623                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5624            let completion_context = CompletionContext {
 5625                trigger_kind: match &trigger_character {
 5626                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5627                    None => CompletionTriggerKind::INVOKED,
 5628                },
 5629                trigger_character,
 5630            };
 5631
 5632            provider.completions(
 5633                buffer_excerpt_id,
 5634                &buffer,
 5635                buffer_position,
 5636                completion_context,
 5637                window,
 5638                cx,
 5639            )
 5640        } else {
 5641            Task::ready(Ok(Vec::new()))
 5642        };
 5643
 5644        let load_word_completions = if !self.word_completions_enabled {
 5645            false
 5646        } else if requested_source
 5647            == Some(CompletionsMenuSource::Words {
 5648                ignore_threshold: true,
 5649            })
 5650        {
 5651            true
 5652        } else {
 5653            load_provider_completions
 5654                && completion_settings.words != WordsCompletionMode::Disabled
 5655                && (ignore_word_threshold || {
 5656                    let words_min_length = completion_settings.words_min_length;
 5657                    // check whether word has at least `words_min_length` characters
 5658                    let query_chars = query.iter().flat_map(|q| q.chars());
 5659                    query_chars.take(words_min_length).count() == words_min_length
 5660                })
 5661        };
 5662
 5663        let mut words = if load_word_completions {
 5664            cx.background_spawn({
 5665                let buffer_snapshot = buffer_snapshot.clone();
 5666                async move {
 5667                    buffer_snapshot.words_in_range(WordsQuery {
 5668                        fuzzy_contents: None,
 5669                        range: word_search_range,
 5670                        skip_digits,
 5671                    })
 5672                }
 5673            })
 5674        } else {
 5675            Task::ready(BTreeMap::default())
 5676        };
 5677
 5678        let snippets = if let Some(provider) = &provider
 5679            && provider.show_snippets()
 5680            && let Some(project) = self.project()
 5681        {
 5682            let char_classifier = buffer_snapshot
 5683                .char_classifier_at(buffer_position)
 5684                .scope_context(Some(CharScopeContext::Completion));
 5685            project.update(cx, |project, cx| {
 5686                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5687            })
 5688        } else {
 5689            Task::ready(Ok(CompletionResponse {
 5690                completions: Vec::new(),
 5691                display_options: Default::default(),
 5692                is_incomplete: false,
 5693            }))
 5694        };
 5695
 5696        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5697
 5698        let id = post_inc(&mut self.next_completion_id);
 5699        let task = cx.spawn_in(window, async move |editor, cx| {
 5700            let Ok(()) = editor.update(cx, |this, _| {
 5701                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5702            }) else {
 5703                return;
 5704            };
 5705
 5706            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5707            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5708            let mut completions = Vec::new();
 5709            let mut is_incomplete = false;
 5710            let mut display_options: Option<CompletionDisplayOptions> = None;
 5711            if let Some(provider_responses) = provider_responses.await.log_err()
 5712                && !provider_responses.is_empty()
 5713            {
 5714                for response in provider_responses {
 5715                    completions.extend(response.completions);
 5716                    is_incomplete = is_incomplete || response.is_incomplete;
 5717                    match display_options.as_mut() {
 5718                        None => {
 5719                            display_options = Some(response.display_options);
 5720                        }
 5721                        Some(options) => options.merge(&response.display_options),
 5722                    }
 5723                }
 5724                if completion_settings.words == WordsCompletionMode::Fallback {
 5725                    words = Task::ready(BTreeMap::default());
 5726                }
 5727            }
 5728            let display_options = display_options.unwrap_or_default();
 5729
 5730            let mut words = words.await;
 5731            if let Some(word_to_exclude) = &word_to_exclude {
 5732                words.remove(word_to_exclude);
 5733            }
 5734            for lsp_completion in &completions {
 5735                words.remove(&lsp_completion.new_text);
 5736            }
 5737            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5738                replace_range: word_replace_range.clone(),
 5739                new_text: word.clone(),
 5740                label: CodeLabel::plain(word, None),
 5741                match_start: None,
 5742                snippet_deduplication_key: None,
 5743                icon_path: None,
 5744                documentation: None,
 5745                source: CompletionSource::BufferWord {
 5746                    word_range,
 5747                    resolved: false,
 5748                },
 5749                insert_text_mode: Some(InsertTextMode::AS_IS),
 5750                confirm: None,
 5751            }));
 5752
 5753            completions.extend(
 5754                snippets
 5755                    .await
 5756                    .into_iter()
 5757                    .flat_map(|response| response.completions),
 5758            );
 5759
 5760            let menu = if completions.is_empty() {
 5761                None
 5762            } else {
 5763                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5764                    let languages = editor
 5765                        .workspace
 5766                        .as_ref()
 5767                        .and_then(|(workspace, _)| workspace.upgrade())
 5768                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5769                    let menu = CompletionsMenu::new(
 5770                        id,
 5771                        requested_source.unwrap_or(if load_provider_completions {
 5772                            CompletionsMenuSource::Normal
 5773                        } else {
 5774                            CompletionsMenuSource::SnippetsOnly
 5775                        }),
 5776                        sort_completions,
 5777                        show_completion_documentation,
 5778                        position,
 5779                        query.clone(),
 5780                        is_incomplete,
 5781                        buffer.clone(),
 5782                        completions.into(),
 5783                        display_options,
 5784                        snippet_sort_order,
 5785                        languages,
 5786                        language,
 5787                        cx,
 5788                    );
 5789
 5790                    let query = if filter_completions { query } else { None };
 5791                    let matches_task = menu.do_async_filtering(
 5792                        query.unwrap_or_default(),
 5793                        buffer_position,
 5794                        &buffer,
 5795                        cx,
 5796                    );
 5797                    (menu, matches_task)
 5798                }) else {
 5799                    return;
 5800                };
 5801
 5802                let matches = matches_task.await;
 5803
 5804                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5805                    // Newer menu already set, so exit.
 5806                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5807                        editor.context_menu.borrow().as_ref()
 5808                        && prev_menu.id > id
 5809                    {
 5810                        return;
 5811                    };
 5812
 5813                    // Only valid to take prev_menu because either the new menu is immediately set
 5814                    // below, or the menu is hidden.
 5815                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5816                        editor.context_menu.borrow_mut().take()
 5817                    {
 5818                        let position_matches =
 5819                            if prev_menu.initial_position == menu.initial_position {
 5820                                true
 5821                            } else {
 5822                                let snapshot = editor.buffer.read(cx).read(cx);
 5823                                prev_menu.initial_position.to_offset(&snapshot)
 5824                                    == menu.initial_position.to_offset(&snapshot)
 5825                            };
 5826                        if position_matches {
 5827                            // Preserve markdown cache before `set_filter_results` because it will
 5828                            // try to populate the documentation cache.
 5829                            menu.preserve_markdown_cache(prev_menu);
 5830                        }
 5831                    };
 5832
 5833                    menu.set_filter_results(matches, provider, window, cx);
 5834                }) else {
 5835                    return;
 5836                };
 5837
 5838                menu.visible().then_some(menu)
 5839            };
 5840
 5841            editor
 5842                .update_in(cx, |editor, window, cx| {
 5843                    if editor.focus_handle.is_focused(window)
 5844                        && let Some(menu) = menu
 5845                    {
 5846                        *editor.context_menu.borrow_mut() =
 5847                            Some(CodeContextMenu::Completions(menu));
 5848
 5849                        crate::hover_popover::hide_hover(editor, cx);
 5850                        if editor.show_edit_predictions_in_menu() {
 5851                            editor.update_visible_edit_prediction(window, cx);
 5852                        } else {
 5853                            editor.discard_edit_prediction(false, cx);
 5854                        }
 5855
 5856                        cx.notify();
 5857                        return;
 5858                    }
 5859
 5860                    if editor.completion_tasks.len() <= 1 {
 5861                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5862                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5863                        // If it was already hidden and we don't show edit predictions in the menu,
 5864                        // we should also show the edit prediction when available.
 5865                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5866                            editor.update_visible_edit_prediction(window, cx);
 5867                        }
 5868                    }
 5869                })
 5870                .ok();
 5871        });
 5872
 5873        self.completion_tasks.push((id, task));
 5874    }
 5875
 5876    #[cfg(feature = "test-support")]
 5877    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5878        let menu = self.context_menu.borrow();
 5879        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5880            let completions = menu.completions.borrow();
 5881            Some(completions.to_vec())
 5882        } else {
 5883            None
 5884        }
 5885    }
 5886
 5887    pub fn with_completions_menu_matching_id<R>(
 5888        &self,
 5889        id: CompletionId,
 5890        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5891    ) -> R {
 5892        let mut context_menu = self.context_menu.borrow_mut();
 5893        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5894            return f(None);
 5895        };
 5896        if completions_menu.id != id {
 5897            return f(None);
 5898        }
 5899        f(Some(completions_menu))
 5900    }
 5901
 5902    pub fn confirm_completion(
 5903        &mut self,
 5904        action: &ConfirmCompletion,
 5905        window: &mut Window,
 5906        cx: &mut Context<Self>,
 5907    ) -> Option<Task<Result<()>>> {
 5908        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5909        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5910    }
 5911
 5912    pub fn confirm_completion_insert(
 5913        &mut self,
 5914        _: &ConfirmCompletionInsert,
 5915        window: &mut Window,
 5916        cx: &mut Context<Self>,
 5917    ) -> Option<Task<Result<()>>> {
 5918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5919        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5920    }
 5921
 5922    pub fn confirm_completion_replace(
 5923        &mut self,
 5924        _: &ConfirmCompletionReplace,
 5925        window: &mut Window,
 5926        cx: &mut Context<Self>,
 5927    ) -> Option<Task<Result<()>>> {
 5928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5929        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5930    }
 5931
 5932    pub fn compose_completion(
 5933        &mut self,
 5934        action: &ComposeCompletion,
 5935        window: &mut Window,
 5936        cx: &mut Context<Self>,
 5937    ) -> Option<Task<Result<()>>> {
 5938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5939        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5940    }
 5941
 5942    fn do_completion(
 5943        &mut self,
 5944        item_ix: Option<usize>,
 5945        intent: CompletionIntent,
 5946        window: &mut Window,
 5947        cx: &mut Context<Editor>,
 5948    ) -> Option<Task<Result<()>>> {
 5949        use language::ToOffset as _;
 5950
 5951        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5952        else {
 5953            return None;
 5954        };
 5955
 5956        let candidate_id = {
 5957            let entries = completions_menu.entries.borrow();
 5958            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5959            if self.show_edit_predictions_in_menu() {
 5960                self.discard_edit_prediction(true, cx);
 5961            }
 5962            mat.candidate_id
 5963        };
 5964
 5965        let completion = completions_menu
 5966            .completions
 5967            .borrow()
 5968            .get(candidate_id)?
 5969            .clone();
 5970        cx.stop_propagation();
 5971
 5972        let buffer_handle = completions_menu.buffer.clone();
 5973
 5974        let CompletionEdit {
 5975            new_text,
 5976            snippet,
 5977            replace_range,
 5978        } = process_completion_for_edit(
 5979            &completion,
 5980            intent,
 5981            &buffer_handle,
 5982            &completions_menu.initial_position.text_anchor,
 5983            cx,
 5984        );
 5985
 5986        let buffer = buffer_handle.read(cx);
 5987        let snapshot = self.buffer.read(cx).snapshot(cx);
 5988        let newest_anchor = self.selections.newest_anchor();
 5989        let replace_range_multibuffer = {
 5990            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5991            excerpt.map_range_from_buffer(replace_range.clone())
 5992        };
 5993        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5994            return None;
 5995        }
 5996
 5997        let old_text = buffer
 5998            .text_for_range(replace_range.clone())
 5999            .collect::<String>();
 6000        let lookbehind = newest_anchor
 6001            .start
 6002            .text_anchor
 6003            .to_offset(buffer)
 6004            .saturating_sub(replace_range.start);
 6005        let lookahead = replace_range
 6006            .end
 6007            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6008        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6009        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6010
 6011        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6012        let mut ranges = Vec::new();
 6013        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6014
 6015        for selection in &selections {
 6016            let range = if selection.id == newest_anchor.id {
 6017                replace_range_multibuffer.clone()
 6018            } else {
 6019                let mut range = selection.range();
 6020
 6021                // if prefix is present, don't duplicate it
 6022                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6023                    range.start = range.start.saturating_sub(lookbehind);
 6024
 6025                    // if suffix is also present, mimic the newest cursor and replace it
 6026                    if selection.id != newest_anchor.id
 6027                        && snapshot.contains_str_at(range.end, suffix)
 6028                    {
 6029                        range.end += lookahead;
 6030                    }
 6031                }
 6032                range
 6033            };
 6034
 6035            ranges.push(range.clone());
 6036
 6037            if !self.linked_edit_ranges.is_empty() {
 6038                let start_anchor = snapshot.anchor_before(range.start);
 6039                let end_anchor = snapshot.anchor_after(range.end);
 6040                if let Some(ranges) = self
 6041                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6042                {
 6043                    for (buffer, edits) in ranges {
 6044                        linked_edits
 6045                            .entry(buffer.clone())
 6046                            .or_default()
 6047                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6048                    }
 6049                }
 6050            }
 6051        }
 6052
 6053        let common_prefix_len = old_text
 6054            .chars()
 6055            .zip(new_text.chars())
 6056            .take_while(|(a, b)| a == b)
 6057            .map(|(a, _)| a.len_utf8())
 6058            .sum::<usize>();
 6059
 6060        cx.emit(EditorEvent::InputHandled {
 6061            utf16_range_to_replace: None,
 6062            text: new_text[common_prefix_len..].into(),
 6063        });
 6064
 6065        self.transact(window, cx, |editor, window, cx| {
 6066            if let Some(mut snippet) = snippet {
 6067                snippet.text = new_text.to_string();
 6068                editor
 6069                    .insert_snippet(&ranges, snippet, window, cx)
 6070                    .log_err();
 6071            } else {
 6072                editor.buffer.update(cx, |multi_buffer, cx| {
 6073                    let auto_indent = match completion.insert_text_mode {
 6074                        Some(InsertTextMode::AS_IS) => None,
 6075                        _ => editor.autoindent_mode.clone(),
 6076                    };
 6077                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6078                    multi_buffer.edit(edits, auto_indent, cx);
 6079                });
 6080            }
 6081            for (buffer, edits) in linked_edits {
 6082                buffer.update(cx, |buffer, cx| {
 6083                    let snapshot = buffer.snapshot();
 6084                    let edits = edits
 6085                        .into_iter()
 6086                        .map(|(range, text)| {
 6087                            use text::ToPoint as TP;
 6088                            let end_point = TP::to_point(&range.end, &snapshot);
 6089                            let start_point = TP::to_point(&range.start, &snapshot);
 6090                            (start_point..end_point, text)
 6091                        })
 6092                        .sorted_by_key(|(range, _)| range.start);
 6093                    buffer.edit(edits, None, cx);
 6094                })
 6095            }
 6096
 6097            editor.refresh_edit_prediction(true, false, window, cx);
 6098        });
 6099        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6100
 6101        let show_new_completions_on_confirm = completion
 6102            .confirm
 6103            .as_ref()
 6104            .is_some_and(|confirm| confirm(intent, window, cx));
 6105        if show_new_completions_on_confirm {
 6106            self.open_or_update_completions_menu(None, None, false, window, cx);
 6107        }
 6108
 6109        let provider = self.completion_provider.as_ref()?;
 6110        drop(completion);
 6111        let apply_edits = provider.apply_additional_edits_for_completion(
 6112            buffer_handle,
 6113            completions_menu.completions.clone(),
 6114            candidate_id,
 6115            true,
 6116            cx,
 6117        );
 6118
 6119        let editor_settings = EditorSettings::get_global(cx);
 6120        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6121            // After the code completion is finished, users often want to know what signatures are needed.
 6122            // so we should automatically call signature_help
 6123            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6124        }
 6125
 6126        Some(cx.foreground_executor().spawn(async move {
 6127            apply_edits.await?;
 6128            Ok(())
 6129        }))
 6130    }
 6131
 6132    pub fn toggle_code_actions(
 6133        &mut self,
 6134        action: &ToggleCodeActions,
 6135        window: &mut Window,
 6136        cx: &mut Context<Self>,
 6137    ) {
 6138        let quick_launch = action.quick_launch;
 6139        let mut context_menu = self.context_menu.borrow_mut();
 6140        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6141            if code_actions.deployed_from == action.deployed_from {
 6142                // Toggle if we're selecting the same one
 6143                *context_menu = None;
 6144                cx.notify();
 6145                return;
 6146            } else {
 6147                // Otherwise, clear it and start a new one
 6148                *context_menu = None;
 6149                cx.notify();
 6150            }
 6151        }
 6152        drop(context_menu);
 6153        let snapshot = self.snapshot(window, cx);
 6154        let deployed_from = action.deployed_from.clone();
 6155        let action = action.clone();
 6156        self.completion_tasks.clear();
 6157        self.discard_edit_prediction(false, cx);
 6158
 6159        let multibuffer_point = match &action.deployed_from {
 6160            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6161                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6162            }
 6163            _ => self
 6164                .selections
 6165                .newest::<Point>(&snapshot.display_snapshot)
 6166                .head(),
 6167        };
 6168        let Some((buffer, buffer_row)) = snapshot
 6169            .buffer_snapshot()
 6170            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6171            .and_then(|(buffer_snapshot, range)| {
 6172                self.buffer()
 6173                    .read(cx)
 6174                    .buffer(buffer_snapshot.remote_id())
 6175                    .map(|buffer| (buffer, range.start.row))
 6176            })
 6177        else {
 6178            return;
 6179        };
 6180        let buffer_id = buffer.read(cx).remote_id();
 6181        let tasks = self
 6182            .tasks
 6183            .get(&(buffer_id, buffer_row))
 6184            .map(|t| Arc::new(t.to_owned()));
 6185
 6186        if !self.focus_handle.is_focused(window) {
 6187            return;
 6188        }
 6189        let project = self.project.clone();
 6190
 6191        let code_actions_task = match deployed_from {
 6192            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6193            _ => self.code_actions(buffer_row, window, cx),
 6194        };
 6195
 6196        let runnable_task = match deployed_from {
 6197            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6198            _ => {
 6199                let mut task_context_task = Task::ready(None);
 6200                if let Some(tasks) = &tasks
 6201                    && let Some(project) = project
 6202                {
 6203                    task_context_task =
 6204                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6205                }
 6206
 6207                cx.spawn_in(window, {
 6208                    let buffer = buffer.clone();
 6209                    async move |editor, cx| {
 6210                        let task_context = task_context_task.await;
 6211
 6212                        let resolved_tasks =
 6213                            tasks
 6214                                .zip(task_context.clone())
 6215                                .map(|(tasks, task_context)| ResolvedTasks {
 6216                                    templates: tasks.resolve(&task_context).collect(),
 6217                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6218                                        multibuffer_point.row,
 6219                                        tasks.column,
 6220                                    )),
 6221                                });
 6222                        let debug_scenarios = editor
 6223                            .update(cx, |editor, cx| {
 6224                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6225                            })?
 6226                            .await;
 6227                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6228                    }
 6229                })
 6230            }
 6231        };
 6232
 6233        cx.spawn_in(window, async move |editor, cx| {
 6234            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6235            let code_actions = code_actions_task.await;
 6236            let spawn_straight_away = quick_launch
 6237                && resolved_tasks
 6238                    .as_ref()
 6239                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6240                && code_actions
 6241                    .as_ref()
 6242                    .is_none_or(|actions| actions.is_empty())
 6243                && debug_scenarios.is_empty();
 6244
 6245            editor.update_in(cx, |editor, window, cx| {
 6246                crate::hover_popover::hide_hover(editor, cx);
 6247                let actions = CodeActionContents::new(
 6248                    resolved_tasks,
 6249                    code_actions,
 6250                    debug_scenarios,
 6251                    task_context.unwrap_or_default(),
 6252                );
 6253
 6254                // Don't show the menu if there are no actions available
 6255                if actions.is_empty() {
 6256                    cx.notify();
 6257                    return Task::ready(Ok(()));
 6258                }
 6259
 6260                *editor.context_menu.borrow_mut() =
 6261                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6262                        buffer,
 6263                        actions,
 6264                        selected_item: Default::default(),
 6265                        scroll_handle: UniformListScrollHandle::default(),
 6266                        deployed_from,
 6267                    }));
 6268                cx.notify();
 6269                if spawn_straight_away
 6270                    && let Some(task) = editor.confirm_code_action(
 6271                        &ConfirmCodeAction { item_ix: Some(0) },
 6272                        window,
 6273                        cx,
 6274                    )
 6275                {
 6276                    return task;
 6277                }
 6278
 6279                Task::ready(Ok(()))
 6280            })
 6281        })
 6282        .detach_and_log_err(cx);
 6283    }
 6284
 6285    fn debug_scenarios(
 6286        &mut self,
 6287        resolved_tasks: &Option<ResolvedTasks>,
 6288        buffer: &Entity<Buffer>,
 6289        cx: &mut App,
 6290    ) -> Task<Vec<task::DebugScenario>> {
 6291        maybe!({
 6292            let project = self.project()?;
 6293            let dap_store = project.read(cx).dap_store();
 6294            let mut scenarios = vec![];
 6295            let resolved_tasks = resolved_tasks.as_ref()?;
 6296            let buffer = buffer.read(cx);
 6297            let language = buffer.language()?;
 6298            let file = buffer.file();
 6299            let debug_adapter = language_settings(language.name().into(), file, cx)
 6300                .debuggers
 6301                .first()
 6302                .map(SharedString::from)
 6303                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6304
 6305            dap_store.update(cx, |dap_store, cx| {
 6306                for (_, task) in &resolved_tasks.templates {
 6307                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6308                        task.original_task().clone(),
 6309                        debug_adapter.clone().into(),
 6310                        task.display_label().to_owned().into(),
 6311                        cx,
 6312                    );
 6313                    scenarios.push(maybe_scenario);
 6314                }
 6315            });
 6316            Some(cx.background_spawn(async move {
 6317                futures::future::join_all(scenarios)
 6318                    .await
 6319                    .into_iter()
 6320                    .flatten()
 6321                    .collect::<Vec<_>>()
 6322            }))
 6323        })
 6324        .unwrap_or_else(|| Task::ready(vec![]))
 6325    }
 6326
 6327    fn code_actions(
 6328        &mut self,
 6329        buffer_row: u32,
 6330        window: &mut Window,
 6331        cx: &mut Context<Self>,
 6332    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6333        let mut task = self.code_actions_task.take();
 6334        cx.spawn_in(window, async move |editor, cx| {
 6335            while let Some(prev_task) = task {
 6336                prev_task.await.log_err();
 6337                task = editor
 6338                    .update(cx, |this, _| this.code_actions_task.take())
 6339                    .ok()?;
 6340            }
 6341
 6342            editor
 6343                .update(cx, |editor, cx| {
 6344                    editor
 6345                        .available_code_actions
 6346                        .clone()
 6347                        .and_then(|(location, code_actions)| {
 6348                            let snapshot = location.buffer.read(cx).snapshot();
 6349                            let point_range = location.range.to_point(&snapshot);
 6350                            let point_range = point_range.start.row..=point_range.end.row;
 6351                            if point_range.contains(&buffer_row) {
 6352                                Some(code_actions)
 6353                            } else {
 6354                                None
 6355                            }
 6356                        })
 6357                })
 6358                .ok()
 6359                .flatten()
 6360        })
 6361    }
 6362
 6363    pub fn confirm_code_action(
 6364        &mut self,
 6365        action: &ConfirmCodeAction,
 6366        window: &mut Window,
 6367        cx: &mut Context<Self>,
 6368    ) -> Option<Task<Result<()>>> {
 6369        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6370
 6371        let actions_menu =
 6372            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6373                menu
 6374            } else {
 6375                return None;
 6376            };
 6377
 6378        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6379        let action = actions_menu.actions.get(action_ix)?;
 6380        let title = action.label();
 6381        let buffer = actions_menu.buffer;
 6382        let workspace = self.workspace()?;
 6383
 6384        match action {
 6385            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6386                workspace.update(cx, |workspace, cx| {
 6387                    workspace.schedule_resolved_task(
 6388                        task_source_kind,
 6389                        resolved_task,
 6390                        false,
 6391                        window,
 6392                        cx,
 6393                    );
 6394
 6395                    Some(Task::ready(Ok(())))
 6396                })
 6397            }
 6398            CodeActionsItem::CodeAction {
 6399                excerpt_id,
 6400                action,
 6401                provider,
 6402            } => {
 6403                let apply_code_action =
 6404                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6405                let workspace = workspace.downgrade();
 6406                Some(cx.spawn_in(window, async move |editor, cx| {
 6407                    let project_transaction = apply_code_action.await?;
 6408                    Self::open_project_transaction(
 6409                        &editor,
 6410                        workspace,
 6411                        project_transaction,
 6412                        title,
 6413                        cx,
 6414                    )
 6415                    .await
 6416                }))
 6417            }
 6418            CodeActionsItem::DebugScenario(scenario) => {
 6419                let context = actions_menu.actions.context;
 6420
 6421                workspace.update(cx, |workspace, cx| {
 6422                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6423                    workspace.start_debug_session(
 6424                        scenario,
 6425                        context,
 6426                        Some(buffer),
 6427                        None,
 6428                        window,
 6429                        cx,
 6430                    );
 6431                });
 6432                Some(Task::ready(Ok(())))
 6433            }
 6434        }
 6435    }
 6436
 6437    pub async fn open_project_transaction(
 6438        editor: &WeakEntity<Editor>,
 6439        workspace: WeakEntity<Workspace>,
 6440        transaction: ProjectTransaction,
 6441        title: String,
 6442        cx: &mut AsyncWindowContext,
 6443    ) -> Result<()> {
 6444        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6445        cx.update(|_, cx| {
 6446            entries.sort_unstable_by_key(|(buffer, _)| {
 6447                buffer.read(cx).file().map(|f| f.path().clone())
 6448            });
 6449        })?;
 6450        if entries.is_empty() {
 6451            return Ok(());
 6452        }
 6453
 6454        // If the project transaction's edits are all contained within this editor, then
 6455        // avoid opening a new editor to display them.
 6456
 6457        if let [(buffer, transaction)] = &*entries {
 6458            let excerpt = editor.update(cx, |editor, cx| {
 6459                editor
 6460                    .buffer()
 6461                    .read(cx)
 6462                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6463            })?;
 6464            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6465                && excerpted_buffer == *buffer
 6466            {
 6467                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6468                    let excerpt_range = excerpt_range.to_offset(buffer);
 6469                    buffer
 6470                        .edited_ranges_for_transaction::<usize>(transaction)
 6471                        .all(|range| {
 6472                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6473                        })
 6474                })?;
 6475
 6476                if all_edits_within_excerpt {
 6477                    return Ok(());
 6478                }
 6479            }
 6480        }
 6481
 6482        let mut ranges_to_highlight = Vec::new();
 6483        let excerpt_buffer = cx.new(|cx| {
 6484            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6485            for (buffer_handle, transaction) in &entries {
 6486                let edited_ranges = buffer_handle
 6487                    .read(cx)
 6488                    .edited_ranges_for_transaction::<Point>(transaction)
 6489                    .collect::<Vec<_>>();
 6490                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6491                    PathKey::for_buffer(buffer_handle, cx),
 6492                    buffer_handle.clone(),
 6493                    edited_ranges,
 6494                    multibuffer_context_lines(cx),
 6495                    cx,
 6496                );
 6497
 6498                ranges_to_highlight.extend(ranges);
 6499            }
 6500            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6501            multibuffer
 6502        })?;
 6503
 6504        workspace.update_in(cx, |workspace, window, cx| {
 6505            let project = workspace.project().clone();
 6506            let editor =
 6507                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6508            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6509            editor.update(cx, |editor, cx| {
 6510                editor.highlight_background::<Self>(
 6511                    &ranges_to_highlight,
 6512                    |theme| theme.colors().editor_highlighted_line_background,
 6513                    cx,
 6514                );
 6515            });
 6516        })?;
 6517
 6518        Ok(())
 6519    }
 6520
 6521    pub fn clear_code_action_providers(&mut self) {
 6522        self.code_action_providers.clear();
 6523        self.available_code_actions.take();
 6524    }
 6525
 6526    pub fn add_code_action_provider(
 6527        &mut self,
 6528        provider: Rc<dyn CodeActionProvider>,
 6529        window: &mut Window,
 6530        cx: &mut Context<Self>,
 6531    ) {
 6532        if self
 6533            .code_action_providers
 6534            .iter()
 6535            .any(|existing_provider| existing_provider.id() == provider.id())
 6536        {
 6537            return;
 6538        }
 6539
 6540        self.code_action_providers.push(provider);
 6541        self.refresh_code_actions(window, cx);
 6542    }
 6543
 6544    pub fn remove_code_action_provider(
 6545        &mut self,
 6546        id: Arc<str>,
 6547        window: &mut Window,
 6548        cx: &mut Context<Self>,
 6549    ) {
 6550        self.code_action_providers
 6551            .retain(|provider| provider.id() != id);
 6552        self.refresh_code_actions(window, cx);
 6553    }
 6554
 6555    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6556        !self.code_action_providers.is_empty()
 6557            && EditorSettings::get_global(cx).toolbar.code_actions
 6558    }
 6559
 6560    pub fn has_available_code_actions(&self) -> bool {
 6561        self.available_code_actions
 6562            .as_ref()
 6563            .is_some_and(|(_, actions)| !actions.is_empty())
 6564    }
 6565
 6566    fn render_inline_code_actions(
 6567        &self,
 6568        icon_size: ui::IconSize,
 6569        display_row: DisplayRow,
 6570        is_active: bool,
 6571        cx: &mut Context<Self>,
 6572    ) -> AnyElement {
 6573        let show_tooltip = !self.context_menu_visible();
 6574        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6575            .icon_size(icon_size)
 6576            .shape(ui::IconButtonShape::Square)
 6577            .icon_color(ui::Color::Hidden)
 6578            .toggle_state(is_active)
 6579            .when(show_tooltip, |this| {
 6580                this.tooltip({
 6581                    let focus_handle = self.focus_handle.clone();
 6582                    move |_window, cx| {
 6583                        Tooltip::for_action_in(
 6584                            "Toggle Code Actions",
 6585                            &ToggleCodeActions {
 6586                                deployed_from: None,
 6587                                quick_launch: false,
 6588                            },
 6589                            &focus_handle,
 6590                            cx,
 6591                        )
 6592                    }
 6593                })
 6594            })
 6595            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6596                window.focus(&editor.focus_handle(cx));
 6597                editor.toggle_code_actions(
 6598                    &crate::actions::ToggleCodeActions {
 6599                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6600                            display_row,
 6601                        )),
 6602                        quick_launch: false,
 6603                    },
 6604                    window,
 6605                    cx,
 6606                );
 6607            }))
 6608            .into_any_element()
 6609    }
 6610
 6611    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6612        &self.context_menu
 6613    }
 6614
 6615    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6616        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6617            cx.background_executor()
 6618                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6619                .await;
 6620
 6621            let (start_buffer, start, _, end, newest_selection) = this
 6622                .update(cx, |this, cx| {
 6623                    let newest_selection = this.selections.newest_anchor().clone();
 6624                    if newest_selection.head().diff_base_anchor.is_some() {
 6625                        return None;
 6626                    }
 6627                    let display_snapshot = this.display_snapshot(cx);
 6628                    let newest_selection_adjusted =
 6629                        this.selections.newest_adjusted(&display_snapshot);
 6630                    let buffer = this.buffer.read(cx);
 6631
 6632                    let (start_buffer, start) =
 6633                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6634                    let (end_buffer, end) =
 6635                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6636
 6637                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6638                })?
 6639                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6640                .context(
 6641                    "Expected selection to lie in a single buffer when refreshing code actions",
 6642                )?;
 6643            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6644                let providers = this.code_action_providers.clone();
 6645                let tasks = this
 6646                    .code_action_providers
 6647                    .iter()
 6648                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6649                    .collect::<Vec<_>>();
 6650                (providers, tasks)
 6651            })?;
 6652
 6653            let mut actions = Vec::new();
 6654            for (provider, provider_actions) in
 6655                providers.into_iter().zip(future::join_all(tasks).await)
 6656            {
 6657                if let Some(provider_actions) = provider_actions.log_err() {
 6658                    actions.extend(provider_actions.into_iter().map(|action| {
 6659                        AvailableCodeAction {
 6660                            excerpt_id: newest_selection.start.excerpt_id,
 6661                            action,
 6662                            provider: provider.clone(),
 6663                        }
 6664                    }));
 6665                }
 6666            }
 6667
 6668            this.update(cx, |this, cx| {
 6669                this.available_code_actions = if actions.is_empty() {
 6670                    None
 6671                } else {
 6672                    Some((
 6673                        Location {
 6674                            buffer: start_buffer,
 6675                            range: start..end,
 6676                        },
 6677                        actions.into(),
 6678                    ))
 6679                };
 6680                cx.notify();
 6681            })
 6682        }));
 6683    }
 6684
 6685    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6686        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6687            self.show_git_blame_inline = false;
 6688
 6689            self.show_git_blame_inline_delay_task =
 6690                Some(cx.spawn_in(window, async move |this, cx| {
 6691                    cx.background_executor().timer(delay).await;
 6692
 6693                    this.update(cx, |this, cx| {
 6694                        this.show_git_blame_inline = true;
 6695                        cx.notify();
 6696                    })
 6697                    .log_err();
 6698                }));
 6699        }
 6700    }
 6701
 6702    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6703        let snapshot = self.snapshot(window, cx);
 6704        let cursor = self
 6705            .selections
 6706            .newest::<Point>(&snapshot.display_snapshot)
 6707            .head();
 6708        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6709        else {
 6710            return;
 6711        };
 6712
 6713        let Some(blame) = self.blame.as_ref() else {
 6714            return;
 6715        };
 6716
 6717        let row_info = RowInfo {
 6718            buffer_id: Some(buffer.remote_id()),
 6719            buffer_row: Some(point.row),
 6720            ..Default::default()
 6721        };
 6722        let Some((buffer, blame_entry)) = blame
 6723            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6724            .flatten()
 6725        else {
 6726            return;
 6727        };
 6728
 6729        let anchor = self.selections.newest_anchor().head();
 6730        let position = self.to_pixel_point(anchor, &snapshot, window);
 6731        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6732            self.show_blame_popover(
 6733                buffer,
 6734                &blame_entry,
 6735                position + last_bounds.origin,
 6736                true,
 6737                cx,
 6738            );
 6739        };
 6740    }
 6741
 6742    fn show_blame_popover(
 6743        &mut self,
 6744        buffer: BufferId,
 6745        blame_entry: &BlameEntry,
 6746        position: gpui::Point<Pixels>,
 6747        ignore_timeout: bool,
 6748        cx: &mut Context<Self>,
 6749    ) {
 6750        if let Some(state) = &mut self.inline_blame_popover {
 6751            state.hide_task.take();
 6752        } else {
 6753            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6754            let blame_entry = blame_entry.clone();
 6755            let show_task = cx.spawn(async move |editor, cx| {
 6756                if !ignore_timeout {
 6757                    cx.background_executor()
 6758                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6759                        .await;
 6760                }
 6761                editor
 6762                    .update(cx, |editor, cx| {
 6763                        editor.inline_blame_popover_show_task.take();
 6764                        let Some(blame) = editor.blame.as_ref() else {
 6765                            return;
 6766                        };
 6767                        let blame = blame.read(cx);
 6768                        let details = blame.details_for_entry(buffer, &blame_entry);
 6769                        let markdown = cx.new(|cx| {
 6770                            Markdown::new(
 6771                                details
 6772                                    .as_ref()
 6773                                    .map(|message| message.message.clone())
 6774                                    .unwrap_or_default(),
 6775                                None,
 6776                                None,
 6777                                cx,
 6778                            )
 6779                        });
 6780                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6781                            position,
 6782                            hide_task: None,
 6783                            popover_bounds: None,
 6784                            popover_state: InlineBlamePopoverState {
 6785                                scroll_handle: ScrollHandle::new(),
 6786                                commit_message: details,
 6787                                markdown,
 6788                            },
 6789                            keyboard_grace: ignore_timeout,
 6790                        });
 6791                        cx.notify();
 6792                    })
 6793                    .ok();
 6794            });
 6795            self.inline_blame_popover_show_task = Some(show_task);
 6796        }
 6797    }
 6798
 6799    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6800        self.inline_blame_popover_show_task.take();
 6801        if let Some(state) = &mut self.inline_blame_popover {
 6802            let hide_task = cx.spawn(async move |editor, cx| {
 6803                if !ignore_timeout {
 6804                    cx.background_executor()
 6805                        .timer(std::time::Duration::from_millis(100))
 6806                        .await;
 6807                }
 6808                editor
 6809                    .update(cx, |editor, cx| {
 6810                        editor.inline_blame_popover.take();
 6811                        cx.notify();
 6812                    })
 6813                    .ok();
 6814            });
 6815            state.hide_task = Some(hide_task);
 6816            true
 6817        } else {
 6818            false
 6819        }
 6820    }
 6821
 6822    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6823        if self.pending_rename.is_some() {
 6824            return None;
 6825        }
 6826
 6827        let provider = self.semantics_provider.clone()?;
 6828        let buffer = self.buffer.read(cx);
 6829        let newest_selection = self.selections.newest_anchor().clone();
 6830        let cursor_position = newest_selection.head();
 6831        let (cursor_buffer, cursor_buffer_position) =
 6832            buffer.text_anchor_for_position(cursor_position, cx)?;
 6833        let (tail_buffer, tail_buffer_position) =
 6834            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6835        if cursor_buffer != tail_buffer {
 6836            return None;
 6837        }
 6838
 6839        let snapshot = cursor_buffer.read(cx).snapshot();
 6840        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6841        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6842        if start_word_range != end_word_range {
 6843            self.document_highlights_task.take();
 6844            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6845            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6846            return None;
 6847        }
 6848
 6849        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6850        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6851            cx.background_executor()
 6852                .timer(Duration::from_millis(debounce))
 6853                .await;
 6854
 6855            let highlights = if let Some(highlights) = cx
 6856                .update(|cx| {
 6857                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6858                })
 6859                .ok()
 6860                .flatten()
 6861            {
 6862                highlights.await.log_err()
 6863            } else {
 6864                None
 6865            };
 6866
 6867            if let Some(highlights) = highlights {
 6868                this.update(cx, |this, cx| {
 6869                    if this.pending_rename.is_some() {
 6870                        return;
 6871                    }
 6872
 6873                    let buffer = this.buffer.read(cx);
 6874                    if buffer
 6875                        .text_anchor_for_position(cursor_position, cx)
 6876                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6877                    {
 6878                        return;
 6879                    }
 6880
 6881                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6882                    let mut write_ranges = Vec::new();
 6883                    let mut read_ranges = Vec::new();
 6884                    for highlight in highlights {
 6885                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6886                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6887                        {
 6888                            let start = highlight
 6889                                .range
 6890                                .start
 6891                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6892                            let end = highlight
 6893                                .range
 6894                                .end
 6895                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6896                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6897                                continue;
 6898                            }
 6899
 6900                            let range =
 6901                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6902                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6903                                write_ranges.push(range);
 6904                            } else {
 6905                                read_ranges.push(range);
 6906                            }
 6907                        }
 6908                    }
 6909
 6910                    this.highlight_background::<DocumentHighlightRead>(
 6911                        &read_ranges,
 6912                        |theme| theme.colors().editor_document_highlight_read_background,
 6913                        cx,
 6914                    );
 6915                    this.highlight_background::<DocumentHighlightWrite>(
 6916                        &write_ranges,
 6917                        |theme| theme.colors().editor_document_highlight_write_background,
 6918                        cx,
 6919                    );
 6920                    cx.notify();
 6921                })
 6922                .log_err();
 6923            }
 6924        }));
 6925        None
 6926    }
 6927
 6928    fn prepare_highlight_query_from_selection(
 6929        &mut self,
 6930        window: &Window,
 6931        cx: &mut Context<Editor>,
 6932    ) -> Option<(String, Range<Anchor>)> {
 6933        if matches!(self.mode, EditorMode::SingleLine) {
 6934            return None;
 6935        }
 6936        if !EditorSettings::get_global(cx).selection_highlight {
 6937            return None;
 6938        }
 6939        if self.selections.count() != 1 || self.selections.line_mode() {
 6940            return None;
 6941        }
 6942        let snapshot = self.snapshot(window, cx);
 6943        let selection = self.selections.newest::<Point>(&snapshot);
 6944        // If the selection spans multiple rows OR it is empty
 6945        if selection.start.row != selection.end.row
 6946            || selection.start.column == selection.end.column
 6947        {
 6948            return None;
 6949        }
 6950        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6951        let query = snapshot
 6952            .buffer_snapshot()
 6953            .text_for_range(selection_anchor_range.clone())
 6954            .collect::<String>();
 6955        if query.trim().is_empty() {
 6956            return None;
 6957        }
 6958        Some((query, selection_anchor_range))
 6959    }
 6960
 6961    fn update_selection_occurrence_highlights(
 6962        &mut self,
 6963        query_text: String,
 6964        query_range: Range<Anchor>,
 6965        multi_buffer_range_to_query: Range<Point>,
 6966        use_debounce: bool,
 6967        window: &mut Window,
 6968        cx: &mut Context<Editor>,
 6969    ) -> Task<()> {
 6970        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6971        cx.spawn_in(window, async move |editor, cx| {
 6972            if use_debounce {
 6973                cx.background_executor()
 6974                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6975                    .await;
 6976            }
 6977            let match_task = cx.background_spawn(async move {
 6978                let buffer_ranges = multi_buffer_snapshot
 6979                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6980                    .into_iter()
 6981                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6982                let mut match_ranges = Vec::new();
 6983                let Ok(regex) = project::search::SearchQuery::text(
 6984                    query_text.clone(),
 6985                    false,
 6986                    false,
 6987                    false,
 6988                    Default::default(),
 6989                    Default::default(),
 6990                    false,
 6991                    None,
 6992                ) else {
 6993                    return Vec::default();
 6994                };
 6995                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6996                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6997                    match_ranges.extend(
 6998                        regex
 6999                            .search(buffer_snapshot, Some(search_range.clone()))
 7000                            .await
 7001                            .into_iter()
 7002                            .filter_map(|match_range| {
 7003                                let match_start = buffer_snapshot
 7004                                    .anchor_after(search_range.start + match_range.start);
 7005                                let match_end = buffer_snapshot
 7006                                    .anchor_before(search_range.start + match_range.end);
 7007                                let match_anchor_range = Anchor::range_in_buffer(
 7008                                    excerpt_id,
 7009                                    buffer_snapshot.remote_id(),
 7010                                    match_start..match_end,
 7011                                );
 7012                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7013                            }),
 7014                    );
 7015                }
 7016                match_ranges
 7017            });
 7018            let match_ranges = match_task.await;
 7019            editor
 7020                .update_in(cx, |editor, _, cx| {
 7021                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7022                    if !match_ranges.is_empty() {
 7023                        editor.highlight_background::<SelectedTextHighlight>(
 7024                            &match_ranges,
 7025                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7026                            cx,
 7027                        )
 7028                    }
 7029                })
 7030                .log_err();
 7031        })
 7032    }
 7033
 7034    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7035        struct NewlineFold;
 7036        let type_id = std::any::TypeId::of::<NewlineFold>();
 7037        if !self.mode.is_single_line() {
 7038            return;
 7039        }
 7040        let snapshot = self.snapshot(window, cx);
 7041        if snapshot.buffer_snapshot().max_point().row == 0 {
 7042            return;
 7043        }
 7044        let task = cx.background_spawn(async move {
 7045            let new_newlines = snapshot
 7046                .buffer_chars_at(0)
 7047                .filter_map(|(c, i)| {
 7048                    if c == '\n' {
 7049                        Some(
 7050                            snapshot.buffer_snapshot().anchor_after(i)
 7051                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7052                        )
 7053                    } else {
 7054                        None
 7055                    }
 7056                })
 7057                .collect::<Vec<_>>();
 7058            let existing_newlines = snapshot
 7059                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7060                .filter_map(|fold| {
 7061                    if fold.placeholder.type_tag == Some(type_id) {
 7062                        Some(fold.range.start..fold.range.end)
 7063                    } else {
 7064                        None
 7065                    }
 7066                })
 7067                .collect::<Vec<_>>();
 7068
 7069            (new_newlines, existing_newlines)
 7070        });
 7071        self.folding_newlines = cx.spawn(async move |this, cx| {
 7072            let (new_newlines, existing_newlines) = task.await;
 7073            if new_newlines == existing_newlines {
 7074                return;
 7075            }
 7076            let placeholder = FoldPlaceholder {
 7077                render: Arc::new(move |_, _, cx| {
 7078                    div()
 7079                        .bg(cx.theme().status().hint_background)
 7080                        .border_b_1()
 7081                        .size_full()
 7082                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7083                        .border_color(cx.theme().status().hint)
 7084                        .child("\\n")
 7085                        .into_any()
 7086                }),
 7087                constrain_width: false,
 7088                merge_adjacent: false,
 7089                type_tag: Some(type_id),
 7090            };
 7091            let creases = new_newlines
 7092                .into_iter()
 7093                .map(|range| Crease::simple(range, placeholder.clone()))
 7094                .collect();
 7095            this.update(cx, |this, cx| {
 7096                this.display_map.update(cx, |display_map, cx| {
 7097                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7098                    display_map.fold(creases, cx);
 7099                });
 7100            })
 7101            .ok();
 7102        });
 7103    }
 7104
 7105    fn refresh_selected_text_highlights(
 7106        &mut self,
 7107        on_buffer_edit: bool,
 7108        window: &mut Window,
 7109        cx: &mut Context<Editor>,
 7110    ) {
 7111        let Some((query_text, query_range)) =
 7112            self.prepare_highlight_query_from_selection(window, cx)
 7113        else {
 7114            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7115            self.quick_selection_highlight_task.take();
 7116            self.debounced_selection_highlight_task.take();
 7117            return;
 7118        };
 7119        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7120        if on_buffer_edit
 7121            || self
 7122                .quick_selection_highlight_task
 7123                .as_ref()
 7124                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7125        {
 7126            let multi_buffer_visible_start = self
 7127                .scroll_manager
 7128                .anchor()
 7129                .anchor
 7130                .to_point(&multi_buffer_snapshot);
 7131            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7132                multi_buffer_visible_start
 7133                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7134                Bias::Left,
 7135            );
 7136            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7137            self.quick_selection_highlight_task = Some((
 7138                query_range.clone(),
 7139                self.update_selection_occurrence_highlights(
 7140                    query_text.clone(),
 7141                    query_range.clone(),
 7142                    multi_buffer_visible_range,
 7143                    false,
 7144                    window,
 7145                    cx,
 7146                ),
 7147            ));
 7148        }
 7149        if on_buffer_edit
 7150            || self
 7151                .debounced_selection_highlight_task
 7152                .as_ref()
 7153                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7154        {
 7155            let multi_buffer_start = multi_buffer_snapshot
 7156                .anchor_before(0)
 7157                .to_point(&multi_buffer_snapshot);
 7158            let multi_buffer_end = multi_buffer_snapshot
 7159                .anchor_after(multi_buffer_snapshot.len())
 7160                .to_point(&multi_buffer_snapshot);
 7161            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7162            self.debounced_selection_highlight_task = Some((
 7163                query_range.clone(),
 7164                self.update_selection_occurrence_highlights(
 7165                    query_text,
 7166                    query_range,
 7167                    multi_buffer_full_range,
 7168                    true,
 7169                    window,
 7170                    cx,
 7171                ),
 7172            ));
 7173        }
 7174    }
 7175
 7176    pub fn refresh_edit_prediction(
 7177        &mut self,
 7178        debounce: bool,
 7179        user_requested: bool,
 7180        window: &mut Window,
 7181        cx: &mut Context<Self>,
 7182    ) -> Option<()> {
 7183        if DisableAiSettings::get_global(cx).disable_ai {
 7184            return None;
 7185        }
 7186
 7187        let provider = self.edit_prediction_provider()?;
 7188        let cursor = self.selections.newest_anchor().head();
 7189        let (buffer, cursor_buffer_position) =
 7190            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7191
 7192        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7193            self.discard_edit_prediction(false, cx);
 7194            return None;
 7195        }
 7196
 7197        self.update_visible_edit_prediction(window, cx);
 7198
 7199        if !user_requested
 7200            && (!self.should_show_edit_predictions()
 7201                || !self.is_focused(window)
 7202                || buffer.read(cx).is_empty())
 7203        {
 7204            self.discard_edit_prediction(false, cx);
 7205            return None;
 7206        }
 7207
 7208        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7209        Some(())
 7210    }
 7211
 7212    fn show_edit_predictions_in_menu(&self) -> bool {
 7213        match self.edit_prediction_settings {
 7214            EditPredictionSettings::Disabled => false,
 7215            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7216        }
 7217    }
 7218
 7219    pub fn edit_predictions_enabled(&self) -> bool {
 7220        match self.edit_prediction_settings {
 7221            EditPredictionSettings::Disabled => false,
 7222            EditPredictionSettings::Enabled { .. } => true,
 7223        }
 7224    }
 7225
 7226    fn edit_prediction_requires_modifier(&self) -> bool {
 7227        match self.edit_prediction_settings {
 7228            EditPredictionSettings::Disabled => false,
 7229            EditPredictionSettings::Enabled {
 7230                preview_requires_modifier,
 7231                ..
 7232            } => preview_requires_modifier,
 7233        }
 7234    }
 7235
 7236    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7237        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7238            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7239            self.discard_edit_prediction(false, cx);
 7240        } else {
 7241            let selection = self.selections.newest_anchor();
 7242            let cursor = selection.head();
 7243
 7244            if let Some((buffer, cursor_buffer_position)) =
 7245                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7246            {
 7247                self.edit_prediction_settings =
 7248                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7249            }
 7250        }
 7251    }
 7252
 7253    fn edit_prediction_settings_at_position(
 7254        &self,
 7255        buffer: &Entity<Buffer>,
 7256        buffer_position: language::Anchor,
 7257        cx: &App,
 7258    ) -> EditPredictionSettings {
 7259        if !self.mode.is_full()
 7260            || !self.show_edit_predictions_override.unwrap_or(true)
 7261            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7262        {
 7263            return EditPredictionSettings::Disabled;
 7264        }
 7265
 7266        let buffer = buffer.read(cx);
 7267
 7268        let file = buffer.file();
 7269
 7270        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7271            return EditPredictionSettings::Disabled;
 7272        };
 7273
 7274        let by_provider = matches!(
 7275            self.menu_edit_predictions_policy,
 7276            MenuEditPredictionsPolicy::ByProvider
 7277        );
 7278
 7279        let show_in_menu = by_provider
 7280            && self
 7281                .edit_prediction_provider
 7282                .as_ref()
 7283                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7284
 7285        let preview_requires_modifier =
 7286            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7287
 7288        EditPredictionSettings::Enabled {
 7289            show_in_menu,
 7290            preview_requires_modifier,
 7291        }
 7292    }
 7293
 7294    fn should_show_edit_predictions(&self) -> bool {
 7295        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7296    }
 7297
 7298    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7299        matches!(
 7300            self.edit_prediction_preview,
 7301            EditPredictionPreview::Active { .. }
 7302        )
 7303    }
 7304
 7305    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7306        let cursor = self.selections.newest_anchor().head();
 7307        if let Some((buffer, cursor_position)) =
 7308            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7309        {
 7310            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7311        } else {
 7312            false
 7313        }
 7314    }
 7315
 7316    pub fn supports_minimap(&self, cx: &App) -> bool {
 7317        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7318    }
 7319
 7320    fn edit_predictions_enabled_in_buffer(
 7321        &self,
 7322        buffer: &Entity<Buffer>,
 7323        buffer_position: language::Anchor,
 7324        cx: &App,
 7325    ) -> bool {
 7326        maybe!({
 7327            if self.read_only(cx) {
 7328                return Some(false);
 7329            }
 7330            let provider = self.edit_prediction_provider()?;
 7331            if !provider.is_enabled(buffer, buffer_position, cx) {
 7332                return Some(false);
 7333            }
 7334            let buffer = buffer.read(cx);
 7335            let Some(file) = buffer.file() else {
 7336                return Some(true);
 7337            };
 7338            let settings = all_language_settings(Some(file), cx);
 7339            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7340        })
 7341        .unwrap_or(false)
 7342    }
 7343
 7344    fn cycle_edit_prediction(
 7345        &mut self,
 7346        direction: Direction,
 7347        window: &mut Window,
 7348        cx: &mut Context<Self>,
 7349    ) -> Option<()> {
 7350        let provider = self.edit_prediction_provider()?;
 7351        let cursor = self.selections.newest_anchor().head();
 7352        let (buffer, cursor_buffer_position) =
 7353            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7354        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7355            return None;
 7356        }
 7357
 7358        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7359        self.update_visible_edit_prediction(window, cx);
 7360
 7361        Some(())
 7362    }
 7363
 7364    pub fn show_edit_prediction(
 7365        &mut self,
 7366        _: &ShowEditPrediction,
 7367        window: &mut Window,
 7368        cx: &mut Context<Self>,
 7369    ) {
 7370        if !self.has_active_edit_prediction() {
 7371            self.refresh_edit_prediction(false, true, window, cx);
 7372            return;
 7373        }
 7374
 7375        self.update_visible_edit_prediction(window, cx);
 7376    }
 7377
 7378    pub fn display_cursor_names(
 7379        &mut self,
 7380        _: &DisplayCursorNames,
 7381        window: &mut Window,
 7382        cx: &mut Context<Self>,
 7383    ) {
 7384        self.show_cursor_names(window, cx);
 7385    }
 7386
 7387    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7388        self.show_cursor_names = true;
 7389        cx.notify();
 7390        cx.spawn_in(window, async move |this, cx| {
 7391            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7392            this.update(cx, |this, cx| {
 7393                this.show_cursor_names = false;
 7394                cx.notify()
 7395            })
 7396            .ok()
 7397        })
 7398        .detach();
 7399    }
 7400
 7401    pub fn next_edit_prediction(
 7402        &mut self,
 7403        _: &NextEditPrediction,
 7404        window: &mut Window,
 7405        cx: &mut Context<Self>,
 7406    ) {
 7407        if self.has_active_edit_prediction() {
 7408            self.cycle_edit_prediction(Direction::Next, window, cx);
 7409        } else {
 7410            let is_copilot_disabled = self
 7411                .refresh_edit_prediction(false, true, window, cx)
 7412                .is_none();
 7413            if is_copilot_disabled {
 7414                cx.propagate();
 7415            }
 7416        }
 7417    }
 7418
 7419    pub fn previous_edit_prediction(
 7420        &mut self,
 7421        _: &PreviousEditPrediction,
 7422        window: &mut Window,
 7423        cx: &mut Context<Self>,
 7424    ) {
 7425        if self.has_active_edit_prediction() {
 7426            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7427        } else {
 7428            let is_copilot_disabled = self
 7429                .refresh_edit_prediction(false, true, window, cx)
 7430                .is_none();
 7431            if is_copilot_disabled {
 7432                cx.propagate();
 7433            }
 7434        }
 7435    }
 7436
 7437    pub fn accept_edit_prediction(
 7438        &mut self,
 7439        _: &AcceptEditPrediction,
 7440        window: &mut Window,
 7441        cx: &mut Context<Self>,
 7442    ) {
 7443        if self.show_edit_predictions_in_menu() {
 7444            self.hide_context_menu(window, cx);
 7445        }
 7446
 7447        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7448            return;
 7449        };
 7450
 7451        match &active_edit_prediction.completion {
 7452            EditPrediction::MoveWithin { target, .. } => {
 7453                let target = *target;
 7454
 7455                if let Some(position_map) = &self.last_position_map {
 7456                    if position_map
 7457                        .visible_row_range
 7458                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7459                        || !self.edit_prediction_requires_modifier()
 7460                    {
 7461                        self.unfold_ranges(&[target..target], true, false, cx);
 7462                        // Note that this is also done in vim's handler of the Tab action.
 7463                        self.change_selections(
 7464                            SelectionEffects::scroll(Autoscroll::newest()),
 7465                            window,
 7466                            cx,
 7467                            |selections| {
 7468                                selections.select_anchor_ranges([target..target]);
 7469                            },
 7470                        );
 7471                        self.clear_row_highlights::<EditPredictionPreview>();
 7472
 7473                        self.edit_prediction_preview
 7474                            .set_previous_scroll_position(None);
 7475                    } else {
 7476                        self.edit_prediction_preview
 7477                            .set_previous_scroll_position(Some(
 7478                                position_map.snapshot.scroll_anchor,
 7479                            ));
 7480
 7481                        self.highlight_rows::<EditPredictionPreview>(
 7482                            target..target,
 7483                            cx.theme().colors().editor_highlighted_line_background,
 7484                            RowHighlightOptions {
 7485                                autoscroll: true,
 7486                                ..Default::default()
 7487                            },
 7488                            cx,
 7489                        );
 7490                        self.request_autoscroll(Autoscroll::fit(), cx);
 7491                    }
 7492                }
 7493            }
 7494            EditPrediction::MoveOutside { snapshot, target } => {
 7495                if let Some(workspace) = self.workspace() {
 7496                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7497                        .detach_and_log_err(cx);
 7498                }
 7499            }
 7500            EditPrediction::Edit { edits, .. } => {
 7501                self.report_edit_prediction_event(
 7502                    active_edit_prediction.completion_id.clone(),
 7503                    true,
 7504                    cx,
 7505                );
 7506
 7507                if let Some(provider) = self.edit_prediction_provider() {
 7508                    provider.accept(cx);
 7509                }
 7510
 7511                // Store the transaction ID and selections before applying the edit
 7512                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7513
 7514                let snapshot = self.buffer.read(cx).snapshot(cx);
 7515                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7516
 7517                self.buffer.update(cx, |buffer, cx| {
 7518                    buffer.edit(edits.iter().cloned(), None, cx)
 7519                });
 7520
 7521                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7522                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7523                });
 7524
 7525                let selections = self.selections.disjoint_anchors_arc();
 7526                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7527                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7528                    if has_new_transaction {
 7529                        self.selection_history
 7530                            .insert_transaction(transaction_id_now, selections);
 7531                    }
 7532                }
 7533
 7534                self.update_visible_edit_prediction(window, cx);
 7535                if self.active_edit_prediction.is_none() {
 7536                    self.refresh_edit_prediction(true, true, window, cx);
 7537                }
 7538
 7539                cx.notify();
 7540            }
 7541        }
 7542
 7543        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7544    }
 7545
 7546    pub fn accept_partial_edit_prediction(
 7547        &mut self,
 7548        _: &AcceptPartialEditPrediction,
 7549        window: &mut Window,
 7550        cx: &mut Context<Self>,
 7551    ) {
 7552        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7553            return;
 7554        };
 7555        if self.selections.count() != 1 {
 7556            return;
 7557        }
 7558
 7559        match &active_edit_prediction.completion {
 7560            EditPrediction::MoveWithin { target, .. } => {
 7561                let target = *target;
 7562                self.change_selections(
 7563                    SelectionEffects::scroll(Autoscroll::newest()),
 7564                    window,
 7565                    cx,
 7566                    |selections| {
 7567                        selections.select_anchor_ranges([target..target]);
 7568                    },
 7569                );
 7570            }
 7571            EditPrediction::MoveOutside { snapshot, target } => {
 7572                if let Some(workspace) = self.workspace() {
 7573                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7574                        .detach_and_log_err(cx);
 7575                }
 7576            }
 7577            EditPrediction::Edit { edits, .. } => {
 7578                self.report_edit_prediction_event(
 7579                    active_edit_prediction.completion_id.clone(),
 7580                    true,
 7581                    cx,
 7582                );
 7583
 7584                // Find an insertion that starts at the cursor position.
 7585                let snapshot = self.buffer.read(cx).snapshot(cx);
 7586                let cursor_offset = self
 7587                    .selections
 7588                    .newest::<usize>(&self.display_snapshot(cx))
 7589                    .head();
 7590                let insertion = edits.iter().find_map(|(range, text)| {
 7591                    let range = range.to_offset(&snapshot);
 7592                    if range.is_empty() && range.start == cursor_offset {
 7593                        Some(text)
 7594                    } else {
 7595                        None
 7596                    }
 7597                });
 7598
 7599                if let Some(text) = insertion {
 7600                    let mut partial_completion = text
 7601                        .chars()
 7602                        .by_ref()
 7603                        .take_while(|c| c.is_alphabetic())
 7604                        .collect::<String>();
 7605                    if partial_completion.is_empty() {
 7606                        partial_completion = text
 7607                            .chars()
 7608                            .by_ref()
 7609                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7610                            .collect::<String>();
 7611                    }
 7612
 7613                    cx.emit(EditorEvent::InputHandled {
 7614                        utf16_range_to_replace: None,
 7615                        text: partial_completion.clone().into(),
 7616                    });
 7617
 7618                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7619
 7620                    self.refresh_edit_prediction(true, true, window, cx);
 7621                    cx.notify();
 7622                } else {
 7623                    self.accept_edit_prediction(&Default::default(), window, cx);
 7624                }
 7625            }
 7626        }
 7627    }
 7628
 7629    fn discard_edit_prediction(
 7630        &mut self,
 7631        should_report_edit_prediction_event: bool,
 7632        cx: &mut Context<Self>,
 7633    ) -> bool {
 7634        if should_report_edit_prediction_event {
 7635            let completion_id = self
 7636                .active_edit_prediction
 7637                .as_ref()
 7638                .and_then(|active_completion| active_completion.completion_id.clone());
 7639
 7640            self.report_edit_prediction_event(completion_id, false, cx);
 7641        }
 7642
 7643        if let Some(provider) = self.edit_prediction_provider() {
 7644            provider.discard(cx);
 7645        }
 7646
 7647        self.take_active_edit_prediction(cx)
 7648    }
 7649
 7650    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7651        let Some(provider) = self.edit_prediction_provider() else {
 7652            return;
 7653        };
 7654
 7655        let Some((_, buffer, _)) = self
 7656            .buffer
 7657            .read(cx)
 7658            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7659        else {
 7660            return;
 7661        };
 7662
 7663        let extension = buffer
 7664            .read(cx)
 7665            .file()
 7666            .and_then(|file| Some(file.path().extension()?.to_string()));
 7667
 7668        let event_type = match accepted {
 7669            true => "Edit Prediction Accepted",
 7670            false => "Edit Prediction Discarded",
 7671        };
 7672        telemetry::event!(
 7673            event_type,
 7674            provider = provider.name(),
 7675            prediction_id = id,
 7676            suggestion_accepted = accepted,
 7677            file_extension = extension,
 7678        );
 7679    }
 7680
 7681    fn open_editor_at_anchor(
 7682        snapshot: &language::BufferSnapshot,
 7683        target: language::Anchor,
 7684        workspace: &Entity<Workspace>,
 7685        window: &mut Window,
 7686        cx: &mut App,
 7687    ) -> Task<Result<()>> {
 7688        workspace.update(cx, |workspace, cx| {
 7689            let path = snapshot.file().map(|file| file.full_path(cx));
 7690            let Some(path) =
 7691                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7692            else {
 7693                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7694            };
 7695            let target = text::ToPoint::to_point(&target, snapshot);
 7696            let item = workspace.open_path(path, None, true, window, cx);
 7697            window.spawn(cx, async move |cx| {
 7698                let Some(editor) = item.await?.downcast::<Editor>() else {
 7699                    return Ok(());
 7700                };
 7701                editor
 7702                    .update_in(cx, |editor, window, cx| {
 7703                        editor.go_to_singleton_buffer_point(target, window, cx);
 7704                    })
 7705                    .ok();
 7706                anyhow::Ok(())
 7707            })
 7708        })
 7709    }
 7710
 7711    pub fn has_active_edit_prediction(&self) -> bool {
 7712        self.active_edit_prediction.is_some()
 7713    }
 7714
 7715    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7716        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7717            return false;
 7718        };
 7719
 7720        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7721        self.clear_highlights::<EditPredictionHighlight>(cx);
 7722        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7723        true
 7724    }
 7725
 7726    /// Returns true when we're displaying the edit prediction popover below the cursor
 7727    /// like we are not previewing and the LSP autocomplete menu is visible
 7728    /// or we are in `when_holding_modifier` mode.
 7729    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7730        if self.edit_prediction_preview_is_active()
 7731            || !self.show_edit_predictions_in_menu()
 7732            || !self.edit_predictions_enabled()
 7733        {
 7734            return false;
 7735        }
 7736
 7737        if self.has_visible_completions_menu() {
 7738            return true;
 7739        }
 7740
 7741        has_completion && self.edit_prediction_requires_modifier()
 7742    }
 7743
 7744    fn handle_modifiers_changed(
 7745        &mut self,
 7746        modifiers: Modifiers,
 7747        position_map: &PositionMap,
 7748        window: &mut Window,
 7749        cx: &mut Context<Self>,
 7750    ) {
 7751        // Ensure that the edit prediction preview is updated, even when not
 7752        // enabled, if there's an active edit prediction preview.
 7753        if self.show_edit_predictions_in_menu()
 7754            || matches!(
 7755                self.edit_prediction_preview,
 7756                EditPredictionPreview::Active { .. }
 7757            )
 7758        {
 7759            self.update_edit_prediction_preview(&modifiers, window, cx);
 7760        }
 7761
 7762        self.update_selection_mode(&modifiers, position_map, window, cx);
 7763
 7764        let mouse_position = window.mouse_position();
 7765        if !position_map.text_hitbox.is_hovered(window) {
 7766            return;
 7767        }
 7768
 7769        self.update_hovered_link(
 7770            position_map.point_for_position(mouse_position),
 7771            &position_map.snapshot,
 7772            modifiers,
 7773            window,
 7774            cx,
 7775        )
 7776    }
 7777
 7778    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7779        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7780            MultiCursorModifier::Alt => modifiers.secondary(),
 7781            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7782        }
 7783    }
 7784
 7785    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7786        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7787            MultiCursorModifier::Alt => modifiers.alt,
 7788            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7789        }
 7790    }
 7791
 7792    fn columnar_selection_mode(
 7793        modifiers: &Modifiers,
 7794        cx: &mut Context<Self>,
 7795    ) -> Option<ColumnarMode> {
 7796        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7797            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7798                Some(ColumnarMode::FromMouse)
 7799            } else if Self::is_alt_pressed(modifiers, cx) {
 7800                Some(ColumnarMode::FromSelection)
 7801            } else {
 7802                None
 7803            }
 7804        } else {
 7805            None
 7806        }
 7807    }
 7808
 7809    fn update_selection_mode(
 7810        &mut self,
 7811        modifiers: &Modifiers,
 7812        position_map: &PositionMap,
 7813        window: &mut Window,
 7814        cx: &mut Context<Self>,
 7815    ) {
 7816        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7817            return;
 7818        };
 7819        if self.selections.pending_anchor().is_none() {
 7820            return;
 7821        }
 7822
 7823        let mouse_position = window.mouse_position();
 7824        let point_for_position = position_map.point_for_position(mouse_position);
 7825        let position = point_for_position.previous_valid;
 7826
 7827        self.select(
 7828            SelectPhase::BeginColumnar {
 7829                position,
 7830                reset: false,
 7831                mode,
 7832                goal_column: point_for_position.exact_unclipped.column(),
 7833            },
 7834            window,
 7835            cx,
 7836        );
 7837    }
 7838
 7839    fn update_edit_prediction_preview(
 7840        &mut self,
 7841        modifiers: &Modifiers,
 7842        window: &mut Window,
 7843        cx: &mut Context<Self>,
 7844    ) {
 7845        let mut modifiers_held = false;
 7846        if let Some(accept_keystroke) = self
 7847            .accept_edit_prediction_keybind(false, window, cx)
 7848            .keystroke()
 7849        {
 7850            modifiers_held = modifiers_held
 7851                || (accept_keystroke.modifiers() == modifiers
 7852                    && accept_keystroke.modifiers().modified());
 7853        };
 7854        if let Some(accept_partial_keystroke) = self
 7855            .accept_edit_prediction_keybind(true, window, cx)
 7856            .keystroke()
 7857        {
 7858            modifiers_held = modifiers_held
 7859                || (accept_partial_keystroke.modifiers() == modifiers
 7860                    && accept_partial_keystroke.modifiers().modified());
 7861        }
 7862
 7863        if modifiers_held {
 7864            if matches!(
 7865                self.edit_prediction_preview,
 7866                EditPredictionPreview::Inactive { .. }
 7867            ) {
 7868                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7869                    provider.provider.did_show(cx)
 7870                }
 7871
 7872                self.edit_prediction_preview = EditPredictionPreview::Active {
 7873                    previous_scroll_position: None,
 7874                    since: Instant::now(),
 7875                };
 7876
 7877                self.update_visible_edit_prediction(window, cx);
 7878                cx.notify();
 7879            }
 7880        } else if let EditPredictionPreview::Active {
 7881            previous_scroll_position,
 7882            since,
 7883        } = self.edit_prediction_preview
 7884        {
 7885            if let (Some(previous_scroll_position), Some(position_map)) =
 7886                (previous_scroll_position, self.last_position_map.as_ref())
 7887            {
 7888                self.set_scroll_position(
 7889                    previous_scroll_position
 7890                        .scroll_position(&position_map.snapshot.display_snapshot),
 7891                    window,
 7892                    cx,
 7893                );
 7894            }
 7895
 7896            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7897                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7898            };
 7899            self.clear_row_highlights::<EditPredictionPreview>();
 7900            self.update_visible_edit_prediction(window, cx);
 7901            cx.notify();
 7902        }
 7903    }
 7904
 7905    fn update_visible_edit_prediction(
 7906        &mut self,
 7907        _window: &mut Window,
 7908        cx: &mut Context<Self>,
 7909    ) -> Option<()> {
 7910        if DisableAiSettings::get_global(cx).disable_ai {
 7911            return None;
 7912        }
 7913
 7914        if self.ime_transaction.is_some() {
 7915            self.discard_edit_prediction(false, cx);
 7916            return None;
 7917        }
 7918
 7919        let selection = self.selections.newest_anchor();
 7920        let cursor = selection.head();
 7921        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7922        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7923        let excerpt_id = cursor.excerpt_id;
 7924
 7925        let show_in_menu = self.show_edit_predictions_in_menu();
 7926        let completions_menu_has_precedence = !show_in_menu
 7927            && (self.context_menu.borrow().is_some()
 7928                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7929
 7930        if completions_menu_has_precedence
 7931            || !offset_selection.is_empty()
 7932            || self
 7933                .active_edit_prediction
 7934                .as_ref()
 7935                .is_some_and(|completion| {
 7936                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7937                        return false;
 7938                    };
 7939                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7940                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7941                    !invalidation_range.contains(&offset_selection.head())
 7942                })
 7943        {
 7944            self.discard_edit_prediction(false, cx);
 7945            return None;
 7946        }
 7947
 7948        self.take_active_edit_prediction(cx);
 7949        let Some(provider) = self.edit_prediction_provider() else {
 7950            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7951            return None;
 7952        };
 7953
 7954        let (buffer, cursor_buffer_position) =
 7955            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7956
 7957        self.edit_prediction_settings =
 7958            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7959
 7960        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7961
 7962        if self.edit_prediction_indent_conflict {
 7963            let cursor_point = cursor.to_point(&multibuffer);
 7964
 7965            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7966
 7967            if let Some((_, indent)) = indents.iter().next()
 7968                && indent.len == cursor_point.column
 7969            {
 7970                self.edit_prediction_indent_conflict = false;
 7971            }
 7972        }
 7973
 7974        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7975
 7976        let (completion_id, edits, edit_preview) = match edit_prediction {
 7977            edit_prediction::EditPrediction::Local {
 7978                id,
 7979                edits,
 7980                edit_preview,
 7981            } => (id, edits, edit_preview),
 7982            edit_prediction::EditPrediction::Jump {
 7983                id,
 7984                snapshot,
 7985                target,
 7986            } => {
 7987                self.stale_edit_prediction_in_menu = None;
 7988                self.active_edit_prediction = Some(EditPredictionState {
 7989                    inlay_ids: vec![],
 7990                    completion: EditPrediction::MoveOutside { snapshot, target },
 7991                    completion_id: id,
 7992                    invalidation_range: None,
 7993                });
 7994                cx.notify();
 7995                return Some(());
 7996            }
 7997        };
 7998
 7999        let edits = edits
 8000            .into_iter()
 8001            .flat_map(|(range, new_text)| {
 8002                Some((
 8003                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8004                    new_text,
 8005                ))
 8006            })
 8007            .collect::<Vec<_>>();
 8008        if edits.is_empty() {
 8009            return None;
 8010        }
 8011
 8012        let first_edit_start = edits.first().unwrap().0.start;
 8013        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8014        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8015
 8016        let last_edit_end = edits.last().unwrap().0.end;
 8017        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8018        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8019
 8020        let cursor_row = cursor.to_point(&multibuffer).row;
 8021
 8022        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8023
 8024        let mut inlay_ids = Vec::new();
 8025        let invalidation_row_range;
 8026        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8027            Some(cursor_row..edit_end_row)
 8028        } else if cursor_row > edit_end_row {
 8029            Some(edit_start_row..cursor_row)
 8030        } else {
 8031            None
 8032        };
 8033        let supports_jump = self
 8034            .edit_prediction_provider
 8035            .as_ref()
 8036            .map(|provider| provider.provider.supports_jump_to_edit())
 8037            .unwrap_or(true);
 8038
 8039        let is_move = supports_jump
 8040            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8041        let completion = if is_move {
 8042            invalidation_row_range =
 8043                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8044            let target = first_edit_start;
 8045            EditPrediction::MoveWithin { target, snapshot }
 8046        } else {
 8047            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8048                && !self.edit_predictions_hidden_for_vim_mode;
 8049
 8050            if show_completions_in_buffer {
 8051                if let Some(provider) = &self.edit_prediction_provider {
 8052                    provider.provider.did_show(cx);
 8053                }
 8054                if edits
 8055                    .iter()
 8056                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8057                {
 8058                    let mut inlays = Vec::new();
 8059                    for (range, new_text) in &edits {
 8060                        let inlay = Inlay::edit_prediction(
 8061                            post_inc(&mut self.next_inlay_id),
 8062                            range.start,
 8063                            new_text.as_ref(),
 8064                        );
 8065                        inlay_ids.push(inlay.id);
 8066                        inlays.push(inlay);
 8067                    }
 8068
 8069                    self.splice_inlays(&[], inlays, cx);
 8070                } else {
 8071                    let background_color = cx.theme().status().deleted_background;
 8072                    self.highlight_text::<EditPredictionHighlight>(
 8073                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8074                        HighlightStyle {
 8075                            background_color: Some(background_color),
 8076                            ..Default::default()
 8077                        },
 8078                        cx,
 8079                    );
 8080                }
 8081            }
 8082
 8083            invalidation_row_range = edit_start_row..edit_end_row;
 8084
 8085            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8086                if provider.show_tab_accept_marker() {
 8087                    EditDisplayMode::TabAccept
 8088                } else {
 8089                    EditDisplayMode::Inline
 8090                }
 8091            } else {
 8092                EditDisplayMode::DiffPopover
 8093            };
 8094
 8095            EditPrediction::Edit {
 8096                edits,
 8097                edit_preview,
 8098                display_mode,
 8099                snapshot,
 8100            }
 8101        };
 8102
 8103        let invalidation_range = multibuffer
 8104            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8105            ..multibuffer.anchor_after(Point::new(
 8106                invalidation_row_range.end,
 8107                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8108            ));
 8109
 8110        self.stale_edit_prediction_in_menu = None;
 8111        self.active_edit_prediction = Some(EditPredictionState {
 8112            inlay_ids,
 8113            completion,
 8114            completion_id,
 8115            invalidation_range: Some(invalidation_range),
 8116        });
 8117
 8118        cx.notify();
 8119
 8120        Some(())
 8121    }
 8122
 8123    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8124        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8125    }
 8126
 8127    fn clear_tasks(&mut self) {
 8128        self.tasks.clear()
 8129    }
 8130
 8131    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8132        if self.tasks.insert(key, value).is_some() {
 8133            // This case should hopefully be rare, but just in case...
 8134            log::error!(
 8135                "multiple different run targets found on a single line, only the last target will be rendered"
 8136            )
 8137        }
 8138    }
 8139
 8140    /// Get all display points of breakpoints that will be rendered within editor
 8141    ///
 8142    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8143    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8144    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8145    fn active_breakpoints(
 8146        &self,
 8147        range: Range<DisplayRow>,
 8148        window: &mut Window,
 8149        cx: &mut Context<Self>,
 8150    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8151        let mut breakpoint_display_points = HashMap::default();
 8152
 8153        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8154            return breakpoint_display_points;
 8155        };
 8156
 8157        let snapshot = self.snapshot(window, cx);
 8158
 8159        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8160        let Some(project) = self.project() else {
 8161            return breakpoint_display_points;
 8162        };
 8163
 8164        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8165            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8166
 8167        for (buffer_snapshot, range, excerpt_id) in
 8168            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8169        {
 8170            let Some(buffer) = project
 8171                .read(cx)
 8172                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8173            else {
 8174                continue;
 8175            };
 8176            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8177                &buffer,
 8178                Some(
 8179                    buffer_snapshot.anchor_before(range.start)
 8180                        ..buffer_snapshot.anchor_after(range.end),
 8181                ),
 8182                buffer_snapshot,
 8183                cx,
 8184            );
 8185            for (breakpoint, state) in breakpoints {
 8186                let multi_buffer_anchor =
 8187                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8188                let position = multi_buffer_anchor
 8189                    .to_point(&multi_buffer_snapshot)
 8190                    .to_display_point(&snapshot);
 8191
 8192                breakpoint_display_points.insert(
 8193                    position.row(),
 8194                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8195                );
 8196            }
 8197        }
 8198
 8199        breakpoint_display_points
 8200    }
 8201
 8202    fn breakpoint_context_menu(
 8203        &self,
 8204        anchor: Anchor,
 8205        window: &mut Window,
 8206        cx: &mut Context<Self>,
 8207    ) -> Entity<ui::ContextMenu> {
 8208        let weak_editor = cx.weak_entity();
 8209        let focus_handle = self.focus_handle(cx);
 8210
 8211        let row = self
 8212            .buffer
 8213            .read(cx)
 8214            .snapshot(cx)
 8215            .summary_for_anchor::<Point>(&anchor)
 8216            .row;
 8217
 8218        let breakpoint = self
 8219            .breakpoint_at_row(row, window, cx)
 8220            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8221
 8222        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8223            "Edit Log Breakpoint"
 8224        } else {
 8225            "Set Log Breakpoint"
 8226        };
 8227
 8228        let condition_breakpoint_msg = if breakpoint
 8229            .as_ref()
 8230            .is_some_and(|bp| bp.1.condition.is_some())
 8231        {
 8232            "Edit Condition Breakpoint"
 8233        } else {
 8234            "Set Condition Breakpoint"
 8235        };
 8236
 8237        let hit_condition_breakpoint_msg = if breakpoint
 8238            .as_ref()
 8239            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8240        {
 8241            "Edit Hit Condition Breakpoint"
 8242        } else {
 8243            "Set Hit Condition Breakpoint"
 8244        };
 8245
 8246        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8247            "Unset Breakpoint"
 8248        } else {
 8249            "Set Breakpoint"
 8250        };
 8251
 8252        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8253
 8254        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8255            BreakpointState::Enabled => Some("Disable"),
 8256            BreakpointState::Disabled => Some("Enable"),
 8257        });
 8258
 8259        let (anchor, breakpoint) =
 8260            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8261
 8262        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8263            menu.on_blur_subscription(Subscription::new(|| {}))
 8264                .context(focus_handle)
 8265                .when(run_to_cursor, |this| {
 8266                    let weak_editor = weak_editor.clone();
 8267                    this.entry("Run to cursor", None, move |window, cx| {
 8268                        weak_editor
 8269                            .update(cx, |editor, cx| {
 8270                                editor.change_selections(
 8271                                    SelectionEffects::no_scroll(),
 8272                                    window,
 8273                                    cx,
 8274                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8275                                );
 8276                            })
 8277                            .ok();
 8278
 8279                        window.dispatch_action(Box::new(RunToCursor), cx);
 8280                    })
 8281                    .separator()
 8282                })
 8283                .when_some(toggle_state_msg, |this, msg| {
 8284                    this.entry(msg, None, {
 8285                        let weak_editor = weak_editor.clone();
 8286                        let breakpoint = breakpoint.clone();
 8287                        move |_window, cx| {
 8288                            weak_editor
 8289                                .update(cx, |this, cx| {
 8290                                    this.edit_breakpoint_at_anchor(
 8291                                        anchor,
 8292                                        breakpoint.as_ref().clone(),
 8293                                        BreakpointEditAction::InvertState,
 8294                                        cx,
 8295                                    );
 8296                                })
 8297                                .log_err();
 8298                        }
 8299                    })
 8300                })
 8301                .entry(set_breakpoint_msg, None, {
 8302                    let weak_editor = weak_editor.clone();
 8303                    let breakpoint = breakpoint.clone();
 8304                    move |_window, cx| {
 8305                        weak_editor
 8306                            .update(cx, |this, cx| {
 8307                                this.edit_breakpoint_at_anchor(
 8308                                    anchor,
 8309                                    breakpoint.as_ref().clone(),
 8310                                    BreakpointEditAction::Toggle,
 8311                                    cx,
 8312                                );
 8313                            })
 8314                            .log_err();
 8315                    }
 8316                })
 8317                .entry(log_breakpoint_msg, None, {
 8318                    let breakpoint = breakpoint.clone();
 8319                    let weak_editor = weak_editor.clone();
 8320                    move |window, cx| {
 8321                        weak_editor
 8322                            .update(cx, |this, cx| {
 8323                                this.add_edit_breakpoint_block(
 8324                                    anchor,
 8325                                    breakpoint.as_ref(),
 8326                                    BreakpointPromptEditAction::Log,
 8327                                    window,
 8328                                    cx,
 8329                                );
 8330                            })
 8331                            .log_err();
 8332                    }
 8333                })
 8334                .entry(condition_breakpoint_msg, None, {
 8335                    let breakpoint = breakpoint.clone();
 8336                    let weak_editor = weak_editor.clone();
 8337                    move |window, cx| {
 8338                        weak_editor
 8339                            .update(cx, |this, cx| {
 8340                                this.add_edit_breakpoint_block(
 8341                                    anchor,
 8342                                    breakpoint.as_ref(),
 8343                                    BreakpointPromptEditAction::Condition,
 8344                                    window,
 8345                                    cx,
 8346                                );
 8347                            })
 8348                            .log_err();
 8349                    }
 8350                })
 8351                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8352                    weak_editor
 8353                        .update(cx, |this, cx| {
 8354                            this.add_edit_breakpoint_block(
 8355                                anchor,
 8356                                breakpoint.as_ref(),
 8357                                BreakpointPromptEditAction::HitCondition,
 8358                                window,
 8359                                cx,
 8360                            );
 8361                        })
 8362                        .log_err();
 8363                })
 8364        })
 8365    }
 8366
 8367    fn render_breakpoint(
 8368        &self,
 8369        position: Anchor,
 8370        row: DisplayRow,
 8371        breakpoint: &Breakpoint,
 8372        state: Option<BreakpointSessionState>,
 8373        cx: &mut Context<Self>,
 8374    ) -> IconButton {
 8375        let is_rejected = state.is_some_and(|s| !s.verified);
 8376        // Is it a breakpoint that shows up when hovering over gutter?
 8377        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8378            (false, false),
 8379            |PhantomBreakpointIndicator {
 8380                 is_active,
 8381                 display_row,
 8382                 collides_with_existing_breakpoint,
 8383             }| {
 8384                (
 8385                    is_active && display_row == row,
 8386                    collides_with_existing_breakpoint,
 8387                )
 8388            },
 8389        );
 8390
 8391        let (color, icon) = {
 8392            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8393                (false, false) => ui::IconName::DebugBreakpoint,
 8394                (true, false) => ui::IconName::DebugLogBreakpoint,
 8395                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8396                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8397            };
 8398
 8399            let color = if is_phantom {
 8400                Color::Hint
 8401            } else if is_rejected {
 8402                Color::Disabled
 8403            } else {
 8404                Color::Debugger
 8405            };
 8406
 8407            (color, icon)
 8408        };
 8409
 8410        let breakpoint = Arc::from(breakpoint.clone());
 8411
 8412        let alt_as_text = gpui::Keystroke {
 8413            modifiers: Modifiers::secondary_key(),
 8414            ..Default::default()
 8415        };
 8416        let primary_action_text = if breakpoint.is_disabled() {
 8417            "Enable breakpoint"
 8418        } else if is_phantom && !collides_with_existing {
 8419            "Set breakpoint"
 8420        } else {
 8421            "Unset breakpoint"
 8422        };
 8423        let focus_handle = self.focus_handle.clone();
 8424
 8425        let meta = if is_rejected {
 8426            SharedString::from("No executable code is associated with this line.")
 8427        } else if collides_with_existing && !breakpoint.is_disabled() {
 8428            SharedString::from(format!(
 8429                "{alt_as_text}-click to disable,\nright-click for more options."
 8430            ))
 8431        } else {
 8432            SharedString::from("Right-click for more options.")
 8433        };
 8434        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8435            .icon_size(IconSize::XSmall)
 8436            .size(ui::ButtonSize::None)
 8437            .when(is_rejected, |this| {
 8438                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8439            })
 8440            .icon_color(color)
 8441            .style(ButtonStyle::Transparent)
 8442            .on_click(cx.listener({
 8443                move |editor, event: &ClickEvent, window, cx| {
 8444                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8445                        BreakpointEditAction::InvertState
 8446                    } else {
 8447                        BreakpointEditAction::Toggle
 8448                    };
 8449
 8450                    window.focus(&editor.focus_handle(cx));
 8451                    editor.edit_breakpoint_at_anchor(
 8452                        position,
 8453                        breakpoint.as_ref().clone(),
 8454                        edit_action,
 8455                        cx,
 8456                    );
 8457                }
 8458            }))
 8459            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8460                editor.set_breakpoint_context_menu(
 8461                    row,
 8462                    Some(position),
 8463                    event.position(),
 8464                    window,
 8465                    cx,
 8466                );
 8467            }))
 8468            .tooltip(move |_window, cx| {
 8469                Tooltip::with_meta_in(
 8470                    primary_action_text,
 8471                    Some(&ToggleBreakpoint),
 8472                    meta.clone(),
 8473                    &focus_handle,
 8474                    cx,
 8475                )
 8476            })
 8477    }
 8478
 8479    fn build_tasks_context(
 8480        project: &Entity<Project>,
 8481        buffer: &Entity<Buffer>,
 8482        buffer_row: u32,
 8483        tasks: &Arc<RunnableTasks>,
 8484        cx: &mut Context<Self>,
 8485    ) -> Task<Option<task::TaskContext>> {
 8486        let position = Point::new(buffer_row, tasks.column);
 8487        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8488        let location = Location {
 8489            buffer: buffer.clone(),
 8490            range: range_start..range_start,
 8491        };
 8492        // Fill in the environmental variables from the tree-sitter captures
 8493        let mut captured_task_variables = TaskVariables::default();
 8494        for (capture_name, value) in tasks.extra_variables.clone() {
 8495            captured_task_variables.insert(
 8496                task::VariableName::Custom(capture_name.into()),
 8497                value.clone(),
 8498            );
 8499        }
 8500        project.update(cx, |project, cx| {
 8501            project.task_store().update(cx, |task_store, cx| {
 8502                task_store.task_context_for_location(captured_task_variables, location, cx)
 8503            })
 8504        })
 8505    }
 8506
 8507    pub fn spawn_nearest_task(
 8508        &mut self,
 8509        action: &SpawnNearestTask,
 8510        window: &mut Window,
 8511        cx: &mut Context<Self>,
 8512    ) {
 8513        let Some((workspace, _)) = self.workspace.clone() else {
 8514            return;
 8515        };
 8516        let Some(project) = self.project.clone() else {
 8517            return;
 8518        };
 8519
 8520        // Try to find a closest, enclosing node using tree-sitter that has a task
 8521        let Some((buffer, buffer_row, tasks)) = self
 8522            .find_enclosing_node_task(cx)
 8523            // Or find the task that's closest in row-distance.
 8524            .or_else(|| self.find_closest_task(cx))
 8525        else {
 8526            return;
 8527        };
 8528
 8529        let reveal_strategy = action.reveal;
 8530        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8531        cx.spawn_in(window, async move |_, cx| {
 8532            let context = task_context.await?;
 8533            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8534
 8535            let resolved = &mut resolved_task.resolved;
 8536            resolved.reveal = reveal_strategy;
 8537
 8538            workspace
 8539                .update_in(cx, |workspace, window, cx| {
 8540                    workspace.schedule_resolved_task(
 8541                        task_source_kind,
 8542                        resolved_task,
 8543                        false,
 8544                        window,
 8545                        cx,
 8546                    );
 8547                })
 8548                .ok()
 8549        })
 8550        .detach();
 8551    }
 8552
 8553    fn find_closest_task(
 8554        &mut self,
 8555        cx: &mut Context<Self>,
 8556    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8557        let cursor_row = self
 8558            .selections
 8559            .newest_adjusted(&self.display_snapshot(cx))
 8560            .head()
 8561            .row;
 8562
 8563        let ((buffer_id, row), tasks) = self
 8564            .tasks
 8565            .iter()
 8566            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8567
 8568        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8569        let tasks = Arc::new(tasks.to_owned());
 8570        Some((buffer, *row, tasks))
 8571    }
 8572
 8573    fn find_enclosing_node_task(
 8574        &mut self,
 8575        cx: &mut Context<Self>,
 8576    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8577        let snapshot = self.buffer.read(cx).snapshot(cx);
 8578        let offset = self
 8579            .selections
 8580            .newest::<usize>(&self.display_snapshot(cx))
 8581            .head();
 8582        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8583        let buffer_id = excerpt.buffer().remote_id();
 8584
 8585        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8586        let mut cursor = layer.node().walk();
 8587
 8588        while cursor.goto_first_child_for_byte(offset).is_some() {
 8589            if cursor.node().end_byte() == offset {
 8590                cursor.goto_next_sibling();
 8591            }
 8592        }
 8593
 8594        // Ascend to the smallest ancestor that contains the range and has a task.
 8595        loop {
 8596            let node = cursor.node();
 8597            let node_range = node.byte_range();
 8598            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8599
 8600            // Check if this node contains our offset
 8601            if node_range.start <= offset && node_range.end >= offset {
 8602                // If it contains offset, check for task
 8603                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8604                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8605                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8606                }
 8607            }
 8608
 8609            if !cursor.goto_parent() {
 8610                break;
 8611            }
 8612        }
 8613        None
 8614    }
 8615
 8616    fn render_run_indicator(
 8617        &self,
 8618        _style: &EditorStyle,
 8619        is_active: bool,
 8620        row: DisplayRow,
 8621        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8622        cx: &mut Context<Self>,
 8623    ) -> IconButton {
 8624        let color = Color::Muted;
 8625        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8626
 8627        IconButton::new(
 8628            ("run_indicator", row.0 as usize),
 8629            ui::IconName::PlayOutlined,
 8630        )
 8631        .shape(ui::IconButtonShape::Square)
 8632        .icon_size(IconSize::XSmall)
 8633        .icon_color(color)
 8634        .toggle_state(is_active)
 8635        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8636            let quick_launch = match e {
 8637                ClickEvent::Keyboard(_) => true,
 8638                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8639            };
 8640
 8641            window.focus(&editor.focus_handle(cx));
 8642            editor.toggle_code_actions(
 8643                &ToggleCodeActions {
 8644                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8645                    quick_launch,
 8646                },
 8647                window,
 8648                cx,
 8649            );
 8650        }))
 8651        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8652            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8653        }))
 8654    }
 8655
 8656    pub fn context_menu_visible(&self) -> bool {
 8657        !self.edit_prediction_preview_is_active()
 8658            && self
 8659                .context_menu
 8660                .borrow()
 8661                .as_ref()
 8662                .is_some_and(|menu| menu.visible())
 8663    }
 8664
 8665    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8666        self.context_menu
 8667            .borrow()
 8668            .as_ref()
 8669            .map(|menu| menu.origin())
 8670    }
 8671
 8672    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8673        self.context_menu_options = Some(options);
 8674    }
 8675
 8676    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8677    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8678
 8679    fn render_edit_prediction_popover(
 8680        &mut self,
 8681        text_bounds: &Bounds<Pixels>,
 8682        content_origin: gpui::Point<Pixels>,
 8683        right_margin: Pixels,
 8684        editor_snapshot: &EditorSnapshot,
 8685        visible_row_range: Range<DisplayRow>,
 8686        scroll_top: ScrollOffset,
 8687        scroll_bottom: ScrollOffset,
 8688        line_layouts: &[LineWithInvisibles],
 8689        line_height: Pixels,
 8690        scroll_position: gpui::Point<ScrollOffset>,
 8691        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8692        newest_selection_head: Option<DisplayPoint>,
 8693        editor_width: Pixels,
 8694        style: &EditorStyle,
 8695        window: &mut Window,
 8696        cx: &mut App,
 8697    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8698        if self.mode().is_minimap() {
 8699            return None;
 8700        }
 8701        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8702
 8703        if self.edit_prediction_visible_in_cursor_popover(true) {
 8704            return None;
 8705        }
 8706
 8707        match &active_edit_prediction.completion {
 8708            EditPrediction::MoveWithin { target, .. } => {
 8709                let target_display_point = target.to_display_point(editor_snapshot);
 8710
 8711                if self.edit_prediction_requires_modifier() {
 8712                    if !self.edit_prediction_preview_is_active() {
 8713                        return None;
 8714                    }
 8715
 8716                    self.render_edit_prediction_modifier_jump_popover(
 8717                        text_bounds,
 8718                        content_origin,
 8719                        visible_row_range,
 8720                        line_layouts,
 8721                        line_height,
 8722                        scroll_pixel_position,
 8723                        newest_selection_head,
 8724                        target_display_point,
 8725                        window,
 8726                        cx,
 8727                    )
 8728                } else {
 8729                    self.render_edit_prediction_eager_jump_popover(
 8730                        text_bounds,
 8731                        content_origin,
 8732                        editor_snapshot,
 8733                        visible_row_range,
 8734                        scroll_top,
 8735                        scroll_bottom,
 8736                        line_height,
 8737                        scroll_pixel_position,
 8738                        target_display_point,
 8739                        editor_width,
 8740                        window,
 8741                        cx,
 8742                    )
 8743                }
 8744            }
 8745            EditPrediction::Edit {
 8746                display_mode: EditDisplayMode::Inline,
 8747                ..
 8748            } => None,
 8749            EditPrediction::Edit {
 8750                display_mode: EditDisplayMode::TabAccept,
 8751                edits,
 8752                ..
 8753            } => {
 8754                let range = &edits.first()?.0;
 8755                let target_display_point = range.end.to_display_point(editor_snapshot);
 8756
 8757                self.render_edit_prediction_end_of_line_popover(
 8758                    "Accept",
 8759                    editor_snapshot,
 8760                    visible_row_range,
 8761                    target_display_point,
 8762                    line_height,
 8763                    scroll_pixel_position,
 8764                    content_origin,
 8765                    editor_width,
 8766                    window,
 8767                    cx,
 8768                )
 8769            }
 8770            EditPrediction::Edit {
 8771                edits,
 8772                edit_preview,
 8773                display_mode: EditDisplayMode::DiffPopover,
 8774                snapshot,
 8775            } => self.render_edit_prediction_diff_popover(
 8776                text_bounds,
 8777                content_origin,
 8778                right_margin,
 8779                editor_snapshot,
 8780                visible_row_range,
 8781                line_layouts,
 8782                line_height,
 8783                scroll_position,
 8784                scroll_pixel_position,
 8785                newest_selection_head,
 8786                editor_width,
 8787                style,
 8788                edits,
 8789                edit_preview,
 8790                snapshot,
 8791                window,
 8792                cx,
 8793            ),
 8794            EditPrediction::MoveOutside { snapshot, .. } => {
 8795                let file_name = snapshot
 8796                    .file()
 8797                    .map(|file| file.file_name(cx))
 8798                    .unwrap_or("untitled");
 8799                let mut element = self
 8800                    .render_edit_prediction_line_popover(
 8801                        format!("Jump to {file_name}"),
 8802                        Some(IconName::ZedPredict),
 8803                        window,
 8804                        cx,
 8805                    )
 8806                    .into_any();
 8807
 8808                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8809                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8810                let origin_y = text_bounds.size.height - size.height - px(30.);
 8811                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8812                element.prepaint_at(origin, window, cx);
 8813
 8814                Some((element, origin))
 8815            }
 8816        }
 8817    }
 8818
 8819    fn render_edit_prediction_modifier_jump_popover(
 8820        &mut self,
 8821        text_bounds: &Bounds<Pixels>,
 8822        content_origin: gpui::Point<Pixels>,
 8823        visible_row_range: Range<DisplayRow>,
 8824        line_layouts: &[LineWithInvisibles],
 8825        line_height: Pixels,
 8826        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8827        newest_selection_head: Option<DisplayPoint>,
 8828        target_display_point: DisplayPoint,
 8829        window: &mut Window,
 8830        cx: &mut App,
 8831    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8832        let scrolled_content_origin =
 8833            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8834
 8835        const SCROLL_PADDING_Y: Pixels = px(12.);
 8836
 8837        if target_display_point.row() < visible_row_range.start {
 8838            return self.render_edit_prediction_scroll_popover(
 8839                |_| SCROLL_PADDING_Y,
 8840                IconName::ArrowUp,
 8841                visible_row_range,
 8842                line_layouts,
 8843                newest_selection_head,
 8844                scrolled_content_origin,
 8845                window,
 8846                cx,
 8847            );
 8848        } else if target_display_point.row() >= visible_row_range.end {
 8849            return self.render_edit_prediction_scroll_popover(
 8850                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8851                IconName::ArrowDown,
 8852                visible_row_range,
 8853                line_layouts,
 8854                newest_selection_head,
 8855                scrolled_content_origin,
 8856                window,
 8857                cx,
 8858            );
 8859        }
 8860
 8861        const POLE_WIDTH: Pixels = px(2.);
 8862
 8863        let line_layout =
 8864            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8865        let target_column = target_display_point.column() as usize;
 8866
 8867        let target_x = line_layout.x_for_index(target_column);
 8868        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8869            - scroll_pixel_position.y;
 8870
 8871        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8872
 8873        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8874        border_color.l += 0.001;
 8875
 8876        let mut element = v_flex()
 8877            .items_end()
 8878            .when(flag_on_right, |el| el.items_start())
 8879            .child(if flag_on_right {
 8880                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8881                    .rounded_bl(px(0.))
 8882                    .rounded_tl(px(0.))
 8883                    .border_l_2()
 8884                    .border_color(border_color)
 8885            } else {
 8886                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8887                    .rounded_br(px(0.))
 8888                    .rounded_tr(px(0.))
 8889                    .border_r_2()
 8890                    .border_color(border_color)
 8891            })
 8892            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8893            .into_any();
 8894
 8895        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8896
 8897        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8898            - point(
 8899                if flag_on_right {
 8900                    POLE_WIDTH
 8901                } else {
 8902                    size.width - POLE_WIDTH
 8903                },
 8904                size.height - line_height,
 8905            );
 8906
 8907        origin.x = origin.x.max(content_origin.x);
 8908
 8909        element.prepaint_at(origin, window, cx);
 8910
 8911        Some((element, origin))
 8912    }
 8913
 8914    fn render_edit_prediction_scroll_popover(
 8915        &mut self,
 8916        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8917        scroll_icon: IconName,
 8918        visible_row_range: Range<DisplayRow>,
 8919        line_layouts: &[LineWithInvisibles],
 8920        newest_selection_head: Option<DisplayPoint>,
 8921        scrolled_content_origin: gpui::Point<Pixels>,
 8922        window: &mut Window,
 8923        cx: &mut App,
 8924    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8925        let mut element = self
 8926            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8927            .into_any();
 8928
 8929        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8930
 8931        let cursor = newest_selection_head?;
 8932        let cursor_row_layout =
 8933            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8934        let cursor_column = cursor.column() as usize;
 8935
 8936        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8937
 8938        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8939
 8940        element.prepaint_at(origin, window, cx);
 8941        Some((element, origin))
 8942    }
 8943
 8944    fn render_edit_prediction_eager_jump_popover(
 8945        &mut self,
 8946        text_bounds: &Bounds<Pixels>,
 8947        content_origin: gpui::Point<Pixels>,
 8948        editor_snapshot: &EditorSnapshot,
 8949        visible_row_range: Range<DisplayRow>,
 8950        scroll_top: ScrollOffset,
 8951        scroll_bottom: ScrollOffset,
 8952        line_height: Pixels,
 8953        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8954        target_display_point: DisplayPoint,
 8955        editor_width: Pixels,
 8956        window: &mut Window,
 8957        cx: &mut App,
 8958    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8959        if target_display_point.row().as_f64() < scroll_top {
 8960            let mut element = self
 8961                .render_edit_prediction_line_popover(
 8962                    "Jump to Edit",
 8963                    Some(IconName::ArrowUp),
 8964                    window,
 8965                    cx,
 8966                )
 8967                .into_any();
 8968
 8969            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8970            let offset = point(
 8971                (text_bounds.size.width - size.width) / 2.,
 8972                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8973            );
 8974
 8975            let origin = text_bounds.origin + offset;
 8976            element.prepaint_at(origin, window, cx);
 8977            Some((element, origin))
 8978        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8979            let mut element = self
 8980                .render_edit_prediction_line_popover(
 8981                    "Jump to Edit",
 8982                    Some(IconName::ArrowDown),
 8983                    window,
 8984                    cx,
 8985                )
 8986                .into_any();
 8987
 8988            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8989            let offset = point(
 8990                (text_bounds.size.width - size.width) / 2.,
 8991                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8992            );
 8993
 8994            let origin = text_bounds.origin + offset;
 8995            element.prepaint_at(origin, window, cx);
 8996            Some((element, origin))
 8997        } else {
 8998            self.render_edit_prediction_end_of_line_popover(
 8999                "Jump to Edit",
 9000                editor_snapshot,
 9001                visible_row_range,
 9002                target_display_point,
 9003                line_height,
 9004                scroll_pixel_position,
 9005                content_origin,
 9006                editor_width,
 9007                window,
 9008                cx,
 9009            )
 9010        }
 9011    }
 9012
 9013    fn render_edit_prediction_end_of_line_popover(
 9014        self: &mut Editor,
 9015        label: &'static str,
 9016        editor_snapshot: &EditorSnapshot,
 9017        visible_row_range: Range<DisplayRow>,
 9018        target_display_point: DisplayPoint,
 9019        line_height: Pixels,
 9020        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9021        content_origin: gpui::Point<Pixels>,
 9022        editor_width: Pixels,
 9023        window: &mut Window,
 9024        cx: &mut App,
 9025    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9026        let target_line_end = DisplayPoint::new(
 9027            target_display_point.row(),
 9028            editor_snapshot.line_len(target_display_point.row()),
 9029        );
 9030
 9031        let mut element = self
 9032            .render_edit_prediction_line_popover(label, None, window, cx)
 9033            .into_any();
 9034
 9035        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9036
 9037        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9038
 9039        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9040        let mut origin = start_point
 9041            + line_origin
 9042            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9043        origin.x = origin.x.max(content_origin.x);
 9044
 9045        let max_x = content_origin.x + editor_width - size.width;
 9046
 9047        if origin.x > max_x {
 9048            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9049
 9050            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9051                origin.y += offset;
 9052                IconName::ArrowUp
 9053            } else {
 9054                origin.y -= offset;
 9055                IconName::ArrowDown
 9056            };
 9057
 9058            element = self
 9059                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9060                .into_any();
 9061
 9062            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9063
 9064            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9065        }
 9066
 9067        element.prepaint_at(origin, window, cx);
 9068        Some((element, origin))
 9069    }
 9070
 9071    fn render_edit_prediction_diff_popover(
 9072        self: &Editor,
 9073        text_bounds: &Bounds<Pixels>,
 9074        content_origin: gpui::Point<Pixels>,
 9075        right_margin: Pixels,
 9076        editor_snapshot: &EditorSnapshot,
 9077        visible_row_range: Range<DisplayRow>,
 9078        line_layouts: &[LineWithInvisibles],
 9079        line_height: Pixels,
 9080        scroll_position: gpui::Point<ScrollOffset>,
 9081        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9082        newest_selection_head: Option<DisplayPoint>,
 9083        editor_width: Pixels,
 9084        style: &EditorStyle,
 9085        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9086        edit_preview: &Option<language::EditPreview>,
 9087        snapshot: &language::BufferSnapshot,
 9088        window: &mut Window,
 9089        cx: &mut App,
 9090    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9091        let edit_start = edits
 9092            .first()
 9093            .unwrap()
 9094            .0
 9095            .start
 9096            .to_display_point(editor_snapshot);
 9097        let edit_end = edits
 9098            .last()
 9099            .unwrap()
 9100            .0
 9101            .end
 9102            .to_display_point(editor_snapshot);
 9103
 9104        let is_visible = visible_row_range.contains(&edit_start.row())
 9105            || visible_row_range.contains(&edit_end.row());
 9106        if !is_visible {
 9107            return None;
 9108        }
 9109
 9110        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9111            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9112        } else {
 9113            // Fallback for providers without edit_preview
 9114            crate::edit_prediction_fallback_text(edits, cx)
 9115        };
 9116
 9117        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9118        let line_count = highlighted_edits.text.lines().count();
 9119
 9120        const BORDER_WIDTH: Pixels = px(1.);
 9121
 9122        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9123        let has_keybind = keybind.is_some();
 9124
 9125        let mut element = h_flex()
 9126            .items_start()
 9127            .child(
 9128                h_flex()
 9129                    .bg(cx.theme().colors().editor_background)
 9130                    .border(BORDER_WIDTH)
 9131                    .shadow_xs()
 9132                    .border_color(cx.theme().colors().border)
 9133                    .rounded_l_lg()
 9134                    .when(line_count > 1, |el| el.rounded_br_lg())
 9135                    .pr_1()
 9136                    .child(styled_text),
 9137            )
 9138            .child(
 9139                h_flex()
 9140                    .h(line_height + BORDER_WIDTH * 2.)
 9141                    .px_1p5()
 9142                    .gap_1()
 9143                    // Workaround: For some reason, there's a gap if we don't do this
 9144                    .ml(-BORDER_WIDTH)
 9145                    .shadow(vec![gpui::BoxShadow {
 9146                        color: gpui::black().opacity(0.05),
 9147                        offset: point(px(1.), px(1.)),
 9148                        blur_radius: px(2.),
 9149                        spread_radius: px(0.),
 9150                    }])
 9151                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9152                    .border(BORDER_WIDTH)
 9153                    .border_color(cx.theme().colors().border)
 9154                    .rounded_r_lg()
 9155                    .id("edit_prediction_diff_popover_keybind")
 9156                    .when(!has_keybind, |el| {
 9157                        let status_colors = cx.theme().status();
 9158
 9159                        el.bg(status_colors.error_background)
 9160                            .border_color(status_colors.error.opacity(0.6))
 9161                            .child(Icon::new(IconName::Info).color(Color::Error))
 9162                            .cursor_default()
 9163                            .hoverable_tooltip(move |_window, cx| {
 9164                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9165                            })
 9166                    })
 9167                    .children(keybind),
 9168            )
 9169            .into_any();
 9170
 9171        let longest_row =
 9172            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9173        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9174            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9175        } else {
 9176            layout_line(
 9177                longest_row,
 9178                editor_snapshot,
 9179                style,
 9180                editor_width,
 9181                |_| false,
 9182                window,
 9183                cx,
 9184            )
 9185            .width
 9186        };
 9187
 9188        let viewport_bounds =
 9189            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9190                right: -right_margin,
 9191                ..Default::default()
 9192            });
 9193
 9194        let x_after_longest = Pixels::from(
 9195            ScrollPixelOffset::from(
 9196                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9197            ) - scroll_pixel_position.x,
 9198        );
 9199
 9200        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9201
 9202        // Fully visible if it can be displayed within the window (allow overlapping other
 9203        // panes). However, this is only allowed if the popover starts within text_bounds.
 9204        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9205            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9206
 9207        let mut origin = if can_position_to_the_right {
 9208            point(
 9209                x_after_longest,
 9210                text_bounds.origin.y
 9211                    + Pixels::from(
 9212                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9213                            - scroll_pixel_position.y,
 9214                    ),
 9215            )
 9216        } else {
 9217            let cursor_row = newest_selection_head.map(|head| head.row());
 9218            let above_edit = edit_start
 9219                .row()
 9220                .0
 9221                .checked_sub(line_count as u32)
 9222                .map(DisplayRow);
 9223            let below_edit = Some(edit_end.row() + 1);
 9224            let above_cursor =
 9225                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9226            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9227
 9228            // Place the edit popover adjacent to the edit if there is a location
 9229            // available that is onscreen and does not obscure the cursor. Otherwise,
 9230            // place it adjacent to the cursor.
 9231            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9232                .into_iter()
 9233                .flatten()
 9234                .find(|&start_row| {
 9235                    let end_row = start_row + line_count as u32;
 9236                    visible_row_range.contains(&start_row)
 9237                        && visible_row_range.contains(&end_row)
 9238                        && cursor_row
 9239                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9240                })?;
 9241
 9242            content_origin
 9243                + point(
 9244                    Pixels::from(-scroll_pixel_position.x),
 9245                    Pixels::from(
 9246                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9247                    ),
 9248                )
 9249        };
 9250
 9251        origin.x -= BORDER_WIDTH;
 9252
 9253        window.defer_draw(element, origin, 1);
 9254
 9255        // Do not return an element, since it will already be drawn due to defer_draw.
 9256        None
 9257    }
 9258
 9259    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9260        px(30.)
 9261    }
 9262
 9263    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9264        if self.read_only(cx) {
 9265            cx.theme().players().read_only()
 9266        } else {
 9267            self.style.as_ref().unwrap().local_player
 9268        }
 9269    }
 9270
 9271    fn render_edit_prediction_accept_keybind(
 9272        &self,
 9273        window: &mut Window,
 9274        cx: &mut App,
 9275    ) -> Option<AnyElement> {
 9276        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9277        let accept_keystroke = accept_binding.keystroke()?;
 9278
 9279        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9280
 9281        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9282            Color::Accent
 9283        } else {
 9284            Color::Muted
 9285        };
 9286
 9287        h_flex()
 9288            .px_0p5()
 9289            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9290            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9291            .text_size(TextSize::XSmall.rems(cx))
 9292            .child(h_flex().children(ui::render_modifiers(
 9293                accept_keystroke.modifiers(),
 9294                PlatformStyle::platform(),
 9295                Some(modifiers_color),
 9296                Some(IconSize::XSmall.rems().into()),
 9297                true,
 9298            )))
 9299            .when(is_platform_style_mac, |parent| {
 9300                parent.child(accept_keystroke.key().to_string())
 9301            })
 9302            .when(!is_platform_style_mac, |parent| {
 9303                parent.child(
 9304                    Key::new(
 9305                        util::capitalize(accept_keystroke.key()),
 9306                        Some(Color::Default),
 9307                    )
 9308                    .size(Some(IconSize::XSmall.rems().into())),
 9309                )
 9310            })
 9311            .into_any()
 9312            .into()
 9313    }
 9314
 9315    fn render_edit_prediction_line_popover(
 9316        &self,
 9317        label: impl Into<SharedString>,
 9318        icon: Option<IconName>,
 9319        window: &mut Window,
 9320        cx: &mut App,
 9321    ) -> Stateful<Div> {
 9322        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9323
 9324        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9325        let has_keybind = keybind.is_some();
 9326
 9327        h_flex()
 9328            .id("ep-line-popover")
 9329            .py_0p5()
 9330            .pl_1()
 9331            .pr(padding_right)
 9332            .gap_1()
 9333            .rounded_md()
 9334            .border_1()
 9335            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9336            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9337            .shadow_xs()
 9338            .when(!has_keybind, |el| {
 9339                let status_colors = cx.theme().status();
 9340
 9341                el.bg(status_colors.error_background)
 9342                    .border_color(status_colors.error.opacity(0.6))
 9343                    .pl_2()
 9344                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9345                    .cursor_default()
 9346                    .hoverable_tooltip(move |_window, cx| {
 9347                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9348                    })
 9349            })
 9350            .children(keybind)
 9351            .child(
 9352                Label::new(label)
 9353                    .size(LabelSize::Small)
 9354                    .when(!has_keybind, |el| {
 9355                        el.color(cx.theme().status().error.into()).strikethrough()
 9356                    }),
 9357            )
 9358            .when(!has_keybind, |el| {
 9359                el.child(
 9360                    h_flex().ml_1().child(
 9361                        Icon::new(IconName::Info)
 9362                            .size(IconSize::Small)
 9363                            .color(cx.theme().status().error.into()),
 9364                    ),
 9365                )
 9366            })
 9367            .when_some(icon, |element, icon| {
 9368                element.child(
 9369                    div()
 9370                        .mt(px(1.5))
 9371                        .child(Icon::new(icon).size(IconSize::Small)),
 9372                )
 9373            })
 9374    }
 9375
 9376    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9377        let accent_color = cx.theme().colors().text_accent;
 9378        let editor_bg_color = cx.theme().colors().editor_background;
 9379        editor_bg_color.blend(accent_color.opacity(0.1))
 9380    }
 9381
 9382    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9383        let accent_color = cx.theme().colors().text_accent;
 9384        let editor_bg_color = cx.theme().colors().editor_background;
 9385        editor_bg_color.blend(accent_color.opacity(0.6))
 9386    }
 9387    fn get_prediction_provider_icon_name(
 9388        provider: &Option<RegisteredEditPredictionProvider>,
 9389    ) -> IconName {
 9390        match provider {
 9391            Some(provider) => match provider.provider.name() {
 9392                "copilot" => IconName::Copilot,
 9393                "supermaven" => IconName::Supermaven,
 9394                _ => IconName::ZedPredict,
 9395            },
 9396            None => IconName::ZedPredict,
 9397        }
 9398    }
 9399
 9400    fn render_edit_prediction_cursor_popover(
 9401        &self,
 9402        min_width: Pixels,
 9403        max_width: Pixels,
 9404        cursor_point: Point,
 9405        style: &EditorStyle,
 9406        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9407        _window: &Window,
 9408        cx: &mut Context<Editor>,
 9409    ) -> Option<AnyElement> {
 9410        let provider = self.edit_prediction_provider.as_ref()?;
 9411        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9412
 9413        let is_refreshing = provider.provider.is_refreshing(cx);
 9414
 9415        fn pending_completion_container(icon: IconName) -> Div {
 9416            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9417        }
 9418
 9419        let completion = match &self.active_edit_prediction {
 9420            Some(prediction) => {
 9421                if !self.has_visible_completions_menu() {
 9422                    const RADIUS: Pixels = px(6.);
 9423                    const BORDER_WIDTH: Pixels = px(1.);
 9424
 9425                    return Some(
 9426                        h_flex()
 9427                            .elevation_2(cx)
 9428                            .border(BORDER_WIDTH)
 9429                            .border_color(cx.theme().colors().border)
 9430                            .when(accept_keystroke.is_none(), |el| {
 9431                                el.border_color(cx.theme().status().error)
 9432                            })
 9433                            .rounded(RADIUS)
 9434                            .rounded_tl(px(0.))
 9435                            .overflow_hidden()
 9436                            .child(div().px_1p5().child(match &prediction.completion {
 9437                                EditPrediction::MoveWithin { target, snapshot } => {
 9438                                    use text::ToPoint as _;
 9439                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9440                                    {
 9441                                        Icon::new(IconName::ZedPredictDown)
 9442                                    } else {
 9443                                        Icon::new(IconName::ZedPredictUp)
 9444                                    }
 9445                                }
 9446                                EditPrediction::MoveOutside { .. } => {
 9447                                    // TODO [zeta2] custom icon for external jump?
 9448                                    Icon::new(provider_icon)
 9449                                }
 9450                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9451                            }))
 9452                            .child(
 9453                                h_flex()
 9454                                    .gap_1()
 9455                                    .py_1()
 9456                                    .px_2()
 9457                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9458                                    .border_l_1()
 9459                                    .border_color(cx.theme().colors().border)
 9460                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9461                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9462                                        el.child(
 9463                                            Label::new("Hold")
 9464                                                .size(LabelSize::Small)
 9465                                                .when(accept_keystroke.is_none(), |el| {
 9466                                                    el.strikethrough()
 9467                                                })
 9468                                                .line_height_style(LineHeightStyle::UiLabel),
 9469                                        )
 9470                                    })
 9471                                    .id("edit_prediction_cursor_popover_keybind")
 9472                                    .when(accept_keystroke.is_none(), |el| {
 9473                                        let status_colors = cx.theme().status();
 9474
 9475                                        el.bg(status_colors.error_background)
 9476                                            .border_color(status_colors.error.opacity(0.6))
 9477                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9478                                            .cursor_default()
 9479                                            .hoverable_tooltip(move |_window, cx| {
 9480                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9481                                                    .into()
 9482                                            })
 9483                                    })
 9484                                    .when_some(
 9485                                        accept_keystroke.as_ref(),
 9486                                        |el, accept_keystroke| {
 9487                                            el.child(h_flex().children(ui::render_modifiers(
 9488                                                accept_keystroke.modifiers(),
 9489                                                PlatformStyle::platform(),
 9490                                                Some(Color::Default),
 9491                                                Some(IconSize::XSmall.rems().into()),
 9492                                                false,
 9493                                            )))
 9494                                        },
 9495                                    ),
 9496                            )
 9497                            .into_any(),
 9498                    );
 9499                }
 9500
 9501                self.render_edit_prediction_cursor_popover_preview(
 9502                    prediction,
 9503                    cursor_point,
 9504                    style,
 9505                    cx,
 9506                )?
 9507            }
 9508
 9509            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9510                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9511                    stale_completion,
 9512                    cursor_point,
 9513                    style,
 9514                    cx,
 9515                )?,
 9516
 9517                None => pending_completion_container(provider_icon)
 9518                    .child(Label::new("...").size(LabelSize::Small)),
 9519            },
 9520
 9521            None => pending_completion_container(provider_icon)
 9522                .child(Label::new("...").size(LabelSize::Small)),
 9523        };
 9524
 9525        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9526            completion
 9527                .with_animation(
 9528                    "loading-completion",
 9529                    Animation::new(Duration::from_secs(2))
 9530                        .repeat()
 9531                        .with_easing(pulsating_between(0.4, 0.8)),
 9532                    |label, delta| label.opacity(delta),
 9533                )
 9534                .into_any_element()
 9535        } else {
 9536            completion.into_any_element()
 9537        };
 9538
 9539        let has_completion = self.active_edit_prediction.is_some();
 9540
 9541        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9542        Some(
 9543            h_flex()
 9544                .min_w(min_width)
 9545                .max_w(max_width)
 9546                .flex_1()
 9547                .elevation_2(cx)
 9548                .border_color(cx.theme().colors().border)
 9549                .child(
 9550                    div()
 9551                        .flex_1()
 9552                        .py_1()
 9553                        .px_2()
 9554                        .overflow_hidden()
 9555                        .child(completion),
 9556                )
 9557                .when_some(accept_keystroke, |el, accept_keystroke| {
 9558                    if !accept_keystroke.modifiers().modified() {
 9559                        return el;
 9560                    }
 9561
 9562                    el.child(
 9563                        h_flex()
 9564                            .h_full()
 9565                            .border_l_1()
 9566                            .rounded_r_lg()
 9567                            .border_color(cx.theme().colors().border)
 9568                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9569                            .gap_1()
 9570                            .py_1()
 9571                            .px_2()
 9572                            .child(
 9573                                h_flex()
 9574                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9575                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9576                                    .child(h_flex().children(ui::render_modifiers(
 9577                                        accept_keystroke.modifiers(),
 9578                                        PlatformStyle::platform(),
 9579                                        Some(if !has_completion {
 9580                                            Color::Muted
 9581                                        } else {
 9582                                            Color::Default
 9583                                        }),
 9584                                        None,
 9585                                        false,
 9586                                    ))),
 9587                            )
 9588                            .child(Label::new("Preview").into_any_element())
 9589                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9590                    )
 9591                })
 9592                .into_any(),
 9593        )
 9594    }
 9595
 9596    fn render_edit_prediction_cursor_popover_preview(
 9597        &self,
 9598        completion: &EditPredictionState,
 9599        cursor_point: Point,
 9600        style: &EditorStyle,
 9601        cx: &mut Context<Editor>,
 9602    ) -> Option<Div> {
 9603        use text::ToPoint as _;
 9604
 9605        fn render_relative_row_jump(
 9606            prefix: impl Into<String>,
 9607            current_row: u32,
 9608            target_row: u32,
 9609        ) -> Div {
 9610            let (row_diff, arrow) = if target_row < current_row {
 9611                (current_row - target_row, IconName::ArrowUp)
 9612            } else {
 9613                (target_row - current_row, IconName::ArrowDown)
 9614            };
 9615
 9616            h_flex()
 9617                .child(
 9618                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9619                        .color(Color::Muted)
 9620                        .size(LabelSize::Small),
 9621                )
 9622                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9623        }
 9624
 9625        let supports_jump = self
 9626            .edit_prediction_provider
 9627            .as_ref()
 9628            .map(|provider| provider.provider.supports_jump_to_edit())
 9629            .unwrap_or(true);
 9630
 9631        match &completion.completion {
 9632            EditPrediction::MoveWithin {
 9633                target, snapshot, ..
 9634            } => {
 9635                if !supports_jump {
 9636                    return None;
 9637                }
 9638
 9639                Some(
 9640                    h_flex()
 9641                        .px_2()
 9642                        .gap_2()
 9643                        .flex_1()
 9644                        .child(
 9645                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9646                                Icon::new(IconName::ZedPredictDown)
 9647                            } else {
 9648                                Icon::new(IconName::ZedPredictUp)
 9649                            },
 9650                        )
 9651                        .child(Label::new("Jump to Edit")),
 9652                )
 9653            }
 9654            EditPrediction::MoveOutside { snapshot, .. } => {
 9655                let file_name = snapshot
 9656                    .file()
 9657                    .map(|file| file.file_name(cx))
 9658                    .unwrap_or("untitled");
 9659                Some(
 9660                    h_flex()
 9661                        .px_2()
 9662                        .gap_2()
 9663                        .flex_1()
 9664                        .child(Icon::new(IconName::ZedPredict))
 9665                        .child(Label::new(format!("Jump to {file_name}"))),
 9666                )
 9667            }
 9668            EditPrediction::Edit {
 9669                edits,
 9670                edit_preview,
 9671                snapshot,
 9672                display_mode: _,
 9673            } => {
 9674                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9675
 9676                let (highlighted_edits, has_more_lines) =
 9677                    if let Some(edit_preview) = edit_preview.as_ref() {
 9678                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9679                            .first_line_preview()
 9680                    } else {
 9681                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9682                    };
 9683
 9684                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9685                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9686
 9687                let preview = h_flex()
 9688                    .gap_1()
 9689                    .min_w_16()
 9690                    .child(styled_text)
 9691                    .when(has_more_lines, |parent| parent.child(""));
 9692
 9693                let left = if supports_jump && first_edit_row != cursor_point.row {
 9694                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9695                        .into_any_element()
 9696                } else {
 9697                    let icon_name =
 9698                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9699                    Icon::new(icon_name).into_any_element()
 9700                };
 9701
 9702                Some(
 9703                    h_flex()
 9704                        .h_full()
 9705                        .flex_1()
 9706                        .gap_2()
 9707                        .pr_1()
 9708                        .overflow_x_hidden()
 9709                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9710                        .child(left)
 9711                        .child(preview),
 9712                )
 9713            }
 9714        }
 9715    }
 9716
 9717    pub fn render_context_menu(
 9718        &self,
 9719        style: &EditorStyle,
 9720        max_height_in_lines: u32,
 9721        window: &mut Window,
 9722        cx: &mut Context<Editor>,
 9723    ) -> Option<AnyElement> {
 9724        let menu = self.context_menu.borrow();
 9725        let menu = menu.as_ref()?;
 9726        if !menu.visible() {
 9727            return None;
 9728        };
 9729        Some(menu.render(style, max_height_in_lines, window, cx))
 9730    }
 9731
 9732    fn render_context_menu_aside(
 9733        &mut self,
 9734        max_size: Size<Pixels>,
 9735        window: &mut Window,
 9736        cx: &mut Context<Editor>,
 9737    ) -> Option<AnyElement> {
 9738        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9739            if menu.visible() {
 9740                menu.render_aside(max_size, window, cx)
 9741            } else {
 9742                None
 9743            }
 9744        })
 9745    }
 9746
 9747    fn hide_context_menu(
 9748        &mut self,
 9749        window: &mut Window,
 9750        cx: &mut Context<Self>,
 9751    ) -> Option<CodeContextMenu> {
 9752        cx.notify();
 9753        self.completion_tasks.clear();
 9754        let context_menu = self.context_menu.borrow_mut().take();
 9755        self.stale_edit_prediction_in_menu.take();
 9756        self.update_visible_edit_prediction(window, cx);
 9757        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9758            && let Some(completion_provider) = &self.completion_provider
 9759        {
 9760            completion_provider.selection_changed(None, window, cx);
 9761        }
 9762        context_menu
 9763    }
 9764
 9765    fn show_snippet_choices(
 9766        &mut self,
 9767        choices: &Vec<String>,
 9768        selection: Range<Anchor>,
 9769        cx: &mut Context<Self>,
 9770    ) {
 9771        let Some((_, buffer, _)) = self
 9772            .buffer()
 9773            .read(cx)
 9774            .excerpt_containing(selection.start, cx)
 9775        else {
 9776            return;
 9777        };
 9778        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9779        else {
 9780            return;
 9781        };
 9782        if buffer != end_buffer {
 9783            log::error!("expected anchor range to have matching buffer IDs");
 9784            return;
 9785        }
 9786
 9787        let id = post_inc(&mut self.next_completion_id);
 9788        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9789        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9790            CompletionsMenu::new_snippet_choices(
 9791                id,
 9792                true,
 9793                choices,
 9794                selection,
 9795                buffer,
 9796                snippet_sort_order,
 9797            ),
 9798        ));
 9799    }
 9800
 9801    pub fn insert_snippet(
 9802        &mut self,
 9803        insertion_ranges: &[Range<usize>],
 9804        snippet: Snippet,
 9805        window: &mut Window,
 9806        cx: &mut Context<Self>,
 9807    ) -> Result<()> {
 9808        struct Tabstop<T> {
 9809            is_end_tabstop: bool,
 9810            ranges: Vec<Range<T>>,
 9811            choices: Option<Vec<String>>,
 9812        }
 9813
 9814        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9815            let snippet_text: Arc<str> = snippet.text.clone().into();
 9816            let edits = insertion_ranges
 9817                .iter()
 9818                .cloned()
 9819                .map(|range| (range, snippet_text.clone()));
 9820            let autoindent_mode = AutoindentMode::Block {
 9821                original_indent_columns: Vec::new(),
 9822            };
 9823            buffer.edit(edits, Some(autoindent_mode), cx);
 9824
 9825            let snapshot = &*buffer.read(cx);
 9826            let snippet = &snippet;
 9827            snippet
 9828                .tabstops
 9829                .iter()
 9830                .map(|tabstop| {
 9831                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9832                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9833                    });
 9834                    let mut tabstop_ranges = tabstop
 9835                        .ranges
 9836                        .iter()
 9837                        .flat_map(|tabstop_range| {
 9838                            let mut delta = 0_isize;
 9839                            insertion_ranges.iter().map(move |insertion_range| {
 9840                                let insertion_start = insertion_range.start as isize + delta;
 9841                                delta +=
 9842                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9843
 9844                                let start = ((insertion_start + tabstop_range.start) as usize)
 9845                                    .min(snapshot.len());
 9846                                let end = ((insertion_start + tabstop_range.end) as usize)
 9847                                    .min(snapshot.len());
 9848                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9849                            })
 9850                        })
 9851                        .collect::<Vec<_>>();
 9852                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9853
 9854                    Tabstop {
 9855                        is_end_tabstop,
 9856                        ranges: tabstop_ranges,
 9857                        choices: tabstop.choices.clone(),
 9858                    }
 9859                })
 9860                .collect::<Vec<_>>()
 9861        });
 9862        if let Some(tabstop) = tabstops.first() {
 9863            self.change_selections(Default::default(), window, cx, |s| {
 9864                // Reverse order so that the first range is the newest created selection.
 9865                // Completions will use it and autoscroll will prioritize it.
 9866                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9867            });
 9868
 9869            if let Some(choices) = &tabstop.choices
 9870                && let Some(selection) = tabstop.ranges.first()
 9871            {
 9872                self.show_snippet_choices(choices, selection.clone(), cx)
 9873            }
 9874
 9875            // If we're already at the last tabstop and it's at the end of the snippet,
 9876            // we're done, we don't need to keep the state around.
 9877            if !tabstop.is_end_tabstop {
 9878                let choices = tabstops
 9879                    .iter()
 9880                    .map(|tabstop| tabstop.choices.clone())
 9881                    .collect();
 9882
 9883                let ranges = tabstops
 9884                    .into_iter()
 9885                    .map(|tabstop| tabstop.ranges)
 9886                    .collect::<Vec<_>>();
 9887
 9888                self.snippet_stack.push(SnippetState {
 9889                    active_index: 0,
 9890                    ranges,
 9891                    choices,
 9892                });
 9893            }
 9894
 9895            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9896            if self.autoclose_regions.is_empty() {
 9897                let snapshot = self.buffer.read(cx).snapshot(cx);
 9898                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9899                    let selection_head = selection.head();
 9900                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9901                        continue;
 9902                    };
 9903
 9904                    let mut bracket_pair = None;
 9905                    let max_lookup_length = scope
 9906                        .brackets()
 9907                        .map(|(pair, _)| {
 9908                            pair.start
 9909                                .as_str()
 9910                                .chars()
 9911                                .count()
 9912                                .max(pair.end.as_str().chars().count())
 9913                        })
 9914                        .max();
 9915                    if let Some(max_lookup_length) = max_lookup_length {
 9916                        let next_text = snapshot
 9917                            .chars_at(selection_head)
 9918                            .take(max_lookup_length)
 9919                            .collect::<String>();
 9920                        let prev_text = snapshot
 9921                            .reversed_chars_at(selection_head)
 9922                            .take(max_lookup_length)
 9923                            .collect::<String>();
 9924
 9925                        for (pair, enabled) in scope.brackets() {
 9926                            if enabled
 9927                                && pair.close
 9928                                && prev_text.starts_with(pair.start.as_str())
 9929                                && next_text.starts_with(pair.end.as_str())
 9930                            {
 9931                                bracket_pair = Some(pair.clone());
 9932                                break;
 9933                            }
 9934                        }
 9935                    }
 9936
 9937                    if let Some(pair) = bracket_pair {
 9938                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9939                        let autoclose_enabled =
 9940                            self.use_autoclose && snapshot_settings.use_autoclose;
 9941                        if autoclose_enabled {
 9942                            let start = snapshot.anchor_after(selection_head);
 9943                            let end = snapshot.anchor_after(selection_head);
 9944                            self.autoclose_regions.push(AutocloseRegion {
 9945                                selection_id: selection.id,
 9946                                range: start..end,
 9947                                pair,
 9948                            });
 9949                        }
 9950                    }
 9951                }
 9952            }
 9953        }
 9954        Ok(())
 9955    }
 9956
 9957    pub fn move_to_next_snippet_tabstop(
 9958        &mut self,
 9959        window: &mut Window,
 9960        cx: &mut Context<Self>,
 9961    ) -> bool {
 9962        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9963    }
 9964
 9965    pub fn move_to_prev_snippet_tabstop(
 9966        &mut self,
 9967        window: &mut Window,
 9968        cx: &mut Context<Self>,
 9969    ) -> bool {
 9970        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9971    }
 9972
 9973    pub fn move_to_snippet_tabstop(
 9974        &mut self,
 9975        bias: Bias,
 9976        window: &mut Window,
 9977        cx: &mut Context<Self>,
 9978    ) -> bool {
 9979        if let Some(mut snippet) = self.snippet_stack.pop() {
 9980            match bias {
 9981                Bias::Left => {
 9982                    if snippet.active_index > 0 {
 9983                        snippet.active_index -= 1;
 9984                    } else {
 9985                        self.snippet_stack.push(snippet);
 9986                        return false;
 9987                    }
 9988                }
 9989                Bias::Right => {
 9990                    if snippet.active_index + 1 < snippet.ranges.len() {
 9991                        snippet.active_index += 1;
 9992                    } else {
 9993                        self.snippet_stack.push(snippet);
 9994                        return false;
 9995                    }
 9996                }
 9997            }
 9998            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9999                self.change_selections(Default::default(), window, cx, |s| {
10000                    // Reverse order so that the first range is the newest created selection.
10001                    // Completions will use it and autoscroll will prioritize it.
10002                    s.select_ranges(current_ranges.iter().rev().cloned())
10003                });
10004
10005                if let Some(choices) = &snippet.choices[snippet.active_index]
10006                    && let Some(selection) = current_ranges.first()
10007                {
10008                    self.show_snippet_choices(choices, selection.clone(), cx);
10009                }
10010
10011                // If snippet state is not at the last tabstop, push it back on the stack
10012                if snippet.active_index + 1 < snippet.ranges.len() {
10013                    self.snippet_stack.push(snippet);
10014                }
10015                return true;
10016            }
10017        }
10018
10019        false
10020    }
10021
10022    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10023        self.transact(window, cx, |this, window, cx| {
10024            this.select_all(&SelectAll, window, cx);
10025            this.insert("", window, cx);
10026        });
10027    }
10028
10029    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10030        if self.read_only(cx) {
10031            return;
10032        }
10033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10034        self.transact(window, cx, |this, window, cx| {
10035            this.select_autoclose_pair(window, cx);
10036
10037            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10038
10039            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10040            if !this.linked_edit_ranges.is_empty() {
10041                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10042                let snapshot = this.buffer.read(cx).snapshot(cx);
10043
10044                for selection in selections.iter() {
10045                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10046                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10047                    if selection_start.buffer_id != selection_end.buffer_id {
10048                        continue;
10049                    }
10050                    if let Some(ranges) =
10051                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10052                    {
10053                        for (buffer, entries) in ranges {
10054                            linked_ranges.entry(buffer).or_default().extend(entries);
10055                        }
10056                    }
10057                }
10058            }
10059
10060            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10061            for selection in &mut selections {
10062                if selection.is_empty() {
10063                    let old_head = selection.head();
10064                    let mut new_head =
10065                        movement::left(&display_map, old_head.to_display_point(&display_map))
10066                            .to_point(&display_map);
10067                    if let Some((buffer, line_buffer_range)) = display_map
10068                        .buffer_snapshot()
10069                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10070                    {
10071                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10072                        let indent_len = match indent_size.kind {
10073                            IndentKind::Space => {
10074                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10075                            }
10076                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10077                        };
10078                        if old_head.column <= indent_size.len && old_head.column > 0 {
10079                            let indent_len = indent_len.get();
10080                            new_head = cmp::min(
10081                                new_head,
10082                                MultiBufferPoint::new(
10083                                    old_head.row,
10084                                    ((old_head.column - 1) / indent_len) * indent_len,
10085                                ),
10086                            );
10087                        }
10088                    }
10089
10090                    selection.set_head(new_head, SelectionGoal::None);
10091                }
10092            }
10093
10094            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10095            this.insert("", window, cx);
10096            let empty_str: Arc<str> = Arc::from("");
10097            for (buffer, edits) in linked_ranges {
10098                let snapshot = buffer.read(cx).snapshot();
10099                use text::ToPoint as TP;
10100
10101                let edits = edits
10102                    .into_iter()
10103                    .map(|range| {
10104                        let end_point = TP::to_point(&range.end, &snapshot);
10105                        let mut start_point = TP::to_point(&range.start, &snapshot);
10106
10107                        if end_point == start_point {
10108                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10109                                .saturating_sub(1);
10110                            start_point =
10111                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10112                        };
10113
10114                        (start_point..end_point, empty_str.clone())
10115                    })
10116                    .sorted_by_key(|(range, _)| range.start)
10117                    .collect::<Vec<_>>();
10118                buffer.update(cx, |this, cx| {
10119                    this.edit(edits, None, cx);
10120                })
10121            }
10122            this.refresh_edit_prediction(true, false, window, cx);
10123            refresh_linked_ranges(this, window, cx);
10124        });
10125    }
10126
10127    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10128        if self.read_only(cx) {
10129            return;
10130        }
10131        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10132        self.transact(window, cx, |this, window, cx| {
10133            this.change_selections(Default::default(), window, cx, |s| {
10134                s.move_with(|map, selection| {
10135                    if selection.is_empty() {
10136                        let cursor = movement::right(map, selection.head());
10137                        selection.end = cursor;
10138                        selection.reversed = true;
10139                        selection.goal = SelectionGoal::None;
10140                    }
10141                })
10142            });
10143            this.insert("", window, cx);
10144            this.refresh_edit_prediction(true, false, window, cx);
10145        });
10146    }
10147
10148    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10149        if self.mode.is_single_line() {
10150            cx.propagate();
10151            return;
10152        }
10153
10154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10155        if self.move_to_prev_snippet_tabstop(window, cx) {
10156            return;
10157        }
10158        self.outdent(&Outdent, window, cx);
10159    }
10160
10161    pub fn next_snippet_tabstop(
10162        &mut self,
10163        _: &NextSnippetTabstop,
10164        window: &mut Window,
10165        cx: &mut Context<Self>,
10166    ) {
10167        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10168            cx.propagate();
10169            return;
10170        }
10171
10172        if self.move_to_next_snippet_tabstop(window, cx) {
10173            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10174            return;
10175        }
10176        cx.propagate();
10177    }
10178
10179    pub fn previous_snippet_tabstop(
10180        &mut self,
10181        _: &PreviousSnippetTabstop,
10182        window: &mut Window,
10183        cx: &mut Context<Self>,
10184    ) {
10185        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10186            cx.propagate();
10187            return;
10188        }
10189
10190        if self.move_to_prev_snippet_tabstop(window, cx) {
10191            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10192            return;
10193        }
10194        cx.propagate();
10195    }
10196
10197    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10198        if self.mode.is_single_line() {
10199            cx.propagate();
10200            return;
10201        }
10202
10203        if self.move_to_next_snippet_tabstop(window, cx) {
10204            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10205            return;
10206        }
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10211        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10212        let buffer = self.buffer.read(cx);
10213        let snapshot = buffer.snapshot(cx);
10214        let rows_iter = selections.iter().map(|s| s.head().row);
10215        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10216
10217        let has_some_cursor_in_whitespace = selections
10218            .iter()
10219            .filter(|selection| selection.is_empty())
10220            .any(|selection| {
10221                let cursor = selection.head();
10222                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10223                cursor.column < current_indent.len
10224            });
10225
10226        let mut edits = Vec::new();
10227        let mut prev_edited_row = 0;
10228        let mut row_delta = 0;
10229        for selection in &mut selections {
10230            if selection.start.row != prev_edited_row {
10231                row_delta = 0;
10232            }
10233            prev_edited_row = selection.end.row;
10234
10235            // If the selection is non-empty, then increase the indentation of the selected lines.
10236            if !selection.is_empty() {
10237                row_delta =
10238                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10239                continue;
10240            }
10241
10242            let cursor = selection.head();
10243            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10244            if let Some(suggested_indent) =
10245                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10246            {
10247                // Don't do anything if already at suggested indent
10248                // and there is any other cursor which is not
10249                if has_some_cursor_in_whitespace
10250                    && cursor.column == current_indent.len
10251                    && current_indent.len == suggested_indent.len
10252                {
10253                    continue;
10254                }
10255
10256                // Adjust line and move cursor to suggested indent
10257                // if cursor is not at suggested indent
10258                if cursor.column < suggested_indent.len
10259                    && cursor.column <= current_indent.len
10260                    && current_indent.len <= suggested_indent.len
10261                {
10262                    selection.start = Point::new(cursor.row, suggested_indent.len);
10263                    selection.end = selection.start;
10264                    if row_delta == 0 {
10265                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10266                            cursor.row,
10267                            current_indent,
10268                            suggested_indent,
10269                        ));
10270                        row_delta = suggested_indent.len - current_indent.len;
10271                    }
10272                    continue;
10273                }
10274
10275                // If current indent is more than suggested indent
10276                // only move cursor to current indent and skip indent
10277                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10278                    selection.start = Point::new(cursor.row, current_indent.len);
10279                    selection.end = selection.start;
10280                    continue;
10281                }
10282            }
10283
10284            // Otherwise, insert a hard or soft tab.
10285            let settings = buffer.language_settings_at(cursor, cx);
10286            let tab_size = if settings.hard_tabs {
10287                IndentSize::tab()
10288            } else {
10289                let tab_size = settings.tab_size.get();
10290                let indent_remainder = snapshot
10291                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10292                    .flat_map(str::chars)
10293                    .fold(row_delta % tab_size, |counter: u32, c| {
10294                        if c == '\t' {
10295                            0
10296                        } else {
10297                            (counter + 1) % tab_size
10298                        }
10299                    });
10300
10301                let chars_to_next_tab_stop = tab_size - indent_remainder;
10302                IndentSize::spaces(chars_to_next_tab_stop)
10303            };
10304            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10305            selection.end = selection.start;
10306            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10307            row_delta += tab_size.len;
10308        }
10309
10310        self.transact(window, cx, |this, window, cx| {
10311            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10312            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10313            this.refresh_edit_prediction(true, false, window, cx);
10314        });
10315    }
10316
10317    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10318        if self.read_only(cx) {
10319            return;
10320        }
10321        if self.mode.is_single_line() {
10322            cx.propagate();
10323            return;
10324        }
10325
10326        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10327        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10328        let mut prev_edited_row = 0;
10329        let mut row_delta = 0;
10330        let mut edits = Vec::new();
10331        let buffer = self.buffer.read(cx);
10332        let snapshot = buffer.snapshot(cx);
10333        for selection in &mut selections {
10334            if selection.start.row != prev_edited_row {
10335                row_delta = 0;
10336            }
10337            prev_edited_row = selection.end.row;
10338
10339            row_delta =
10340                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10341        }
10342
10343        self.transact(window, cx, |this, window, cx| {
10344            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10345            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10346        });
10347    }
10348
10349    fn indent_selection(
10350        buffer: &MultiBuffer,
10351        snapshot: &MultiBufferSnapshot,
10352        selection: &mut Selection<Point>,
10353        edits: &mut Vec<(Range<Point>, String)>,
10354        delta_for_start_row: u32,
10355        cx: &App,
10356    ) -> u32 {
10357        let settings = buffer.language_settings_at(selection.start, cx);
10358        let tab_size = settings.tab_size.get();
10359        let indent_kind = if settings.hard_tabs {
10360            IndentKind::Tab
10361        } else {
10362            IndentKind::Space
10363        };
10364        let mut start_row = selection.start.row;
10365        let mut end_row = selection.end.row + 1;
10366
10367        // If a selection ends at the beginning of a line, don't indent
10368        // that last line.
10369        if selection.end.column == 0 && selection.end.row > selection.start.row {
10370            end_row -= 1;
10371        }
10372
10373        // Avoid re-indenting a row that has already been indented by a
10374        // previous selection, but still update this selection's column
10375        // to reflect that indentation.
10376        if delta_for_start_row > 0 {
10377            start_row += 1;
10378            selection.start.column += delta_for_start_row;
10379            if selection.end.row == selection.start.row {
10380                selection.end.column += delta_for_start_row;
10381            }
10382        }
10383
10384        let mut delta_for_end_row = 0;
10385        let has_multiple_rows = start_row + 1 != end_row;
10386        for row in start_row..end_row {
10387            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10388            let indent_delta = match (current_indent.kind, indent_kind) {
10389                (IndentKind::Space, IndentKind::Space) => {
10390                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10391                    IndentSize::spaces(columns_to_next_tab_stop)
10392                }
10393                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10394                (_, IndentKind::Tab) => IndentSize::tab(),
10395            };
10396
10397            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10398                0
10399            } else {
10400                selection.start.column
10401            };
10402            let row_start = Point::new(row, start);
10403            edits.push((
10404                row_start..row_start,
10405                indent_delta.chars().collect::<String>(),
10406            ));
10407
10408            // Update this selection's endpoints to reflect the indentation.
10409            if row == selection.start.row {
10410                selection.start.column += indent_delta.len;
10411            }
10412            if row == selection.end.row {
10413                selection.end.column += indent_delta.len;
10414                delta_for_end_row = indent_delta.len;
10415            }
10416        }
10417
10418        if selection.start.row == selection.end.row {
10419            delta_for_start_row + delta_for_end_row
10420        } else {
10421            delta_for_end_row
10422        }
10423    }
10424
10425    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10426        if self.read_only(cx) {
10427            return;
10428        }
10429        if self.mode.is_single_line() {
10430            cx.propagate();
10431            return;
10432        }
10433
10434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10435        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10436        let selections = self.selections.all::<Point>(&display_map);
10437        let mut deletion_ranges = Vec::new();
10438        let mut last_outdent = None;
10439        {
10440            let buffer = self.buffer.read(cx);
10441            let snapshot = buffer.snapshot(cx);
10442            for selection in &selections {
10443                let settings = buffer.language_settings_at(selection.start, cx);
10444                let tab_size = settings.tab_size.get();
10445                let mut rows = selection.spanned_rows(false, &display_map);
10446
10447                // Avoid re-outdenting a row that has already been outdented by a
10448                // previous selection.
10449                if let Some(last_row) = last_outdent
10450                    && last_row == rows.start
10451                {
10452                    rows.start = rows.start.next_row();
10453                }
10454                let has_multiple_rows = rows.len() > 1;
10455                for row in rows.iter_rows() {
10456                    let indent_size = snapshot.indent_size_for_line(row);
10457                    if indent_size.len > 0 {
10458                        let deletion_len = match indent_size.kind {
10459                            IndentKind::Space => {
10460                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10461                                if columns_to_prev_tab_stop == 0 {
10462                                    tab_size
10463                                } else {
10464                                    columns_to_prev_tab_stop
10465                                }
10466                            }
10467                            IndentKind::Tab => 1,
10468                        };
10469                        let start = if has_multiple_rows
10470                            || deletion_len > selection.start.column
10471                            || indent_size.len < selection.start.column
10472                        {
10473                            0
10474                        } else {
10475                            selection.start.column - deletion_len
10476                        };
10477                        deletion_ranges.push(
10478                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10479                        );
10480                        last_outdent = Some(row);
10481                    }
10482                }
10483            }
10484        }
10485
10486        self.transact(window, cx, |this, window, cx| {
10487            this.buffer.update(cx, |buffer, cx| {
10488                let empty_str: Arc<str> = Arc::default();
10489                buffer.edit(
10490                    deletion_ranges
10491                        .into_iter()
10492                        .map(|range| (range, empty_str.clone())),
10493                    None,
10494                    cx,
10495                );
10496            });
10497            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10498            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10499        });
10500    }
10501
10502    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10503        if self.read_only(cx) {
10504            return;
10505        }
10506        if self.mode.is_single_line() {
10507            cx.propagate();
10508            return;
10509        }
10510
10511        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10512        let selections = self
10513            .selections
10514            .all::<usize>(&self.display_snapshot(cx))
10515            .into_iter()
10516            .map(|s| s.range());
10517
10518        self.transact(window, cx, |this, window, cx| {
10519            this.buffer.update(cx, |buffer, cx| {
10520                buffer.autoindent_ranges(selections, cx);
10521            });
10522            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10523            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10524        });
10525    }
10526
10527    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10529        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10530        let selections = self.selections.all::<Point>(&display_map);
10531
10532        let mut new_cursors = Vec::new();
10533        let mut edit_ranges = Vec::new();
10534        let mut selections = selections.iter().peekable();
10535        while let Some(selection) = selections.next() {
10536            let mut rows = selection.spanned_rows(false, &display_map);
10537
10538            // Accumulate contiguous regions of rows that we want to delete.
10539            while let Some(next_selection) = selections.peek() {
10540                let next_rows = next_selection.spanned_rows(false, &display_map);
10541                if next_rows.start <= rows.end {
10542                    rows.end = next_rows.end;
10543                    selections.next().unwrap();
10544                } else {
10545                    break;
10546                }
10547            }
10548
10549            let buffer = display_map.buffer_snapshot();
10550            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10551            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10552                // If there's a line after the range, delete the \n from the end of the row range
10553                (
10554                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10555                    rows.end,
10556                )
10557            } else {
10558                // If there isn't a line after the range, delete the \n from the line before the
10559                // start of the row range
10560                edit_start = edit_start.saturating_sub(1);
10561                (buffer.len(), rows.start.previous_row())
10562            };
10563
10564            let text_layout_details = self.text_layout_details(window);
10565            let x = display_map.x_for_display_point(
10566                selection.head().to_display_point(&display_map),
10567                &text_layout_details,
10568            );
10569            let row = Point::new(target_row.0, 0)
10570                .to_display_point(&display_map)
10571                .row();
10572            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10573
10574            new_cursors.push((
10575                selection.id,
10576                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10577                SelectionGoal::None,
10578            ));
10579            edit_ranges.push(edit_start..edit_end);
10580        }
10581
10582        self.transact(window, cx, |this, window, cx| {
10583            let buffer = this.buffer.update(cx, |buffer, cx| {
10584                let empty_str: Arc<str> = Arc::default();
10585                buffer.edit(
10586                    edit_ranges
10587                        .into_iter()
10588                        .map(|range| (range, empty_str.clone())),
10589                    None,
10590                    cx,
10591                );
10592                buffer.snapshot(cx)
10593            });
10594            let new_selections = new_cursors
10595                .into_iter()
10596                .map(|(id, cursor, goal)| {
10597                    let cursor = cursor.to_point(&buffer);
10598                    Selection {
10599                        id,
10600                        start: cursor,
10601                        end: cursor,
10602                        reversed: false,
10603                        goal,
10604                    }
10605                })
10606                .collect();
10607
10608            this.change_selections(Default::default(), window, cx, |s| {
10609                s.select(new_selections);
10610            });
10611        });
10612    }
10613
10614    pub fn join_lines_impl(
10615        &mut self,
10616        insert_whitespace: bool,
10617        window: &mut Window,
10618        cx: &mut Context<Self>,
10619    ) {
10620        if self.read_only(cx) {
10621            return;
10622        }
10623        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10624        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10625            let start = MultiBufferRow(selection.start.row);
10626            // Treat single line selections as if they include the next line. Otherwise this action
10627            // would do nothing for single line selections individual cursors.
10628            let end = if selection.start.row == selection.end.row {
10629                MultiBufferRow(selection.start.row + 1)
10630            } else {
10631                MultiBufferRow(selection.end.row)
10632            };
10633
10634            if let Some(last_row_range) = row_ranges.last_mut()
10635                && start <= last_row_range.end
10636            {
10637                last_row_range.end = end;
10638                continue;
10639            }
10640            row_ranges.push(start..end);
10641        }
10642
10643        let snapshot = self.buffer.read(cx).snapshot(cx);
10644        let mut cursor_positions = Vec::new();
10645        for row_range in &row_ranges {
10646            let anchor = snapshot.anchor_before(Point::new(
10647                row_range.end.previous_row().0,
10648                snapshot.line_len(row_range.end.previous_row()),
10649            ));
10650            cursor_positions.push(anchor..anchor);
10651        }
10652
10653        self.transact(window, cx, |this, window, cx| {
10654            for row_range in row_ranges.into_iter().rev() {
10655                for row in row_range.iter_rows().rev() {
10656                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10657                    let next_line_row = row.next_row();
10658                    let indent = snapshot.indent_size_for_line(next_line_row);
10659                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10660
10661                    let replace =
10662                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10663                            " "
10664                        } else {
10665                            ""
10666                        };
10667
10668                    this.buffer.update(cx, |buffer, cx| {
10669                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10670                    });
10671                }
10672            }
10673
10674            this.change_selections(Default::default(), window, cx, |s| {
10675                s.select_anchor_ranges(cursor_positions)
10676            });
10677        });
10678    }
10679
10680    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10682        self.join_lines_impl(true, window, cx);
10683    }
10684
10685    pub fn sort_lines_case_sensitive(
10686        &mut self,
10687        _: &SortLinesCaseSensitive,
10688        window: &mut Window,
10689        cx: &mut Context<Self>,
10690    ) {
10691        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10692    }
10693
10694    pub fn sort_lines_by_length(
10695        &mut self,
10696        _: &SortLinesByLength,
10697        window: &mut Window,
10698        cx: &mut Context<Self>,
10699    ) {
10700        self.manipulate_immutable_lines(window, cx, |lines| {
10701            lines.sort_by_key(|&line| line.chars().count())
10702        })
10703    }
10704
10705    pub fn sort_lines_case_insensitive(
10706        &mut self,
10707        _: &SortLinesCaseInsensitive,
10708        window: &mut Window,
10709        cx: &mut Context<Self>,
10710    ) {
10711        self.manipulate_immutable_lines(window, cx, |lines| {
10712            lines.sort_by_key(|line| line.to_lowercase())
10713        })
10714    }
10715
10716    pub fn unique_lines_case_insensitive(
10717        &mut self,
10718        _: &UniqueLinesCaseInsensitive,
10719        window: &mut Window,
10720        cx: &mut Context<Self>,
10721    ) {
10722        self.manipulate_immutable_lines(window, cx, |lines| {
10723            let mut seen = HashSet::default();
10724            lines.retain(|line| seen.insert(line.to_lowercase()));
10725        })
10726    }
10727
10728    pub fn unique_lines_case_sensitive(
10729        &mut self,
10730        _: &UniqueLinesCaseSensitive,
10731        window: &mut Window,
10732        cx: &mut Context<Self>,
10733    ) {
10734        self.manipulate_immutable_lines(window, cx, |lines| {
10735            let mut seen = HashSet::default();
10736            lines.retain(|line| seen.insert(*line));
10737        })
10738    }
10739
10740    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10741        let snapshot = self.buffer.read(cx).snapshot(cx);
10742        for selection in self.selections.disjoint_anchors_arc().iter() {
10743            if snapshot
10744                .language_at(selection.start)
10745                .and_then(|lang| lang.config().wrap_characters.as_ref())
10746                .is_some()
10747            {
10748                return true;
10749            }
10750        }
10751        false
10752    }
10753
10754    fn wrap_selections_in_tag(
10755        &mut self,
10756        _: &WrapSelectionsInTag,
10757        window: &mut Window,
10758        cx: &mut Context<Self>,
10759    ) {
10760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10761
10762        let snapshot = self.buffer.read(cx).snapshot(cx);
10763
10764        let mut edits = Vec::new();
10765        let mut boundaries = Vec::new();
10766
10767        for selection in self
10768            .selections
10769            .all_adjusted(&self.display_snapshot(cx))
10770            .iter()
10771        {
10772            let Some(wrap_config) = snapshot
10773                .language_at(selection.start)
10774                .and_then(|lang| lang.config().wrap_characters.clone())
10775            else {
10776                continue;
10777            };
10778
10779            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10780            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10781
10782            let start_before = snapshot.anchor_before(selection.start);
10783            let end_after = snapshot.anchor_after(selection.end);
10784
10785            edits.push((start_before..start_before, open_tag));
10786            edits.push((end_after..end_after, close_tag));
10787
10788            boundaries.push((
10789                start_before,
10790                end_after,
10791                wrap_config.start_prefix.len(),
10792                wrap_config.end_suffix.len(),
10793            ));
10794        }
10795
10796        if edits.is_empty() {
10797            return;
10798        }
10799
10800        self.transact(window, cx, |this, window, cx| {
10801            let buffer = this.buffer.update(cx, |buffer, cx| {
10802                buffer.edit(edits, None, cx);
10803                buffer.snapshot(cx)
10804            });
10805
10806            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10807            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10808                boundaries.into_iter()
10809            {
10810                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10811                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10812                new_selections.push(open_offset..open_offset);
10813                new_selections.push(close_offset..close_offset);
10814            }
10815
10816            this.change_selections(Default::default(), window, cx, |s| {
10817                s.select_ranges(new_selections);
10818            });
10819
10820            this.request_autoscroll(Autoscroll::fit(), cx);
10821        });
10822    }
10823
10824    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10825        let Some(project) = self.project.clone() else {
10826            return;
10827        };
10828        self.reload(project, window, cx)
10829            .detach_and_notify_err(window, cx);
10830    }
10831
10832    pub fn restore_file(
10833        &mut self,
10834        _: &::git::RestoreFile,
10835        window: &mut Window,
10836        cx: &mut Context<Self>,
10837    ) {
10838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10839        let mut buffer_ids = HashSet::default();
10840        let snapshot = self.buffer().read(cx).snapshot(cx);
10841        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10842            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10843        }
10844
10845        let buffer = self.buffer().read(cx);
10846        let ranges = buffer_ids
10847            .into_iter()
10848            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10849            .collect::<Vec<_>>();
10850
10851        self.restore_hunks_in_ranges(ranges, window, cx);
10852    }
10853
10854    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10855        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10856        let selections = self
10857            .selections
10858            .all(&self.display_snapshot(cx))
10859            .into_iter()
10860            .map(|s| s.range())
10861            .collect();
10862        self.restore_hunks_in_ranges(selections, window, cx);
10863    }
10864
10865    pub fn restore_hunks_in_ranges(
10866        &mut self,
10867        ranges: Vec<Range<Point>>,
10868        window: &mut Window,
10869        cx: &mut Context<Editor>,
10870    ) {
10871        let mut revert_changes = HashMap::default();
10872        let chunk_by = self
10873            .snapshot(window, cx)
10874            .hunks_for_ranges(ranges)
10875            .into_iter()
10876            .chunk_by(|hunk| hunk.buffer_id);
10877        for (buffer_id, hunks) in &chunk_by {
10878            let hunks = hunks.collect::<Vec<_>>();
10879            for hunk in &hunks {
10880                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10881            }
10882            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10883        }
10884        drop(chunk_by);
10885        if !revert_changes.is_empty() {
10886            self.transact(window, cx, |editor, window, cx| {
10887                editor.restore(revert_changes, window, cx);
10888            });
10889        }
10890    }
10891
10892    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10893        if let Some(status) = self
10894            .addons
10895            .iter()
10896            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10897        {
10898            return Some(status);
10899        }
10900        self.project
10901            .as_ref()?
10902            .read(cx)
10903            .status_for_buffer_id(buffer_id, cx)
10904    }
10905
10906    pub fn open_active_item_in_terminal(
10907        &mut self,
10908        _: &OpenInTerminal,
10909        window: &mut Window,
10910        cx: &mut Context<Self>,
10911    ) {
10912        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10913            let project_path = buffer.read(cx).project_path(cx)?;
10914            let project = self.project()?.read(cx);
10915            let entry = project.entry_for_path(&project_path, cx)?;
10916            let parent = match &entry.canonical_path {
10917                Some(canonical_path) => canonical_path.to_path_buf(),
10918                None => project.absolute_path(&project_path, cx)?,
10919            }
10920            .parent()?
10921            .to_path_buf();
10922            Some(parent)
10923        }) {
10924            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10925        }
10926    }
10927
10928    fn set_breakpoint_context_menu(
10929        &mut self,
10930        display_row: DisplayRow,
10931        position: Option<Anchor>,
10932        clicked_point: gpui::Point<Pixels>,
10933        window: &mut Window,
10934        cx: &mut Context<Self>,
10935    ) {
10936        let source = self
10937            .buffer
10938            .read(cx)
10939            .snapshot(cx)
10940            .anchor_before(Point::new(display_row.0, 0u32));
10941
10942        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10943
10944        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10945            self,
10946            source,
10947            clicked_point,
10948            context_menu,
10949            window,
10950            cx,
10951        );
10952    }
10953
10954    fn add_edit_breakpoint_block(
10955        &mut self,
10956        anchor: Anchor,
10957        breakpoint: &Breakpoint,
10958        edit_action: BreakpointPromptEditAction,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        let weak_editor = cx.weak_entity();
10963        let bp_prompt = cx.new(|cx| {
10964            BreakpointPromptEditor::new(
10965                weak_editor,
10966                anchor,
10967                breakpoint.clone(),
10968                edit_action,
10969                window,
10970                cx,
10971            )
10972        });
10973
10974        let height = bp_prompt.update(cx, |this, cx| {
10975            this.prompt
10976                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10977        });
10978        let cloned_prompt = bp_prompt.clone();
10979        let blocks = vec![BlockProperties {
10980            style: BlockStyle::Sticky,
10981            placement: BlockPlacement::Above(anchor),
10982            height: Some(height),
10983            render: Arc::new(move |cx| {
10984                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10985                cloned_prompt.clone().into_any_element()
10986            }),
10987            priority: 0,
10988        }];
10989
10990        let focus_handle = bp_prompt.focus_handle(cx);
10991        window.focus(&focus_handle);
10992
10993        let block_ids = self.insert_blocks(blocks, None, cx);
10994        bp_prompt.update(cx, |prompt, _| {
10995            prompt.add_block_ids(block_ids);
10996        });
10997    }
10998
10999    pub(crate) fn breakpoint_at_row(
11000        &self,
11001        row: u32,
11002        window: &mut Window,
11003        cx: &mut Context<Self>,
11004    ) -> Option<(Anchor, Breakpoint)> {
11005        let snapshot = self.snapshot(window, cx);
11006        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11007
11008        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11009    }
11010
11011    pub(crate) fn breakpoint_at_anchor(
11012        &self,
11013        breakpoint_position: Anchor,
11014        snapshot: &EditorSnapshot,
11015        cx: &mut Context<Self>,
11016    ) -> Option<(Anchor, Breakpoint)> {
11017        let buffer = self
11018            .buffer
11019            .read(cx)
11020            .buffer_for_anchor(breakpoint_position, cx)?;
11021
11022        let enclosing_excerpt = breakpoint_position.excerpt_id;
11023        let buffer_snapshot = buffer.read(cx).snapshot();
11024
11025        let row = buffer_snapshot
11026            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11027            .row;
11028
11029        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11030        let anchor_end = snapshot
11031            .buffer_snapshot()
11032            .anchor_after(Point::new(row, line_len));
11033
11034        self.breakpoint_store
11035            .as_ref()?
11036            .read_with(cx, |breakpoint_store, cx| {
11037                breakpoint_store
11038                    .breakpoints(
11039                        &buffer,
11040                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11041                        &buffer_snapshot,
11042                        cx,
11043                    )
11044                    .next()
11045                    .and_then(|(bp, _)| {
11046                        let breakpoint_row = buffer_snapshot
11047                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11048                            .row;
11049
11050                        if breakpoint_row == row {
11051                            snapshot
11052                                .buffer_snapshot()
11053                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11054                                .map(|position| (position, bp.bp.clone()))
11055                        } else {
11056                            None
11057                        }
11058                    })
11059            })
11060    }
11061
11062    pub fn edit_log_breakpoint(
11063        &mut self,
11064        _: &EditLogBreakpoint,
11065        window: &mut Window,
11066        cx: &mut Context<Self>,
11067    ) {
11068        if self.breakpoint_store.is_none() {
11069            return;
11070        }
11071
11072        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11073            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11074                message: None,
11075                state: BreakpointState::Enabled,
11076                condition: None,
11077                hit_condition: None,
11078            });
11079
11080            self.add_edit_breakpoint_block(
11081                anchor,
11082                &breakpoint,
11083                BreakpointPromptEditAction::Log,
11084                window,
11085                cx,
11086            );
11087        }
11088    }
11089
11090    fn breakpoints_at_cursors(
11091        &self,
11092        window: &mut Window,
11093        cx: &mut Context<Self>,
11094    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11095        let snapshot = self.snapshot(window, cx);
11096        let cursors = self
11097            .selections
11098            .disjoint_anchors_arc()
11099            .iter()
11100            .map(|selection| {
11101                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11102
11103                let breakpoint_position = self
11104                    .breakpoint_at_row(cursor_position.row, window, cx)
11105                    .map(|bp| bp.0)
11106                    .unwrap_or_else(|| {
11107                        snapshot
11108                            .display_snapshot
11109                            .buffer_snapshot()
11110                            .anchor_after(Point::new(cursor_position.row, 0))
11111                    });
11112
11113                let breakpoint = self
11114                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11115                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11116
11117                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11118            })
11119            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
11120            .collect::<HashMap<Anchor, _>>();
11121
11122        cursors.into_iter().collect()
11123    }
11124
11125    pub fn enable_breakpoint(
11126        &mut self,
11127        _: &crate::actions::EnableBreakpoint,
11128        window: &mut Window,
11129        cx: &mut Context<Self>,
11130    ) {
11131        if self.breakpoint_store.is_none() {
11132            return;
11133        }
11134
11135        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11136            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11137                continue;
11138            };
11139            self.edit_breakpoint_at_anchor(
11140                anchor,
11141                breakpoint,
11142                BreakpointEditAction::InvertState,
11143                cx,
11144            );
11145        }
11146    }
11147
11148    pub fn disable_breakpoint(
11149        &mut self,
11150        _: &crate::actions::DisableBreakpoint,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153    ) {
11154        if self.breakpoint_store.is_none() {
11155            return;
11156        }
11157
11158        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11159            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11160                continue;
11161            };
11162            self.edit_breakpoint_at_anchor(
11163                anchor,
11164                breakpoint,
11165                BreakpointEditAction::InvertState,
11166                cx,
11167            );
11168        }
11169    }
11170
11171    pub fn toggle_breakpoint(
11172        &mut self,
11173        _: &crate::actions::ToggleBreakpoint,
11174        window: &mut Window,
11175        cx: &mut Context<Self>,
11176    ) {
11177        if self.breakpoint_store.is_none() {
11178            return;
11179        }
11180
11181        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11182            if let Some(breakpoint) = breakpoint {
11183                self.edit_breakpoint_at_anchor(
11184                    anchor,
11185                    breakpoint,
11186                    BreakpointEditAction::Toggle,
11187                    cx,
11188                );
11189            } else {
11190                self.edit_breakpoint_at_anchor(
11191                    anchor,
11192                    Breakpoint::new_standard(),
11193                    BreakpointEditAction::Toggle,
11194                    cx,
11195                );
11196            }
11197        }
11198    }
11199
11200    pub fn edit_breakpoint_at_anchor(
11201        &mut self,
11202        breakpoint_position: Anchor,
11203        breakpoint: Breakpoint,
11204        edit_action: BreakpointEditAction,
11205        cx: &mut Context<Self>,
11206    ) {
11207        let Some(breakpoint_store) = &self.breakpoint_store else {
11208            return;
11209        };
11210
11211        let Some(buffer) = self
11212            .buffer
11213            .read(cx)
11214            .buffer_for_anchor(breakpoint_position, cx)
11215        else {
11216            return;
11217        };
11218
11219        breakpoint_store.update(cx, |breakpoint_store, cx| {
11220            breakpoint_store.toggle_breakpoint(
11221                buffer,
11222                BreakpointWithPosition {
11223                    position: breakpoint_position.text_anchor,
11224                    bp: breakpoint,
11225                },
11226                edit_action,
11227                cx,
11228            );
11229        });
11230
11231        cx.notify();
11232    }
11233
11234    #[cfg(any(test, feature = "test-support"))]
11235    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11236        self.breakpoint_store.clone()
11237    }
11238
11239    pub fn prepare_restore_change(
11240        &self,
11241        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11242        hunk: &MultiBufferDiffHunk,
11243        cx: &mut App,
11244    ) -> Option<()> {
11245        if hunk.is_created_file() {
11246            return None;
11247        }
11248        let buffer = self.buffer.read(cx);
11249        let diff = buffer.diff_for(hunk.buffer_id)?;
11250        let buffer = buffer.buffer(hunk.buffer_id)?;
11251        let buffer = buffer.read(cx);
11252        let original_text = diff
11253            .read(cx)
11254            .base_text()
11255            .as_rope()
11256            .slice(hunk.diff_base_byte_range.clone());
11257        let buffer_snapshot = buffer.snapshot();
11258        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11259        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11260            probe
11261                .0
11262                .start
11263                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11264                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11265        }) {
11266            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11267            Some(())
11268        } else {
11269            None
11270        }
11271    }
11272
11273    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11274        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11275    }
11276
11277    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11278        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11279    }
11280
11281    fn manipulate_lines<M>(
11282        &mut self,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285        mut manipulate: M,
11286    ) where
11287        M: FnMut(&str) -> LineManipulationResult,
11288    {
11289        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11290
11291        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11292        let buffer = self.buffer.read(cx).snapshot(cx);
11293
11294        let mut edits = Vec::new();
11295
11296        let selections = self.selections.all::<Point>(&display_map);
11297        let mut selections = selections.iter().peekable();
11298        let mut contiguous_row_selections = Vec::new();
11299        let mut new_selections = Vec::new();
11300        let mut added_lines = 0;
11301        let mut removed_lines = 0;
11302
11303        while let Some(selection) = selections.next() {
11304            let (start_row, end_row) = consume_contiguous_rows(
11305                &mut contiguous_row_selections,
11306                selection,
11307                &display_map,
11308                &mut selections,
11309            );
11310
11311            let start_point = Point::new(start_row.0, 0);
11312            let end_point = Point::new(
11313                end_row.previous_row().0,
11314                buffer.line_len(end_row.previous_row()),
11315            );
11316            let text = buffer
11317                .text_for_range(start_point..end_point)
11318                .collect::<String>();
11319
11320            let LineManipulationResult {
11321                new_text,
11322                line_count_before,
11323                line_count_after,
11324            } = manipulate(&text);
11325
11326            edits.push((start_point..end_point, new_text));
11327
11328            // Selections must change based on added and removed line count
11329            let start_row =
11330                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11331            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11332            new_selections.push(Selection {
11333                id: selection.id,
11334                start: start_row,
11335                end: end_row,
11336                goal: SelectionGoal::None,
11337                reversed: selection.reversed,
11338            });
11339
11340            if line_count_after > line_count_before {
11341                added_lines += line_count_after - line_count_before;
11342            } else if line_count_before > line_count_after {
11343                removed_lines += line_count_before - line_count_after;
11344            }
11345        }
11346
11347        self.transact(window, cx, |this, window, cx| {
11348            let buffer = this.buffer.update(cx, |buffer, cx| {
11349                buffer.edit(edits, None, cx);
11350                buffer.snapshot(cx)
11351            });
11352
11353            // Recalculate offsets on newly edited buffer
11354            let new_selections = new_selections
11355                .iter()
11356                .map(|s| {
11357                    let start_point = Point::new(s.start.0, 0);
11358                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11359                    Selection {
11360                        id: s.id,
11361                        start: buffer.point_to_offset(start_point),
11362                        end: buffer.point_to_offset(end_point),
11363                        goal: s.goal,
11364                        reversed: s.reversed,
11365                    }
11366                })
11367                .collect();
11368
11369            this.change_selections(Default::default(), window, cx, |s| {
11370                s.select(new_selections);
11371            });
11372
11373            this.request_autoscroll(Autoscroll::fit(), cx);
11374        });
11375    }
11376
11377    fn manipulate_immutable_lines<Fn>(
11378        &mut self,
11379        window: &mut Window,
11380        cx: &mut Context<Self>,
11381        mut callback: Fn,
11382    ) where
11383        Fn: FnMut(&mut Vec<&str>),
11384    {
11385        self.manipulate_lines(window, cx, |text| {
11386            let mut lines: Vec<&str> = text.split('\n').collect();
11387            let line_count_before = lines.len();
11388
11389            callback(&mut lines);
11390
11391            LineManipulationResult {
11392                new_text: lines.join("\n"),
11393                line_count_before,
11394                line_count_after: lines.len(),
11395            }
11396        });
11397    }
11398
11399    fn manipulate_mutable_lines<Fn>(
11400        &mut self,
11401        window: &mut Window,
11402        cx: &mut Context<Self>,
11403        mut callback: Fn,
11404    ) where
11405        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11406    {
11407        self.manipulate_lines(window, cx, |text| {
11408            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11409            let line_count_before = lines.len();
11410
11411            callback(&mut lines);
11412
11413            LineManipulationResult {
11414                new_text: lines.join("\n"),
11415                line_count_before,
11416                line_count_after: lines.len(),
11417            }
11418        });
11419    }
11420
11421    pub fn convert_indentation_to_spaces(
11422        &mut self,
11423        _: &ConvertIndentationToSpaces,
11424        window: &mut Window,
11425        cx: &mut Context<Self>,
11426    ) {
11427        let settings = self.buffer.read(cx).language_settings(cx);
11428        let tab_size = settings.tab_size.get() as usize;
11429
11430        self.manipulate_mutable_lines(window, cx, |lines| {
11431            // Allocates a reasonably sized scratch buffer once for the whole loop
11432            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11433            // Avoids recomputing spaces that could be inserted many times
11434            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11435                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11436                .collect();
11437
11438            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11439                let mut chars = line.as_ref().chars();
11440                let mut col = 0;
11441                let mut changed = false;
11442
11443                for ch in chars.by_ref() {
11444                    match ch {
11445                        ' ' => {
11446                            reindented_line.push(' ');
11447                            col += 1;
11448                        }
11449                        '\t' => {
11450                            // \t are converted to spaces depending on the current column
11451                            let spaces_len = tab_size - (col % tab_size);
11452                            reindented_line.extend(&space_cache[spaces_len - 1]);
11453                            col += spaces_len;
11454                            changed = true;
11455                        }
11456                        _ => {
11457                            // If we dont append before break, the character is consumed
11458                            reindented_line.push(ch);
11459                            break;
11460                        }
11461                    }
11462                }
11463
11464                if !changed {
11465                    reindented_line.clear();
11466                    continue;
11467                }
11468                // Append the rest of the line and replace old reference with new one
11469                reindented_line.extend(chars);
11470                *line = Cow::Owned(reindented_line.clone());
11471                reindented_line.clear();
11472            }
11473        });
11474    }
11475
11476    pub fn convert_indentation_to_tabs(
11477        &mut self,
11478        _: &ConvertIndentationToTabs,
11479        window: &mut Window,
11480        cx: &mut Context<Self>,
11481    ) {
11482        let settings = self.buffer.read(cx).language_settings(cx);
11483        let tab_size = settings.tab_size.get() as usize;
11484
11485        self.manipulate_mutable_lines(window, cx, |lines| {
11486            // Allocates a reasonably sized buffer once for the whole loop
11487            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11488            // Avoids recomputing spaces that could be inserted many times
11489            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11490                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11491                .collect();
11492
11493            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11494                let mut chars = line.chars();
11495                let mut spaces_count = 0;
11496                let mut first_non_indent_char = None;
11497                let mut changed = false;
11498
11499                for ch in chars.by_ref() {
11500                    match ch {
11501                        ' ' => {
11502                            // Keep track of spaces. Append \t when we reach tab_size
11503                            spaces_count += 1;
11504                            changed = true;
11505                            if spaces_count == tab_size {
11506                                reindented_line.push('\t');
11507                                spaces_count = 0;
11508                            }
11509                        }
11510                        '\t' => {
11511                            reindented_line.push('\t');
11512                            spaces_count = 0;
11513                        }
11514                        _ => {
11515                            // Dont append it yet, we might have remaining spaces
11516                            first_non_indent_char = Some(ch);
11517                            break;
11518                        }
11519                    }
11520                }
11521
11522                if !changed {
11523                    reindented_line.clear();
11524                    continue;
11525                }
11526                // Remaining spaces that didn't make a full tab stop
11527                if spaces_count > 0 {
11528                    reindented_line.extend(&space_cache[spaces_count - 1]);
11529                }
11530                // If we consume an extra character that was not indentation, add it back
11531                if let Some(extra_char) = first_non_indent_char {
11532                    reindented_line.push(extra_char);
11533                }
11534                // Append the rest of the line and replace old reference with new one
11535                reindented_line.extend(chars);
11536                *line = Cow::Owned(reindented_line.clone());
11537                reindented_line.clear();
11538            }
11539        });
11540    }
11541
11542    pub fn convert_to_upper_case(
11543        &mut self,
11544        _: &ConvertToUpperCase,
11545        window: &mut Window,
11546        cx: &mut Context<Self>,
11547    ) {
11548        self.manipulate_text(window, cx, |text| text.to_uppercase())
11549    }
11550
11551    pub fn convert_to_lower_case(
11552        &mut self,
11553        _: &ConvertToLowerCase,
11554        window: &mut Window,
11555        cx: &mut Context<Self>,
11556    ) {
11557        self.manipulate_text(window, cx, |text| text.to_lowercase())
11558    }
11559
11560    pub fn convert_to_title_case(
11561        &mut self,
11562        _: &ConvertToTitleCase,
11563        window: &mut Window,
11564        cx: &mut Context<Self>,
11565    ) {
11566        self.manipulate_text(window, cx, |text| {
11567            text.split('\n')
11568                .map(|line| line.to_case(Case::Title))
11569                .join("\n")
11570        })
11571    }
11572
11573    pub fn convert_to_snake_case(
11574        &mut self,
11575        _: &ConvertToSnakeCase,
11576        window: &mut Window,
11577        cx: &mut Context<Self>,
11578    ) {
11579        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11580    }
11581
11582    pub fn convert_to_kebab_case(
11583        &mut self,
11584        _: &ConvertToKebabCase,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11589    }
11590
11591    pub fn convert_to_upper_camel_case(
11592        &mut self,
11593        _: &ConvertToUpperCamelCase,
11594        window: &mut Window,
11595        cx: &mut Context<Self>,
11596    ) {
11597        self.manipulate_text(window, cx, |text| {
11598            text.split('\n')
11599                .map(|line| line.to_case(Case::UpperCamel))
11600                .join("\n")
11601        })
11602    }
11603
11604    pub fn convert_to_lower_camel_case(
11605        &mut self,
11606        _: &ConvertToLowerCamelCase,
11607        window: &mut Window,
11608        cx: &mut Context<Self>,
11609    ) {
11610        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11611    }
11612
11613    pub fn convert_to_opposite_case(
11614        &mut self,
11615        _: &ConvertToOppositeCase,
11616        window: &mut Window,
11617        cx: &mut Context<Self>,
11618    ) {
11619        self.manipulate_text(window, cx, |text| {
11620            text.chars()
11621                .fold(String::with_capacity(text.len()), |mut t, c| {
11622                    if c.is_uppercase() {
11623                        t.extend(c.to_lowercase());
11624                    } else {
11625                        t.extend(c.to_uppercase());
11626                    }
11627                    t
11628                })
11629        })
11630    }
11631
11632    pub fn convert_to_sentence_case(
11633        &mut self,
11634        _: &ConvertToSentenceCase,
11635        window: &mut Window,
11636        cx: &mut Context<Self>,
11637    ) {
11638        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11639    }
11640
11641    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11642        self.manipulate_text(window, cx, |text| {
11643            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11644            if has_upper_case_characters {
11645                text.to_lowercase()
11646            } else {
11647                text.to_uppercase()
11648            }
11649        })
11650    }
11651
11652    pub fn convert_to_rot13(
11653        &mut self,
11654        _: &ConvertToRot13,
11655        window: &mut Window,
11656        cx: &mut Context<Self>,
11657    ) {
11658        self.manipulate_text(window, cx, |text| {
11659            text.chars()
11660                .map(|c| match c {
11661                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11662                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11663                    _ => c,
11664                })
11665                .collect()
11666        })
11667    }
11668
11669    pub fn convert_to_rot47(
11670        &mut self,
11671        _: &ConvertToRot47,
11672        window: &mut Window,
11673        cx: &mut Context<Self>,
11674    ) {
11675        self.manipulate_text(window, cx, |text| {
11676            text.chars()
11677                .map(|c| {
11678                    let code_point = c as u32;
11679                    if code_point >= 33 && code_point <= 126 {
11680                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11681                    }
11682                    c
11683                })
11684                .collect()
11685        })
11686    }
11687
11688    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11689    where
11690        Fn: FnMut(&str) -> String,
11691    {
11692        let buffer = self.buffer.read(cx).snapshot(cx);
11693
11694        let mut new_selections = Vec::new();
11695        let mut edits = Vec::new();
11696        let mut selection_adjustment = 0i32;
11697
11698        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11699            let selection_is_empty = selection.is_empty();
11700
11701            let (start, end) = if selection_is_empty {
11702                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11703                (word_range.start, word_range.end)
11704            } else {
11705                (
11706                    buffer.point_to_offset(selection.start),
11707                    buffer.point_to_offset(selection.end),
11708                )
11709            };
11710
11711            let text = buffer.text_for_range(start..end).collect::<String>();
11712            let old_length = text.len() as i32;
11713            let text = callback(&text);
11714
11715            new_selections.push(Selection {
11716                start: (start as i32 - selection_adjustment) as usize,
11717                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11718                goal: SelectionGoal::None,
11719                id: selection.id,
11720                reversed: selection.reversed,
11721            });
11722
11723            selection_adjustment += old_length - text.len() as i32;
11724
11725            edits.push((start..end, text));
11726        }
11727
11728        self.transact(window, cx, |this, window, cx| {
11729            this.buffer.update(cx, |buffer, cx| {
11730                buffer.edit(edits, None, cx);
11731            });
11732
11733            this.change_selections(Default::default(), window, cx, |s| {
11734                s.select(new_selections);
11735            });
11736
11737            this.request_autoscroll(Autoscroll::fit(), cx);
11738        });
11739    }
11740
11741    pub fn move_selection_on_drop(
11742        &mut self,
11743        selection: &Selection<Anchor>,
11744        target: DisplayPoint,
11745        is_cut: bool,
11746        window: &mut Window,
11747        cx: &mut Context<Self>,
11748    ) {
11749        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11750        let buffer = display_map.buffer_snapshot();
11751        let mut edits = Vec::new();
11752        let insert_point = display_map
11753            .clip_point(target, Bias::Left)
11754            .to_point(&display_map);
11755        let text = buffer
11756            .text_for_range(selection.start..selection.end)
11757            .collect::<String>();
11758        if is_cut {
11759            edits.push(((selection.start..selection.end), String::new()));
11760        }
11761        let insert_anchor = buffer.anchor_before(insert_point);
11762        edits.push(((insert_anchor..insert_anchor), text));
11763        let last_edit_start = insert_anchor.bias_left(buffer);
11764        let last_edit_end = insert_anchor.bias_right(buffer);
11765        self.transact(window, cx, |this, window, cx| {
11766            this.buffer.update(cx, |buffer, cx| {
11767                buffer.edit(edits, None, cx);
11768            });
11769            this.change_selections(Default::default(), window, cx, |s| {
11770                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11771            });
11772        });
11773    }
11774
11775    pub fn clear_selection_drag_state(&mut self) {
11776        self.selection_drag_state = SelectionDragState::None;
11777    }
11778
11779    pub fn duplicate(
11780        &mut self,
11781        upwards: bool,
11782        whole_lines: bool,
11783        window: &mut Window,
11784        cx: &mut Context<Self>,
11785    ) {
11786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11787
11788        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11789        let buffer = display_map.buffer_snapshot();
11790        let selections = self.selections.all::<Point>(&display_map);
11791
11792        let mut edits = Vec::new();
11793        let mut selections_iter = selections.iter().peekable();
11794        while let Some(selection) = selections_iter.next() {
11795            let mut rows = selection.spanned_rows(false, &display_map);
11796            // duplicate line-wise
11797            if whole_lines || selection.start == selection.end {
11798                // Avoid duplicating the same lines twice.
11799                while let Some(next_selection) = selections_iter.peek() {
11800                    let next_rows = next_selection.spanned_rows(false, &display_map);
11801                    if next_rows.start < rows.end {
11802                        rows.end = next_rows.end;
11803                        selections_iter.next().unwrap();
11804                    } else {
11805                        break;
11806                    }
11807                }
11808
11809                // Copy the text from the selected row region and splice it either at the start
11810                // or end of the region.
11811                let start = Point::new(rows.start.0, 0);
11812                let end = Point::new(
11813                    rows.end.previous_row().0,
11814                    buffer.line_len(rows.end.previous_row()),
11815                );
11816
11817                let mut text = buffer.text_for_range(start..end).collect::<String>();
11818
11819                let insert_location = if upwards {
11820                    // When duplicating upward, we need to insert before the current line.
11821                    // If we're on the last line and it doesn't end with a newline,
11822                    // we need to add a newline before the duplicated content.
11823                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11824                        && buffer.max_point().column > 0
11825                        && !text.ends_with('\n');
11826
11827                    if needs_leading_newline {
11828                        text.insert(0, '\n');
11829                        end
11830                    } else {
11831                        text.push('\n');
11832                        Point::new(rows.start.0, 0)
11833                    }
11834                } else {
11835                    text.push('\n');
11836                    start
11837                };
11838                edits.push((insert_location..insert_location, text));
11839            } else {
11840                // duplicate character-wise
11841                let start = selection.start;
11842                let end = selection.end;
11843                let text = buffer.text_for_range(start..end).collect::<String>();
11844                edits.push((selection.end..selection.end, text));
11845            }
11846        }
11847
11848        self.transact(window, cx, |this, window, cx| {
11849            this.buffer.update(cx, |buffer, cx| {
11850                buffer.edit(edits, None, cx);
11851            });
11852
11853            // When duplicating upward with whole lines, move the cursor to the duplicated line
11854            if upwards && whole_lines {
11855                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11856
11857                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11858                    let mut new_ranges = Vec::new();
11859                    let selections = s.all::<Point>(&display_map);
11860                    let mut selections_iter = selections.iter().peekable();
11861
11862                    while let Some(first_selection) = selections_iter.next() {
11863                        // Group contiguous selections together to find the total row span
11864                        let mut group_selections = vec![first_selection];
11865                        let mut rows = first_selection.spanned_rows(false, &display_map);
11866
11867                        while let Some(next_selection) = selections_iter.peek() {
11868                            let next_rows = next_selection.spanned_rows(false, &display_map);
11869                            if next_rows.start < rows.end {
11870                                rows.end = next_rows.end;
11871                                group_selections.push(selections_iter.next().unwrap());
11872                            } else {
11873                                break;
11874                            }
11875                        }
11876
11877                        let row_count = rows.end.0 - rows.start.0;
11878
11879                        // Move all selections in this group up by the total number of duplicated rows
11880                        for selection in group_selections {
11881                            let new_start = Point::new(
11882                                selection.start.row.saturating_sub(row_count),
11883                                selection.start.column,
11884                            );
11885
11886                            let new_end = Point::new(
11887                                selection.end.row.saturating_sub(row_count),
11888                                selection.end.column,
11889                            );
11890
11891                            new_ranges.push(new_start..new_end);
11892                        }
11893                    }
11894
11895                    s.select_ranges(new_ranges);
11896                });
11897            }
11898
11899            this.request_autoscroll(Autoscroll::fit(), cx);
11900        });
11901    }
11902
11903    pub fn duplicate_line_up(
11904        &mut self,
11905        _: &DuplicateLineUp,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908    ) {
11909        self.duplicate(true, true, window, cx);
11910    }
11911
11912    pub fn duplicate_line_down(
11913        &mut self,
11914        _: &DuplicateLineDown,
11915        window: &mut Window,
11916        cx: &mut Context<Self>,
11917    ) {
11918        self.duplicate(false, true, window, cx);
11919    }
11920
11921    pub fn duplicate_selection(
11922        &mut self,
11923        _: &DuplicateSelection,
11924        window: &mut Window,
11925        cx: &mut Context<Self>,
11926    ) {
11927        self.duplicate(false, false, window, cx);
11928    }
11929
11930    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11932        if self.mode.is_single_line() {
11933            cx.propagate();
11934            return;
11935        }
11936
11937        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11938        let buffer = self.buffer.read(cx).snapshot(cx);
11939
11940        let mut edits = Vec::new();
11941        let mut unfold_ranges = Vec::new();
11942        let mut refold_creases = Vec::new();
11943
11944        let selections = self.selections.all::<Point>(&display_map);
11945        let mut selections = selections.iter().peekable();
11946        let mut contiguous_row_selections = Vec::new();
11947        let mut new_selections = Vec::new();
11948
11949        while let Some(selection) = selections.next() {
11950            // Find all the selections that span a contiguous row range
11951            let (start_row, end_row) = consume_contiguous_rows(
11952                &mut contiguous_row_selections,
11953                selection,
11954                &display_map,
11955                &mut selections,
11956            );
11957
11958            // Move the text spanned by the row range to be before the line preceding the row range
11959            if start_row.0 > 0 {
11960                let range_to_move = Point::new(
11961                    start_row.previous_row().0,
11962                    buffer.line_len(start_row.previous_row()),
11963                )
11964                    ..Point::new(
11965                        end_row.previous_row().0,
11966                        buffer.line_len(end_row.previous_row()),
11967                    );
11968                let insertion_point = display_map
11969                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11970                    .0;
11971
11972                // Don't move lines across excerpts
11973                if buffer
11974                    .excerpt_containing(insertion_point..range_to_move.end)
11975                    .is_some()
11976                {
11977                    let text = buffer
11978                        .text_for_range(range_to_move.clone())
11979                        .flat_map(|s| s.chars())
11980                        .skip(1)
11981                        .chain(['\n'])
11982                        .collect::<String>();
11983
11984                    edits.push((
11985                        buffer.anchor_after(range_to_move.start)
11986                            ..buffer.anchor_before(range_to_move.end),
11987                        String::new(),
11988                    ));
11989                    let insertion_anchor = buffer.anchor_after(insertion_point);
11990                    edits.push((insertion_anchor..insertion_anchor, text));
11991
11992                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11993
11994                    // Move selections up
11995                    new_selections.extend(contiguous_row_selections.drain(..).map(
11996                        |mut selection| {
11997                            selection.start.row -= row_delta;
11998                            selection.end.row -= row_delta;
11999                            selection
12000                        },
12001                    ));
12002
12003                    // Move folds up
12004                    unfold_ranges.push(range_to_move.clone());
12005                    for fold in display_map.folds_in_range(
12006                        buffer.anchor_before(range_to_move.start)
12007                            ..buffer.anchor_after(range_to_move.end),
12008                    ) {
12009                        let mut start = fold.range.start.to_point(&buffer);
12010                        let mut end = fold.range.end.to_point(&buffer);
12011                        start.row -= row_delta;
12012                        end.row -= row_delta;
12013                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12014                    }
12015                }
12016            }
12017
12018            // If we didn't move line(s), preserve the existing selections
12019            new_selections.append(&mut contiguous_row_selections);
12020        }
12021
12022        self.transact(window, cx, |this, window, cx| {
12023            this.unfold_ranges(&unfold_ranges, true, true, cx);
12024            this.buffer.update(cx, |buffer, cx| {
12025                for (range, text) in edits {
12026                    buffer.edit([(range, text)], None, cx);
12027                }
12028            });
12029            this.fold_creases(refold_creases, true, window, cx);
12030            this.change_selections(Default::default(), window, cx, |s| {
12031                s.select(new_selections);
12032            })
12033        });
12034    }
12035
12036    pub fn move_line_down(
12037        &mut self,
12038        _: &MoveLineDown,
12039        window: &mut Window,
12040        cx: &mut Context<Self>,
12041    ) {
12042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12043        if self.mode.is_single_line() {
12044            cx.propagate();
12045            return;
12046        }
12047
12048        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12049        let buffer = self.buffer.read(cx).snapshot(cx);
12050
12051        let mut edits = Vec::new();
12052        let mut unfold_ranges = Vec::new();
12053        let mut refold_creases = Vec::new();
12054
12055        let selections = self.selections.all::<Point>(&display_map);
12056        let mut selections = selections.iter().peekable();
12057        let mut contiguous_row_selections = Vec::new();
12058        let mut new_selections = Vec::new();
12059
12060        while let Some(selection) = selections.next() {
12061            // Find all the selections that span a contiguous row range
12062            let (start_row, end_row) = consume_contiguous_rows(
12063                &mut contiguous_row_selections,
12064                selection,
12065                &display_map,
12066                &mut selections,
12067            );
12068
12069            // Move the text spanned by the row range to be after the last line of the row range
12070            if end_row.0 <= buffer.max_point().row {
12071                let range_to_move =
12072                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12073                let insertion_point = display_map
12074                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12075                    .0;
12076
12077                // Don't move lines across excerpt boundaries
12078                if buffer
12079                    .excerpt_containing(range_to_move.start..insertion_point)
12080                    .is_some()
12081                {
12082                    let mut text = String::from("\n");
12083                    text.extend(buffer.text_for_range(range_to_move.clone()));
12084                    text.pop(); // Drop trailing newline
12085                    edits.push((
12086                        buffer.anchor_after(range_to_move.start)
12087                            ..buffer.anchor_before(range_to_move.end),
12088                        String::new(),
12089                    ));
12090                    let insertion_anchor = buffer.anchor_after(insertion_point);
12091                    edits.push((insertion_anchor..insertion_anchor, text));
12092
12093                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12094
12095                    // Move selections down
12096                    new_selections.extend(contiguous_row_selections.drain(..).map(
12097                        |mut selection| {
12098                            selection.start.row += row_delta;
12099                            selection.end.row += row_delta;
12100                            selection
12101                        },
12102                    ));
12103
12104                    // Move folds down
12105                    unfold_ranges.push(range_to_move.clone());
12106                    for fold in display_map.folds_in_range(
12107                        buffer.anchor_before(range_to_move.start)
12108                            ..buffer.anchor_after(range_to_move.end),
12109                    ) {
12110                        let mut start = fold.range.start.to_point(&buffer);
12111                        let mut end = fold.range.end.to_point(&buffer);
12112                        start.row += row_delta;
12113                        end.row += row_delta;
12114                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12115                    }
12116                }
12117            }
12118
12119            // If we didn't move line(s), preserve the existing selections
12120            new_selections.append(&mut contiguous_row_selections);
12121        }
12122
12123        self.transact(window, cx, |this, window, cx| {
12124            this.unfold_ranges(&unfold_ranges, true, true, cx);
12125            this.buffer.update(cx, |buffer, cx| {
12126                for (range, text) in edits {
12127                    buffer.edit([(range, text)], None, cx);
12128                }
12129            });
12130            this.fold_creases(refold_creases, true, window, cx);
12131            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12132        });
12133    }
12134
12135    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12136        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12137        let text_layout_details = &self.text_layout_details(window);
12138        self.transact(window, cx, |this, window, cx| {
12139            let edits = this.change_selections(Default::default(), window, cx, |s| {
12140                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12141                s.move_with(|display_map, selection| {
12142                    if !selection.is_empty() {
12143                        return;
12144                    }
12145
12146                    let mut head = selection.head();
12147                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12148                    if head.column() == display_map.line_len(head.row()) {
12149                        transpose_offset = display_map
12150                            .buffer_snapshot()
12151                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12152                    }
12153
12154                    if transpose_offset == 0 {
12155                        return;
12156                    }
12157
12158                    *head.column_mut() += 1;
12159                    head = display_map.clip_point(head, Bias::Right);
12160                    let goal = SelectionGoal::HorizontalPosition(
12161                        display_map
12162                            .x_for_display_point(head, text_layout_details)
12163                            .into(),
12164                    );
12165                    selection.collapse_to(head, goal);
12166
12167                    let transpose_start = display_map
12168                        .buffer_snapshot()
12169                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12170                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12171                        let transpose_end = display_map
12172                            .buffer_snapshot()
12173                            .clip_offset(transpose_offset + 1, Bias::Right);
12174                        if let Some(ch) = display_map
12175                            .buffer_snapshot()
12176                            .chars_at(transpose_start)
12177                            .next()
12178                        {
12179                            edits.push((transpose_start..transpose_offset, String::new()));
12180                            edits.push((transpose_end..transpose_end, ch.to_string()));
12181                        }
12182                    }
12183                });
12184                edits
12185            });
12186            this.buffer
12187                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12188            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12189            this.change_selections(Default::default(), window, cx, |s| {
12190                s.select(selections);
12191            });
12192        });
12193    }
12194
12195    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12197        if self.mode.is_single_line() {
12198            cx.propagate();
12199            return;
12200        }
12201
12202        self.rewrap_impl(RewrapOptions::default(), cx)
12203    }
12204
12205    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12206        let buffer = self.buffer.read(cx).snapshot(cx);
12207        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12208
12209        #[derive(Clone, Debug, PartialEq)]
12210        enum CommentFormat {
12211            /// single line comment, with prefix for line
12212            Line(String),
12213            /// single line within a block comment, with prefix for line
12214            BlockLine(String),
12215            /// a single line of a block comment that includes the initial delimiter
12216            BlockCommentWithStart(BlockCommentConfig),
12217            /// a single line of a block comment that includes the ending delimiter
12218            BlockCommentWithEnd(BlockCommentConfig),
12219        }
12220
12221        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12222        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12223            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12224                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12225                .peekable();
12226
12227            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12228                row
12229            } else {
12230                return Vec::new();
12231            };
12232
12233            let language_settings = buffer.language_settings_at(selection.head(), cx);
12234            let language_scope = buffer.language_scope_at(selection.head());
12235
12236            let indent_and_prefix_for_row =
12237                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12238                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12239                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12240                        &language_scope
12241                    {
12242                        let indent_end = Point::new(row, indent.len);
12243                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12244                        let line_text_after_indent = buffer
12245                            .text_for_range(indent_end..line_end)
12246                            .collect::<String>();
12247
12248                        let is_within_comment_override = buffer
12249                            .language_scope_at(indent_end)
12250                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12251                        let comment_delimiters = if is_within_comment_override {
12252                            // we are within a comment syntax node, but we don't
12253                            // yet know what kind of comment: block, doc or line
12254                            match (
12255                                language_scope.documentation_comment(),
12256                                language_scope.block_comment(),
12257                            ) {
12258                                (Some(config), _) | (_, Some(config))
12259                                    if buffer.contains_str_at(indent_end, &config.start) =>
12260                                {
12261                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12262                                }
12263                                (Some(config), _) | (_, Some(config))
12264                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12265                                {
12266                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12267                                }
12268                                (Some(config), _) | (_, Some(config))
12269                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12270                                {
12271                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12272                                }
12273                                (_, _) => language_scope
12274                                    .line_comment_prefixes()
12275                                    .iter()
12276                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12277                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12278                            }
12279                        } else {
12280                            // we not in an overridden comment node, but we may
12281                            // be within a non-overridden line comment node
12282                            language_scope
12283                                .line_comment_prefixes()
12284                                .iter()
12285                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12286                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12287                        };
12288
12289                        let rewrap_prefix = language_scope
12290                            .rewrap_prefixes()
12291                            .iter()
12292                            .find_map(|prefix_regex| {
12293                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12294                                    if mat.start() == 0 {
12295                                        Some(mat.as_str().to_string())
12296                                    } else {
12297                                        None
12298                                    }
12299                                })
12300                            })
12301                            .flatten();
12302                        (comment_delimiters, rewrap_prefix)
12303                    } else {
12304                        (None, None)
12305                    };
12306                    (indent, comment_prefix, rewrap_prefix)
12307                };
12308
12309            let mut ranges = Vec::new();
12310            let from_empty_selection = selection.is_empty();
12311
12312            let mut current_range_start = first_row;
12313            let mut prev_row = first_row;
12314            let (
12315                mut current_range_indent,
12316                mut current_range_comment_delimiters,
12317                mut current_range_rewrap_prefix,
12318            ) = indent_and_prefix_for_row(first_row);
12319
12320            for row in non_blank_rows_iter.skip(1) {
12321                let has_paragraph_break = row > prev_row + 1;
12322
12323                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12324                    indent_and_prefix_for_row(row);
12325
12326                let has_indent_change = row_indent != current_range_indent;
12327                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12328
12329                let has_boundary_change = has_comment_change
12330                    || row_rewrap_prefix.is_some()
12331                    || (has_indent_change && current_range_comment_delimiters.is_some());
12332
12333                if has_paragraph_break || has_boundary_change {
12334                    ranges.push((
12335                        language_settings.clone(),
12336                        Point::new(current_range_start, 0)
12337                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12338                        current_range_indent,
12339                        current_range_comment_delimiters.clone(),
12340                        current_range_rewrap_prefix.clone(),
12341                        from_empty_selection,
12342                    ));
12343                    current_range_start = row;
12344                    current_range_indent = row_indent;
12345                    current_range_comment_delimiters = row_comment_delimiters;
12346                    current_range_rewrap_prefix = row_rewrap_prefix;
12347                }
12348                prev_row = row;
12349            }
12350
12351            ranges.push((
12352                language_settings.clone(),
12353                Point::new(current_range_start, 0)
12354                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12355                current_range_indent,
12356                current_range_comment_delimiters,
12357                current_range_rewrap_prefix,
12358                from_empty_selection,
12359            ));
12360
12361            ranges
12362        });
12363
12364        let mut edits = Vec::new();
12365        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12366
12367        for (
12368            language_settings,
12369            wrap_range,
12370            mut indent_size,
12371            comment_prefix,
12372            rewrap_prefix,
12373            from_empty_selection,
12374        ) in wrap_ranges
12375        {
12376            let mut start_row = wrap_range.start.row;
12377            let mut end_row = wrap_range.end.row;
12378
12379            // Skip selections that overlap with a range that has already been rewrapped.
12380            let selection_range = start_row..end_row;
12381            if rewrapped_row_ranges
12382                .iter()
12383                .any(|range| range.overlaps(&selection_range))
12384            {
12385                continue;
12386            }
12387
12388            let tab_size = language_settings.tab_size;
12389
12390            let (line_prefix, inside_comment) = match &comment_prefix {
12391                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12392                    (Some(prefix.as_str()), true)
12393                }
12394                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12395                    (Some(prefix.as_ref()), true)
12396                }
12397                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12398                    start: _,
12399                    end: _,
12400                    prefix,
12401                    tab_size,
12402                })) => {
12403                    indent_size.len += tab_size;
12404                    (Some(prefix.as_ref()), true)
12405                }
12406                None => (None, false),
12407            };
12408            let indent_prefix = indent_size.chars().collect::<String>();
12409            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12410
12411            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12412                RewrapBehavior::InComments => inside_comment,
12413                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12414                RewrapBehavior::Anywhere => true,
12415            };
12416
12417            let should_rewrap = options.override_language_settings
12418                || allow_rewrap_based_on_language
12419                || self.hard_wrap.is_some();
12420            if !should_rewrap {
12421                continue;
12422            }
12423
12424            if from_empty_selection {
12425                'expand_upwards: while start_row > 0 {
12426                    let prev_row = start_row - 1;
12427                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12428                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12429                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12430                    {
12431                        start_row = prev_row;
12432                    } else {
12433                        break 'expand_upwards;
12434                    }
12435                }
12436
12437                'expand_downwards: while end_row < buffer.max_point().row {
12438                    let next_row = end_row + 1;
12439                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12440                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12441                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12442                    {
12443                        end_row = next_row;
12444                    } else {
12445                        break 'expand_downwards;
12446                    }
12447                }
12448            }
12449
12450            let start = Point::new(start_row, 0);
12451            let start_offset = ToOffset::to_offset(&start, &buffer);
12452            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12453            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12454            let mut first_line_delimiter = None;
12455            let mut last_line_delimiter = None;
12456            let Some(lines_without_prefixes) = selection_text
12457                .lines()
12458                .enumerate()
12459                .map(|(ix, line)| {
12460                    let line_trimmed = line.trim_start();
12461                    if rewrap_prefix.is_some() && ix > 0 {
12462                        Ok(line_trimmed)
12463                    } else if let Some(
12464                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12465                            start,
12466                            prefix,
12467                            end,
12468                            tab_size,
12469                        })
12470                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12471                            start,
12472                            prefix,
12473                            end,
12474                            tab_size,
12475                        }),
12476                    ) = &comment_prefix
12477                    {
12478                        let line_trimmed = line_trimmed
12479                            .strip_prefix(start.as_ref())
12480                            .map(|s| {
12481                                let mut indent_size = indent_size;
12482                                indent_size.len -= tab_size;
12483                                let indent_prefix: String = indent_size.chars().collect();
12484                                first_line_delimiter = Some((indent_prefix, start));
12485                                s.trim_start()
12486                            })
12487                            .unwrap_or(line_trimmed);
12488                        let line_trimmed = line_trimmed
12489                            .strip_suffix(end.as_ref())
12490                            .map(|s| {
12491                                last_line_delimiter = Some(end);
12492                                s.trim_end()
12493                            })
12494                            .unwrap_or(line_trimmed);
12495                        let line_trimmed = line_trimmed
12496                            .strip_prefix(prefix.as_ref())
12497                            .unwrap_or(line_trimmed);
12498                        Ok(line_trimmed)
12499                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12500                        line_trimmed.strip_prefix(prefix).with_context(|| {
12501                            format!("line did not start with prefix {prefix:?}: {line:?}")
12502                        })
12503                    } else {
12504                        line_trimmed
12505                            .strip_prefix(&line_prefix.trim_start())
12506                            .with_context(|| {
12507                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12508                            })
12509                    }
12510                })
12511                .collect::<Result<Vec<_>, _>>()
12512                .log_err()
12513            else {
12514                continue;
12515            };
12516
12517            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12518                buffer
12519                    .language_settings_at(Point::new(start_row, 0), cx)
12520                    .preferred_line_length as usize
12521            });
12522
12523            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12524                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12525            } else {
12526                line_prefix.clone()
12527            };
12528
12529            let wrapped_text = {
12530                let mut wrapped_text = wrap_with_prefix(
12531                    line_prefix,
12532                    subsequent_lines_prefix,
12533                    lines_without_prefixes.join("\n"),
12534                    wrap_column,
12535                    tab_size,
12536                    options.preserve_existing_whitespace,
12537                );
12538
12539                if let Some((indent, delimiter)) = first_line_delimiter {
12540                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12541                }
12542                if let Some(last_line) = last_line_delimiter {
12543                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12544                }
12545
12546                wrapped_text
12547            };
12548
12549            // TODO: should always use char-based diff while still supporting cursor behavior that
12550            // matches vim.
12551            let mut diff_options = DiffOptions::default();
12552            if options.override_language_settings {
12553                diff_options.max_word_diff_len = 0;
12554                diff_options.max_word_diff_line_count = 0;
12555            } else {
12556                diff_options.max_word_diff_len = usize::MAX;
12557                diff_options.max_word_diff_line_count = usize::MAX;
12558            }
12559
12560            for (old_range, new_text) in
12561                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12562            {
12563                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12564                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12565                edits.push((edit_start..edit_end, new_text));
12566            }
12567
12568            rewrapped_row_ranges.push(start_row..=end_row);
12569        }
12570
12571        self.buffer
12572            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12573    }
12574
12575    pub fn cut_common(
12576        &mut self,
12577        cut_no_selection_line: bool,
12578        window: &mut Window,
12579        cx: &mut Context<Self>,
12580    ) -> ClipboardItem {
12581        let mut text = String::new();
12582        let buffer = self.buffer.read(cx).snapshot(cx);
12583        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12584        let mut clipboard_selections = Vec::with_capacity(selections.len());
12585        {
12586            let max_point = buffer.max_point();
12587            let mut is_first = true;
12588            let mut prev_selection_was_entire_line = false;
12589            for selection in &mut selections {
12590                let is_entire_line =
12591                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12592                if is_entire_line {
12593                    selection.start = Point::new(selection.start.row, 0);
12594                    if !selection.is_empty() && selection.end.column == 0 {
12595                        selection.end = cmp::min(max_point, selection.end);
12596                    } else {
12597                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12598                    }
12599                    selection.goal = SelectionGoal::None;
12600                }
12601                if is_first {
12602                    is_first = false;
12603                } else if !prev_selection_was_entire_line {
12604                    text += "\n";
12605                }
12606                prev_selection_was_entire_line = is_entire_line;
12607                let mut len = 0;
12608                for chunk in buffer.text_for_range(selection.start..selection.end) {
12609                    text.push_str(chunk);
12610                    len += chunk.len();
12611                }
12612                clipboard_selections.push(ClipboardSelection {
12613                    len,
12614                    is_entire_line,
12615                    first_line_indent: buffer
12616                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12617                        .len,
12618                });
12619            }
12620        }
12621
12622        self.transact(window, cx, |this, window, cx| {
12623            this.change_selections(Default::default(), window, cx, |s| {
12624                s.select(selections);
12625            });
12626            this.insert("", window, cx);
12627        });
12628        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12629    }
12630
12631    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12633        let item = self.cut_common(true, window, cx);
12634        cx.write_to_clipboard(item);
12635    }
12636
12637    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12638        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12639        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12640            s.move_with(|snapshot, sel| {
12641                if sel.is_empty() {
12642                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12643                }
12644                if sel.is_empty() {
12645                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12646                }
12647            });
12648        });
12649        let item = self.cut_common(false, window, cx);
12650        cx.set_global(KillRing(item))
12651    }
12652
12653    pub fn kill_ring_yank(
12654        &mut self,
12655        _: &KillRingYank,
12656        window: &mut Window,
12657        cx: &mut Context<Self>,
12658    ) {
12659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12660        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12661            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12662                (kill_ring.text().to_string(), kill_ring.metadata_json())
12663            } else {
12664                return;
12665            }
12666        } else {
12667            return;
12668        };
12669        self.do_paste(&text, metadata, false, window, cx);
12670    }
12671
12672    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12673        self.do_copy(true, cx);
12674    }
12675
12676    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12677        self.do_copy(false, cx);
12678    }
12679
12680    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12681        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12682        let buffer = self.buffer.read(cx).read(cx);
12683        let mut text = String::new();
12684
12685        let mut clipboard_selections = Vec::with_capacity(selections.len());
12686        {
12687            let max_point = buffer.max_point();
12688            let mut is_first = true;
12689            let mut prev_selection_was_entire_line = false;
12690            for selection in &selections {
12691                let mut start = selection.start;
12692                let mut end = selection.end;
12693                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12694                let mut add_trailing_newline = false;
12695                if is_entire_line {
12696                    start = Point::new(start.row, 0);
12697                    let next_line_start = Point::new(end.row + 1, 0);
12698                    if next_line_start <= max_point {
12699                        end = next_line_start;
12700                    } else {
12701                        // We're on the last line without a trailing newline.
12702                        // Copy to the end of the line and add a newline afterwards.
12703                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12704                        add_trailing_newline = true;
12705                    }
12706                }
12707
12708                let mut trimmed_selections = Vec::new();
12709                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12710                    let row = MultiBufferRow(start.row);
12711                    let first_indent = buffer.indent_size_for_line(row);
12712                    if first_indent.len == 0 || start.column > first_indent.len {
12713                        trimmed_selections.push(start..end);
12714                    } else {
12715                        trimmed_selections.push(
12716                            Point::new(row.0, first_indent.len)
12717                                ..Point::new(row.0, buffer.line_len(row)),
12718                        );
12719                        for row in start.row + 1..=end.row {
12720                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12721                            if row == end.row {
12722                                line_len = end.column;
12723                            }
12724                            if line_len == 0 {
12725                                trimmed_selections
12726                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12727                                continue;
12728                            }
12729                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12730                            if row_indent_size.len >= first_indent.len {
12731                                trimmed_selections.push(
12732                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12733                                );
12734                            } else {
12735                                trimmed_selections.clear();
12736                                trimmed_selections.push(start..end);
12737                                break;
12738                            }
12739                        }
12740                    }
12741                } else {
12742                    trimmed_selections.push(start..end);
12743                }
12744
12745                for trimmed_range in trimmed_selections {
12746                    if is_first {
12747                        is_first = false;
12748                    } else if !prev_selection_was_entire_line {
12749                        text += "\n";
12750                    }
12751                    prev_selection_was_entire_line = is_entire_line;
12752                    let mut len = 0;
12753                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12754                        text.push_str(chunk);
12755                        len += chunk.len();
12756                    }
12757                    if add_trailing_newline {
12758                        text.push('\n');
12759                        len += 1;
12760                    }
12761                    clipboard_selections.push(ClipboardSelection {
12762                        len,
12763                        is_entire_line,
12764                        first_line_indent: buffer
12765                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12766                            .len,
12767                    });
12768                }
12769            }
12770        }
12771
12772        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12773            text,
12774            clipboard_selections,
12775        ));
12776    }
12777
12778    pub fn do_paste(
12779        &mut self,
12780        text: &String,
12781        clipboard_selections: Option<Vec<ClipboardSelection>>,
12782        handle_entire_lines: bool,
12783        window: &mut Window,
12784        cx: &mut Context<Self>,
12785    ) {
12786        if self.read_only(cx) {
12787            return;
12788        }
12789
12790        let clipboard_text = Cow::Borrowed(text.as_str());
12791
12792        self.transact(window, cx, |this, window, cx| {
12793            let had_active_edit_prediction = this.has_active_edit_prediction();
12794            let display_map = this.display_snapshot(cx);
12795            let old_selections = this.selections.all::<usize>(&display_map);
12796            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12797
12798            if let Some(mut clipboard_selections) = clipboard_selections {
12799                let all_selections_were_entire_line =
12800                    clipboard_selections.iter().all(|s| s.is_entire_line);
12801                let first_selection_indent_column =
12802                    clipboard_selections.first().map(|s| s.first_line_indent);
12803                if clipboard_selections.len() != old_selections.len() {
12804                    clipboard_selections.drain(..);
12805                }
12806                let mut auto_indent_on_paste = true;
12807
12808                this.buffer.update(cx, |buffer, cx| {
12809                    let snapshot = buffer.read(cx);
12810                    auto_indent_on_paste = snapshot
12811                        .language_settings_at(cursor_offset, cx)
12812                        .auto_indent_on_paste;
12813
12814                    let mut start_offset = 0;
12815                    let mut edits = Vec::new();
12816                    let mut original_indent_columns = Vec::new();
12817                    for (ix, selection) in old_selections.iter().enumerate() {
12818                        let to_insert;
12819                        let entire_line;
12820                        let original_indent_column;
12821                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12822                            let end_offset = start_offset + clipboard_selection.len;
12823                            to_insert = &clipboard_text[start_offset..end_offset];
12824                            entire_line = clipboard_selection.is_entire_line;
12825                            start_offset = if entire_line {
12826                                end_offset
12827                            } else {
12828                                end_offset + 1
12829                            };
12830                            original_indent_column = Some(clipboard_selection.first_line_indent);
12831                        } else {
12832                            to_insert = &*clipboard_text;
12833                            entire_line = all_selections_were_entire_line;
12834                            original_indent_column = first_selection_indent_column
12835                        }
12836
12837                        let (range, to_insert) =
12838                            if selection.is_empty() && handle_entire_lines && entire_line {
12839                                // If the corresponding selection was empty when this slice of the
12840                                // clipboard text was written, then the entire line containing the
12841                                // selection was copied. If this selection is also currently empty,
12842                                // then paste the line before the current line of the buffer.
12843                                let column = selection.start.to_point(&snapshot).column as usize;
12844                                let line_start = selection.start - column;
12845                                (line_start..line_start, Cow::Borrowed(to_insert))
12846                            } else {
12847                                let language = snapshot.language_at(selection.head());
12848                                let range = selection.range();
12849                                if let Some(language) = language
12850                                    && language.name() == "Markdown".into()
12851                                {
12852                                    edit_for_markdown_paste(
12853                                        &snapshot,
12854                                        range,
12855                                        to_insert,
12856                                        url::Url::parse(to_insert).ok(),
12857                                    )
12858                                } else {
12859                                    (range, Cow::Borrowed(to_insert))
12860                                }
12861                            };
12862
12863                        edits.push((range, to_insert));
12864                        original_indent_columns.push(original_indent_column);
12865                    }
12866                    drop(snapshot);
12867
12868                    buffer.edit(
12869                        edits,
12870                        if auto_indent_on_paste {
12871                            Some(AutoindentMode::Block {
12872                                original_indent_columns,
12873                            })
12874                        } else {
12875                            None
12876                        },
12877                        cx,
12878                    );
12879                });
12880
12881                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12882                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12883            } else {
12884                let url = url::Url::parse(&clipboard_text).ok();
12885
12886                let auto_indent_mode = if !clipboard_text.is_empty() {
12887                    Some(AutoindentMode::Block {
12888                        original_indent_columns: Vec::new(),
12889                    })
12890                } else {
12891                    None
12892                };
12893
12894                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12895                    let snapshot = buffer.snapshot(cx);
12896
12897                    let anchors = old_selections
12898                        .iter()
12899                        .map(|s| {
12900                            let anchor = snapshot.anchor_after(s.head());
12901                            s.map(|_| anchor)
12902                        })
12903                        .collect::<Vec<_>>();
12904
12905                    let mut edits = Vec::new();
12906
12907                    for selection in old_selections.iter() {
12908                        let language = snapshot.language_at(selection.head());
12909                        let range = selection.range();
12910
12911                        let (edit_range, edit_text) = if let Some(language) = language
12912                            && language.name() == "Markdown".into()
12913                        {
12914                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12915                        } else {
12916                            (range, clipboard_text.clone())
12917                        };
12918
12919                        edits.push((edit_range, edit_text));
12920                    }
12921
12922                    drop(snapshot);
12923                    buffer.edit(edits, auto_indent_mode, cx);
12924
12925                    anchors
12926                });
12927
12928                this.change_selections(Default::default(), window, cx, |s| {
12929                    s.select_anchors(selection_anchors);
12930                });
12931            }
12932
12933            //   🤔                 |    ..     | show_in_menu |
12934            // | ..                  |   true        true
12935            // | had_edit_prediction |   false       true
12936
12937            let trigger_in_words =
12938                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12939
12940            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12941        });
12942    }
12943
12944    pub fn diff_clipboard_with_selection(
12945        &mut self,
12946        _: &DiffClipboardWithSelection,
12947        window: &mut Window,
12948        cx: &mut Context<Self>,
12949    ) {
12950        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12951
12952        if selections.is_empty() {
12953            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12954            return;
12955        };
12956
12957        let clipboard_text = match cx.read_from_clipboard() {
12958            Some(item) => match item.entries().first() {
12959                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12960                _ => None,
12961            },
12962            None => None,
12963        };
12964
12965        let Some(clipboard_text) = clipboard_text else {
12966            log::warn!("Clipboard doesn't contain text.");
12967            return;
12968        };
12969
12970        window.dispatch_action(
12971            Box::new(DiffClipboardWithSelectionData {
12972                clipboard_text,
12973                editor: cx.entity(),
12974            }),
12975            cx,
12976        );
12977    }
12978
12979    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12981        if let Some(item) = cx.read_from_clipboard() {
12982            let entries = item.entries();
12983
12984            match entries.first() {
12985                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12986                // of all the pasted entries.
12987                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12988                    .do_paste(
12989                        clipboard_string.text(),
12990                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12991                        true,
12992                        window,
12993                        cx,
12994                    ),
12995                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12996            }
12997        }
12998    }
12999
13000    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13001        if self.read_only(cx) {
13002            return;
13003        }
13004
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13006
13007        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13008            if let Some((selections, _)) =
13009                self.selection_history.transaction(transaction_id).cloned()
13010            {
13011                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13012                    s.select_anchors(selections.to_vec());
13013                });
13014            } else {
13015                log::error!(
13016                    "No entry in selection_history found for undo. \
13017                     This may correspond to a bug where undo does not update the selection. \
13018                     If this is occurring, please add details to \
13019                     https://github.com/zed-industries/zed/issues/22692"
13020                );
13021            }
13022            self.request_autoscroll(Autoscroll::fit(), cx);
13023            self.unmark_text(window, cx);
13024            self.refresh_edit_prediction(true, false, window, cx);
13025            cx.emit(EditorEvent::Edited { transaction_id });
13026            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13027        }
13028    }
13029
13030    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13031        if self.read_only(cx) {
13032            return;
13033        }
13034
13035        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13036
13037        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13038            if let Some((_, Some(selections))) =
13039                self.selection_history.transaction(transaction_id).cloned()
13040            {
13041                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13042                    s.select_anchors(selections.to_vec());
13043                });
13044            } else {
13045                log::error!(
13046                    "No entry in selection_history found for redo. \
13047                     This may correspond to a bug where undo does not update the selection. \
13048                     If this is occurring, please add details to \
13049                     https://github.com/zed-industries/zed/issues/22692"
13050                );
13051            }
13052            self.request_autoscroll(Autoscroll::fit(), cx);
13053            self.unmark_text(window, cx);
13054            self.refresh_edit_prediction(true, false, window, cx);
13055            cx.emit(EditorEvent::Edited { transaction_id });
13056        }
13057    }
13058
13059    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13060        self.buffer
13061            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13062    }
13063
13064    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13065        self.buffer
13066            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13067    }
13068
13069    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13071        self.change_selections(Default::default(), window, cx, |s| {
13072            s.move_with(|map, selection| {
13073                let cursor = if selection.is_empty() {
13074                    movement::left(map, selection.start)
13075                } else {
13076                    selection.start
13077                };
13078                selection.collapse_to(cursor, SelectionGoal::None);
13079            });
13080        })
13081    }
13082
13083    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13085        self.change_selections(Default::default(), window, cx, |s| {
13086            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13087        })
13088    }
13089
13090    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13092        self.change_selections(Default::default(), window, cx, |s| {
13093            s.move_with(|map, selection| {
13094                let cursor = if selection.is_empty() {
13095                    movement::right(map, selection.end)
13096                } else {
13097                    selection.end
13098                };
13099                selection.collapse_to(cursor, SelectionGoal::None)
13100            });
13101        })
13102    }
13103
13104    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13106        self.change_selections(Default::default(), window, cx, |s| {
13107            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13108        });
13109    }
13110
13111    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13112        if self.take_rename(true, window, cx).is_some() {
13113            return;
13114        }
13115
13116        if self.mode.is_single_line() {
13117            cx.propagate();
13118            return;
13119        }
13120
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13122
13123        let text_layout_details = &self.text_layout_details(window);
13124        let selection_count = self.selections.count();
13125        let first_selection = self.selections.first_anchor();
13126
13127        self.change_selections(Default::default(), window, cx, |s| {
13128            s.move_with(|map, selection| {
13129                if !selection.is_empty() {
13130                    selection.goal = SelectionGoal::None;
13131                }
13132                let (cursor, goal) = movement::up(
13133                    map,
13134                    selection.start,
13135                    selection.goal,
13136                    false,
13137                    text_layout_details,
13138                );
13139                selection.collapse_to(cursor, goal);
13140            });
13141        });
13142
13143        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13144        {
13145            cx.propagate();
13146        }
13147    }
13148
13149    pub fn move_up_by_lines(
13150        &mut self,
13151        action: &MoveUpByLines,
13152        window: &mut Window,
13153        cx: &mut Context<Self>,
13154    ) {
13155        if self.take_rename(true, window, cx).is_some() {
13156            return;
13157        }
13158
13159        if self.mode.is_single_line() {
13160            cx.propagate();
13161            return;
13162        }
13163
13164        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13165
13166        let text_layout_details = &self.text_layout_details(window);
13167
13168        self.change_selections(Default::default(), window, cx, |s| {
13169            s.move_with(|map, selection| {
13170                if !selection.is_empty() {
13171                    selection.goal = SelectionGoal::None;
13172                }
13173                let (cursor, goal) = movement::up_by_rows(
13174                    map,
13175                    selection.start,
13176                    action.lines,
13177                    selection.goal,
13178                    false,
13179                    text_layout_details,
13180                );
13181                selection.collapse_to(cursor, goal);
13182            });
13183        })
13184    }
13185
13186    pub fn move_down_by_lines(
13187        &mut self,
13188        action: &MoveDownByLines,
13189        window: &mut Window,
13190        cx: &mut Context<Self>,
13191    ) {
13192        if self.take_rename(true, window, cx).is_some() {
13193            return;
13194        }
13195
13196        if self.mode.is_single_line() {
13197            cx.propagate();
13198            return;
13199        }
13200
13201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13202
13203        let text_layout_details = &self.text_layout_details(window);
13204
13205        self.change_selections(Default::default(), window, cx, |s| {
13206            s.move_with(|map, selection| {
13207                if !selection.is_empty() {
13208                    selection.goal = SelectionGoal::None;
13209                }
13210                let (cursor, goal) = movement::down_by_rows(
13211                    map,
13212                    selection.start,
13213                    action.lines,
13214                    selection.goal,
13215                    false,
13216                    text_layout_details,
13217                );
13218                selection.collapse_to(cursor, goal);
13219            });
13220        })
13221    }
13222
13223    pub fn select_down_by_lines(
13224        &mut self,
13225        action: &SelectDownByLines,
13226        window: &mut Window,
13227        cx: &mut Context<Self>,
13228    ) {
13229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13230        let text_layout_details = &self.text_layout_details(window);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_heads_with(|map, head, goal| {
13233                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13234            })
13235        })
13236    }
13237
13238    pub fn select_up_by_lines(
13239        &mut self,
13240        action: &SelectUpByLines,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        let text_layout_details = &self.text_layout_details(window);
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_heads_with(|map, head, goal| {
13248                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13249            })
13250        })
13251    }
13252
13253    pub fn select_page_up(
13254        &mut self,
13255        _: &SelectPageUp,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        let Some(row_count) = self.visible_row_count() else {
13260            return;
13261        };
13262
13263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13264
13265        let text_layout_details = &self.text_layout_details(window);
13266
13267        self.change_selections(Default::default(), window, cx, |s| {
13268            s.move_heads_with(|map, head, goal| {
13269                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13270            })
13271        })
13272    }
13273
13274    pub fn move_page_up(
13275        &mut self,
13276        action: &MovePageUp,
13277        window: &mut Window,
13278        cx: &mut Context<Self>,
13279    ) {
13280        if self.take_rename(true, window, cx).is_some() {
13281            return;
13282        }
13283
13284        if self
13285            .context_menu
13286            .borrow_mut()
13287            .as_mut()
13288            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13289            .unwrap_or(false)
13290        {
13291            return;
13292        }
13293
13294        if matches!(self.mode, EditorMode::SingleLine) {
13295            cx.propagate();
13296            return;
13297        }
13298
13299        let Some(row_count) = self.visible_row_count() else {
13300            return;
13301        };
13302
13303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13304
13305        let effects = if action.center_cursor {
13306            SelectionEffects::scroll(Autoscroll::center())
13307        } else {
13308            SelectionEffects::default()
13309        };
13310
13311        let text_layout_details = &self.text_layout_details(window);
13312
13313        self.change_selections(effects, window, cx, |s| {
13314            s.move_with(|map, selection| {
13315                if !selection.is_empty() {
13316                    selection.goal = SelectionGoal::None;
13317                }
13318                let (cursor, goal) = movement::up_by_rows(
13319                    map,
13320                    selection.end,
13321                    row_count,
13322                    selection.goal,
13323                    false,
13324                    text_layout_details,
13325                );
13326                selection.collapse_to(cursor, goal);
13327            });
13328        });
13329    }
13330
13331    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13332        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13333        let text_layout_details = &self.text_layout_details(window);
13334        self.change_selections(Default::default(), window, cx, |s| {
13335            s.move_heads_with(|map, head, goal| {
13336                movement::up(map, head, goal, false, text_layout_details)
13337            })
13338        })
13339    }
13340
13341    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13342        self.take_rename(true, window, cx);
13343
13344        if self.mode.is_single_line() {
13345            cx.propagate();
13346            return;
13347        }
13348
13349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13350
13351        let text_layout_details = &self.text_layout_details(window);
13352        let selection_count = self.selections.count();
13353        let first_selection = self.selections.first_anchor();
13354
13355        self.change_selections(Default::default(), window, cx, |s| {
13356            s.move_with(|map, selection| {
13357                if !selection.is_empty() {
13358                    selection.goal = SelectionGoal::None;
13359                }
13360                let (cursor, goal) = movement::down(
13361                    map,
13362                    selection.end,
13363                    selection.goal,
13364                    false,
13365                    text_layout_details,
13366                );
13367                selection.collapse_to(cursor, goal);
13368            });
13369        });
13370
13371        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13372        {
13373            cx.propagate();
13374        }
13375    }
13376
13377    pub fn select_page_down(
13378        &mut self,
13379        _: &SelectPageDown,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        let Some(row_count) = self.visible_row_count() else {
13384            return;
13385        };
13386
13387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13388
13389        let text_layout_details = &self.text_layout_details(window);
13390
13391        self.change_selections(Default::default(), window, cx, |s| {
13392            s.move_heads_with(|map, head, goal| {
13393                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13394            })
13395        })
13396    }
13397
13398    pub fn move_page_down(
13399        &mut self,
13400        action: &MovePageDown,
13401        window: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        if self.take_rename(true, window, cx).is_some() {
13405            return;
13406        }
13407
13408        if self
13409            .context_menu
13410            .borrow_mut()
13411            .as_mut()
13412            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13413            .unwrap_or(false)
13414        {
13415            return;
13416        }
13417
13418        if matches!(self.mode, EditorMode::SingleLine) {
13419            cx.propagate();
13420            return;
13421        }
13422
13423        let Some(row_count) = self.visible_row_count() else {
13424            return;
13425        };
13426
13427        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13428
13429        let effects = if action.center_cursor {
13430            SelectionEffects::scroll(Autoscroll::center())
13431        } else {
13432            SelectionEffects::default()
13433        };
13434
13435        let text_layout_details = &self.text_layout_details(window);
13436        self.change_selections(effects, window, cx, |s| {
13437            s.move_with(|map, selection| {
13438                if !selection.is_empty() {
13439                    selection.goal = SelectionGoal::None;
13440                }
13441                let (cursor, goal) = movement::down_by_rows(
13442                    map,
13443                    selection.end,
13444                    row_count,
13445                    selection.goal,
13446                    false,
13447                    text_layout_details,
13448                );
13449                selection.collapse_to(cursor, goal);
13450            });
13451        });
13452    }
13453
13454    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13456        let text_layout_details = &self.text_layout_details(window);
13457        self.change_selections(Default::default(), window, cx, |s| {
13458            s.move_heads_with(|map, head, goal| {
13459                movement::down(map, head, goal, false, text_layout_details)
13460            })
13461        });
13462    }
13463
13464    pub fn context_menu_first(
13465        &mut self,
13466        _: &ContextMenuFirst,
13467        window: &mut Window,
13468        cx: &mut Context<Self>,
13469    ) {
13470        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13471            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13472        }
13473    }
13474
13475    pub fn context_menu_prev(
13476        &mut self,
13477        _: &ContextMenuPrevious,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) {
13481        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13482            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13483        }
13484    }
13485
13486    pub fn context_menu_next(
13487        &mut self,
13488        _: &ContextMenuNext,
13489        window: &mut Window,
13490        cx: &mut Context<Self>,
13491    ) {
13492        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13493            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13494        }
13495    }
13496
13497    pub fn context_menu_last(
13498        &mut self,
13499        _: &ContextMenuLast,
13500        window: &mut Window,
13501        cx: &mut Context<Self>,
13502    ) {
13503        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13504            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13505        }
13506    }
13507
13508    pub fn signature_help_prev(
13509        &mut self,
13510        _: &SignatureHelpPrevious,
13511        _: &mut Window,
13512        cx: &mut Context<Self>,
13513    ) {
13514        if let Some(popover) = self.signature_help_state.popover_mut() {
13515            if popover.current_signature == 0 {
13516                popover.current_signature = popover.signatures.len() - 1;
13517            } else {
13518                popover.current_signature -= 1;
13519            }
13520            cx.notify();
13521        }
13522    }
13523
13524    pub fn signature_help_next(
13525        &mut self,
13526        _: &SignatureHelpNext,
13527        _: &mut Window,
13528        cx: &mut Context<Self>,
13529    ) {
13530        if let Some(popover) = self.signature_help_state.popover_mut() {
13531            if popover.current_signature + 1 == popover.signatures.len() {
13532                popover.current_signature = 0;
13533            } else {
13534                popover.current_signature += 1;
13535            }
13536            cx.notify();
13537        }
13538    }
13539
13540    pub fn move_to_previous_word_start(
13541        &mut self,
13542        _: &MoveToPreviousWordStart,
13543        window: &mut Window,
13544        cx: &mut Context<Self>,
13545    ) {
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13547        self.change_selections(Default::default(), window, cx, |s| {
13548            s.move_cursors_with(|map, head, _| {
13549                (
13550                    movement::previous_word_start(map, head),
13551                    SelectionGoal::None,
13552                )
13553            });
13554        })
13555    }
13556
13557    pub fn move_to_previous_subword_start(
13558        &mut self,
13559        _: &MoveToPreviousSubwordStart,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13564        self.change_selections(Default::default(), window, cx, |s| {
13565            s.move_cursors_with(|map, head, _| {
13566                (
13567                    movement::previous_subword_start(map, head),
13568                    SelectionGoal::None,
13569                )
13570            });
13571        })
13572    }
13573
13574    pub fn select_to_previous_word_start(
13575        &mut self,
13576        _: &SelectToPreviousWordStart,
13577        window: &mut Window,
13578        cx: &mut Context<Self>,
13579    ) {
13580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13581        self.change_selections(Default::default(), window, cx, |s| {
13582            s.move_heads_with(|map, head, _| {
13583                (
13584                    movement::previous_word_start(map, head),
13585                    SelectionGoal::None,
13586                )
13587            });
13588        })
13589    }
13590
13591    pub fn select_to_previous_subword_start(
13592        &mut self,
13593        _: &SelectToPreviousSubwordStart,
13594        window: &mut Window,
13595        cx: &mut Context<Self>,
13596    ) {
13597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13598        self.change_selections(Default::default(), window, cx, |s| {
13599            s.move_heads_with(|map, head, _| {
13600                (
13601                    movement::previous_subword_start(map, head),
13602                    SelectionGoal::None,
13603                )
13604            });
13605        })
13606    }
13607
13608    pub fn delete_to_previous_word_start(
13609        &mut self,
13610        action: &DeleteToPreviousWordStart,
13611        window: &mut Window,
13612        cx: &mut Context<Self>,
13613    ) {
13614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13615        self.transact(window, cx, |this, window, cx| {
13616            this.select_autoclose_pair(window, cx);
13617            this.change_selections(Default::default(), window, cx, |s| {
13618                s.move_with(|map, selection| {
13619                    if selection.is_empty() {
13620                        let mut cursor = if action.ignore_newlines {
13621                            movement::previous_word_start(map, selection.head())
13622                        } else {
13623                            movement::previous_word_start_or_newline(map, selection.head())
13624                        };
13625                        cursor = movement::adjust_greedy_deletion(
13626                            map,
13627                            selection.head(),
13628                            cursor,
13629                            action.ignore_brackets,
13630                        );
13631                        selection.set_head(cursor, SelectionGoal::None);
13632                    }
13633                });
13634            });
13635            this.insert("", window, cx);
13636        });
13637    }
13638
13639    pub fn delete_to_previous_subword_start(
13640        &mut self,
13641        _: &DeleteToPreviousSubwordStart,
13642        window: &mut Window,
13643        cx: &mut Context<Self>,
13644    ) {
13645        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13646        self.transact(window, cx, |this, window, cx| {
13647            this.select_autoclose_pair(window, cx);
13648            this.change_selections(Default::default(), window, cx, |s| {
13649                s.move_with(|map, selection| {
13650                    if selection.is_empty() {
13651                        let mut cursor = movement::previous_subword_start(map, selection.head());
13652                        cursor =
13653                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13654                        selection.set_head(cursor, SelectionGoal::None);
13655                    }
13656                });
13657            });
13658            this.insert("", window, cx);
13659        });
13660    }
13661
13662    pub fn move_to_next_word_end(
13663        &mut self,
13664        _: &MoveToNextWordEnd,
13665        window: &mut Window,
13666        cx: &mut Context<Self>,
13667    ) {
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_cursors_with(|map, head, _| {
13671                (movement::next_word_end(map, head), SelectionGoal::None)
13672            });
13673        })
13674    }
13675
13676    pub fn move_to_next_subword_end(
13677        &mut self,
13678        _: &MoveToNextSubwordEnd,
13679        window: &mut Window,
13680        cx: &mut Context<Self>,
13681    ) {
13682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13683        self.change_selections(Default::default(), window, cx, |s| {
13684            s.move_cursors_with(|map, head, _| {
13685                (movement::next_subword_end(map, head), SelectionGoal::None)
13686            });
13687        })
13688    }
13689
13690    pub fn select_to_next_word_end(
13691        &mut self,
13692        _: &SelectToNextWordEnd,
13693        window: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) {
13696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13697        self.change_selections(Default::default(), window, cx, |s| {
13698            s.move_heads_with(|map, head, _| {
13699                (movement::next_word_end(map, head), SelectionGoal::None)
13700            });
13701        })
13702    }
13703
13704    pub fn select_to_next_subword_end(
13705        &mut self,
13706        _: &SelectToNextSubwordEnd,
13707        window: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.move_heads_with(|map, head, _| {
13713                (movement::next_subword_end(map, head), SelectionGoal::None)
13714            });
13715        })
13716    }
13717
13718    pub fn delete_to_next_word_end(
13719        &mut self,
13720        action: &DeleteToNextWordEnd,
13721        window: &mut Window,
13722        cx: &mut Context<Self>,
13723    ) {
13724        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13725        self.transact(window, cx, |this, window, cx| {
13726            this.change_selections(Default::default(), window, cx, |s| {
13727                s.move_with(|map, selection| {
13728                    if selection.is_empty() {
13729                        let mut cursor = if action.ignore_newlines {
13730                            movement::next_word_end(map, selection.head())
13731                        } else {
13732                            movement::next_word_end_or_newline(map, selection.head())
13733                        };
13734                        cursor = movement::adjust_greedy_deletion(
13735                            map,
13736                            selection.head(),
13737                            cursor,
13738                            action.ignore_brackets,
13739                        );
13740                        selection.set_head(cursor, SelectionGoal::None);
13741                    }
13742                });
13743            });
13744            this.insert("", window, cx);
13745        });
13746    }
13747
13748    pub fn delete_to_next_subword_end(
13749        &mut self,
13750        _: &DeleteToNextSubwordEnd,
13751        window: &mut Window,
13752        cx: &mut Context<Self>,
13753    ) {
13754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13755        self.transact(window, cx, |this, window, cx| {
13756            this.change_selections(Default::default(), window, cx, |s| {
13757                s.move_with(|map, selection| {
13758                    if selection.is_empty() {
13759                        let mut cursor = movement::next_subword_end(map, selection.head());
13760                        cursor =
13761                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13762                        selection.set_head(cursor, SelectionGoal::None);
13763                    }
13764                });
13765            });
13766            this.insert("", window, cx);
13767        });
13768    }
13769
13770    pub fn move_to_beginning_of_line(
13771        &mut self,
13772        action: &MoveToBeginningOfLine,
13773        window: &mut Window,
13774        cx: &mut Context<Self>,
13775    ) {
13776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13777        self.change_selections(Default::default(), window, cx, |s| {
13778            s.move_cursors_with(|map, head, _| {
13779                (
13780                    movement::indented_line_beginning(
13781                        map,
13782                        head,
13783                        action.stop_at_soft_wraps,
13784                        action.stop_at_indent,
13785                    ),
13786                    SelectionGoal::None,
13787                )
13788            });
13789        })
13790    }
13791
13792    pub fn select_to_beginning_of_line(
13793        &mut self,
13794        action: &SelectToBeginningOfLine,
13795        window: &mut Window,
13796        cx: &mut Context<Self>,
13797    ) {
13798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13799        self.change_selections(Default::default(), window, cx, |s| {
13800            s.move_heads_with(|map, head, _| {
13801                (
13802                    movement::indented_line_beginning(
13803                        map,
13804                        head,
13805                        action.stop_at_soft_wraps,
13806                        action.stop_at_indent,
13807                    ),
13808                    SelectionGoal::None,
13809                )
13810            });
13811        });
13812    }
13813
13814    pub fn delete_to_beginning_of_line(
13815        &mut self,
13816        action: &DeleteToBeginningOfLine,
13817        window: &mut Window,
13818        cx: &mut Context<Self>,
13819    ) {
13820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13821        self.transact(window, cx, |this, window, cx| {
13822            this.change_selections(Default::default(), window, cx, |s| {
13823                s.move_with(|_, selection| {
13824                    selection.reversed = true;
13825                });
13826            });
13827
13828            this.select_to_beginning_of_line(
13829                &SelectToBeginningOfLine {
13830                    stop_at_soft_wraps: false,
13831                    stop_at_indent: action.stop_at_indent,
13832                },
13833                window,
13834                cx,
13835            );
13836            this.backspace(&Backspace, window, cx);
13837        });
13838    }
13839
13840    pub fn move_to_end_of_line(
13841        &mut self,
13842        action: &MoveToEndOfLine,
13843        window: &mut Window,
13844        cx: &mut Context<Self>,
13845    ) {
13846        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13847        self.change_selections(Default::default(), window, cx, |s| {
13848            s.move_cursors_with(|map, head, _| {
13849                (
13850                    movement::line_end(map, head, action.stop_at_soft_wraps),
13851                    SelectionGoal::None,
13852                )
13853            });
13854        })
13855    }
13856
13857    pub fn select_to_end_of_line(
13858        &mut self,
13859        action: &SelectToEndOfLine,
13860        window: &mut Window,
13861        cx: &mut Context<Self>,
13862    ) {
13863        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13864        self.change_selections(Default::default(), window, cx, |s| {
13865            s.move_heads_with(|map, head, _| {
13866                (
13867                    movement::line_end(map, head, action.stop_at_soft_wraps),
13868                    SelectionGoal::None,
13869                )
13870            });
13871        })
13872    }
13873
13874    pub fn delete_to_end_of_line(
13875        &mut self,
13876        _: &DeleteToEndOfLine,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13881        self.transact(window, cx, |this, window, cx| {
13882            this.select_to_end_of_line(
13883                &SelectToEndOfLine {
13884                    stop_at_soft_wraps: false,
13885                },
13886                window,
13887                cx,
13888            );
13889            this.delete(&Delete, window, cx);
13890        });
13891    }
13892
13893    pub fn cut_to_end_of_line(
13894        &mut self,
13895        action: &CutToEndOfLine,
13896        window: &mut Window,
13897        cx: &mut Context<Self>,
13898    ) {
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13900        self.transact(window, cx, |this, window, cx| {
13901            this.select_to_end_of_line(
13902                &SelectToEndOfLine {
13903                    stop_at_soft_wraps: false,
13904                },
13905                window,
13906                cx,
13907            );
13908            if !action.stop_at_newlines {
13909                this.change_selections(Default::default(), window, cx, |s| {
13910                    s.move_with(|_, sel| {
13911                        if sel.is_empty() {
13912                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13913                        }
13914                    });
13915                });
13916            }
13917            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13918            let item = this.cut_common(false, window, cx);
13919            cx.write_to_clipboard(item);
13920        });
13921    }
13922
13923    pub fn move_to_start_of_paragraph(
13924        &mut self,
13925        _: &MoveToStartOfParagraph,
13926        window: &mut Window,
13927        cx: &mut Context<Self>,
13928    ) {
13929        if matches!(self.mode, EditorMode::SingleLine) {
13930            cx.propagate();
13931            return;
13932        }
13933        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13934        self.change_selections(Default::default(), window, cx, |s| {
13935            s.move_with(|map, selection| {
13936                selection.collapse_to(
13937                    movement::start_of_paragraph(map, selection.head(), 1),
13938                    SelectionGoal::None,
13939                )
13940            });
13941        })
13942    }
13943
13944    pub fn move_to_end_of_paragraph(
13945        &mut self,
13946        _: &MoveToEndOfParagraph,
13947        window: &mut Window,
13948        cx: &mut Context<Self>,
13949    ) {
13950        if matches!(self.mode, EditorMode::SingleLine) {
13951            cx.propagate();
13952            return;
13953        }
13954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13955        self.change_selections(Default::default(), window, cx, |s| {
13956            s.move_with(|map, selection| {
13957                selection.collapse_to(
13958                    movement::end_of_paragraph(map, selection.head(), 1),
13959                    SelectionGoal::None,
13960                )
13961            });
13962        })
13963    }
13964
13965    pub fn select_to_start_of_paragraph(
13966        &mut self,
13967        _: &SelectToStartOfParagraph,
13968        window: &mut Window,
13969        cx: &mut Context<Self>,
13970    ) {
13971        if matches!(self.mode, EditorMode::SingleLine) {
13972            cx.propagate();
13973            return;
13974        }
13975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13976        self.change_selections(Default::default(), window, cx, |s| {
13977            s.move_heads_with(|map, head, _| {
13978                (
13979                    movement::start_of_paragraph(map, head, 1),
13980                    SelectionGoal::None,
13981                )
13982            });
13983        })
13984    }
13985
13986    pub fn select_to_end_of_paragraph(
13987        &mut self,
13988        _: &SelectToEndOfParagraph,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        if matches!(self.mode, EditorMode::SingleLine) {
13993            cx.propagate();
13994            return;
13995        }
13996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13997        self.change_selections(Default::default(), window, cx, |s| {
13998            s.move_heads_with(|map, head, _| {
13999                (
14000                    movement::end_of_paragraph(map, head, 1),
14001                    SelectionGoal::None,
14002                )
14003            });
14004        })
14005    }
14006
14007    pub fn move_to_start_of_excerpt(
14008        &mut self,
14009        _: &MoveToStartOfExcerpt,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) {
14013        if matches!(self.mode, EditorMode::SingleLine) {
14014            cx.propagate();
14015            return;
14016        }
14017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14018        self.change_selections(Default::default(), window, cx, |s| {
14019            s.move_with(|map, selection| {
14020                selection.collapse_to(
14021                    movement::start_of_excerpt(
14022                        map,
14023                        selection.head(),
14024                        workspace::searchable::Direction::Prev,
14025                    ),
14026                    SelectionGoal::None,
14027                )
14028            });
14029        })
14030    }
14031
14032    pub fn move_to_start_of_next_excerpt(
14033        &mut self,
14034        _: &MoveToStartOfNextExcerpt,
14035        window: &mut Window,
14036        cx: &mut Context<Self>,
14037    ) {
14038        if matches!(self.mode, EditorMode::SingleLine) {
14039            cx.propagate();
14040            return;
14041        }
14042
14043        self.change_selections(Default::default(), window, cx, |s| {
14044            s.move_with(|map, selection| {
14045                selection.collapse_to(
14046                    movement::start_of_excerpt(
14047                        map,
14048                        selection.head(),
14049                        workspace::searchable::Direction::Next,
14050                    ),
14051                    SelectionGoal::None,
14052                )
14053            });
14054        })
14055    }
14056
14057    pub fn move_to_end_of_excerpt(
14058        &mut self,
14059        _: &MoveToEndOfExcerpt,
14060        window: &mut Window,
14061        cx: &mut Context<Self>,
14062    ) {
14063        if matches!(self.mode, EditorMode::SingleLine) {
14064            cx.propagate();
14065            return;
14066        }
14067        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14068        self.change_selections(Default::default(), window, cx, |s| {
14069            s.move_with(|map, selection| {
14070                selection.collapse_to(
14071                    movement::end_of_excerpt(
14072                        map,
14073                        selection.head(),
14074                        workspace::searchable::Direction::Next,
14075                    ),
14076                    SelectionGoal::None,
14077                )
14078            });
14079        })
14080    }
14081
14082    pub fn move_to_end_of_previous_excerpt(
14083        &mut self,
14084        _: &MoveToEndOfPreviousExcerpt,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) {
14088        if matches!(self.mode, EditorMode::SingleLine) {
14089            cx.propagate();
14090            return;
14091        }
14092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14093        self.change_selections(Default::default(), window, cx, |s| {
14094            s.move_with(|map, selection| {
14095                selection.collapse_to(
14096                    movement::end_of_excerpt(
14097                        map,
14098                        selection.head(),
14099                        workspace::searchable::Direction::Prev,
14100                    ),
14101                    SelectionGoal::None,
14102                )
14103            });
14104        })
14105    }
14106
14107    pub fn select_to_start_of_excerpt(
14108        &mut self,
14109        _: &SelectToStartOfExcerpt,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) {
14113        if matches!(self.mode, EditorMode::SingleLine) {
14114            cx.propagate();
14115            return;
14116        }
14117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14118        self.change_selections(Default::default(), window, cx, |s| {
14119            s.move_heads_with(|map, head, _| {
14120                (
14121                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14122                    SelectionGoal::None,
14123                )
14124            });
14125        })
14126    }
14127
14128    pub fn select_to_start_of_next_excerpt(
14129        &mut self,
14130        _: &SelectToStartOfNextExcerpt,
14131        window: &mut Window,
14132        cx: &mut Context<Self>,
14133    ) {
14134        if matches!(self.mode, EditorMode::SingleLine) {
14135            cx.propagate();
14136            return;
14137        }
14138        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14139        self.change_selections(Default::default(), window, cx, |s| {
14140            s.move_heads_with(|map, head, _| {
14141                (
14142                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14143                    SelectionGoal::None,
14144                )
14145            });
14146        })
14147    }
14148
14149    pub fn select_to_end_of_excerpt(
14150        &mut self,
14151        _: &SelectToEndOfExcerpt,
14152        window: &mut Window,
14153        cx: &mut Context<Self>,
14154    ) {
14155        if matches!(self.mode, EditorMode::SingleLine) {
14156            cx.propagate();
14157            return;
14158        }
14159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14160        self.change_selections(Default::default(), window, cx, |s| {
14161            s.move_heads_with(|map, head, _| {
14162                (
14163                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14164                    SelectionGoal::None,
14165                )
14166            });
14167        })
14168    }
14169
14170    pub fn select_to_end_of_previous_excerpt(
14171        &mut self,
14172        _: &SelectToEndOfPreviousExcerpt,
14173        window: &mut Window,
14174        cx: &mut Context<Self>,
14175    ) {
14176        if matches!(self.mode, EditorMode::SingleLine) {
14177            cx.propagate();
14178            return;
14179        }
14180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14181        self.change_selections(Default::default(), window, cx, |s| {
14182            s.move_heads_with(|map, head, _| {
14183                (
14184                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14185                    SelectionGoal::None,
14186                )
14187            });
14188        })
14189    }
14190
14191    pub fn move_to_beginning(
14192        &mut self,
14193        _: &MoveToBeginning,
14194        window: &mut Window,
14195        cx: &mut Context<Self>,
14196    ) {
14197        if matches!(self.mode, EditorMode::SingleLine) {
14198            cx.propagate();
14199            return;
14200        }
14201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14202        self.change_selections(Default::default(), window, cx, |s| {
14203            s.select_ranges(vec![0..0]);
14204        });
14205    }
14206
14207    pub fn select_to_beginning(
14208        &mut self,
14209        _: &SelectToBeginning,
14210        window: &mut Window,
14211        cx: &mut Context<Self>,
14212    ) {
14213        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14214        selection.set_head(Point::zero(), SelectionGoal::None);
14215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14216        self.change_selections(Default::default(), window, cx, |s| {
14217            s.select(vec![selection]);
14218        });
14219    }
14220
14221    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14222        if matches!(self.mode, EditorMode::SingleLine) {
14223            cx.propagate();
14224            return;
14225        }
14226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14227        let cursor = self.buffer.read(cx).read(cx).len();
14228        self.change_selections(Default::default(), window, cx, |s| {
14229            s.select_ranges(vec![cursor..cursor])
14230        });
14231    }
14232
14233    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14234        self.nav_history = nav_history;
14235    }
14236
14237    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14238        self.nav_history.as_ref()
14239    }
14240
14241    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14242        self.push_to_nav_history(
14243            self.selections.newest_anchor().head(),
14244            None,
14245            false,
14246            true,
14247            cx,
14248        );
14249    }
14250
14251    fn push_to_nav_history(
14252        &mut self,
14253        cursor_anchor: Anchor,
14254        new_position: Option<Point>,
14255        is_deactivate: bool,
14256        always: bool,
14257        cx: &mut Context<Self>,
14258    ) {
14259        if let Some(nav_history) = self.nav_history.as_mut() {
14260            let buffer = self.buffer.read(cx).read(cx);
14261            let cursor_position = cursor_anchor.to_point(&buffer);
14262            let scroll_state = self.scroll_manager.anchor();
14263            let scroll_top_row = scroll_state.top_row(&buffer);
14264            drop(buffer);
14265
14266            if let Some(new_position) = new_position {
14267                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14268                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14269                    return;
14270                }
14271            }
14272
14273            nav_history.push(
14274                Some(NavigationData {
14275                    cursor_anchor,
14276                    cursor_position,
14277                    scroll_anchor: scroll_state,
14278                    scroll_top_row,
14279                }),
14280                cx,
14281            );
14282            cx.emit(EditorEvent::PushedToNavHistory {
14283                anchor: cursor_anchor,
14284                is_deactivate,
14285            })
14286        }
14287    }
14288
14289    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14291        let buffer = self.buffer.read(cx).snapshot(cx);
14292        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14293        selection.set_head(buffer.len(), SelectionGoal::None);
14294        self.change_selections(Default::default(), window, cx, |s| {
14295            s.select(vec![selection]);
14296        });
14297    }
14298
14299    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14300        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14301        let end = self.buffer.read(cx).read(cx).len();
14302        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14303            s.select_ranges(vec![0..end]);
14304        });
14305    }
14306
14307    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14309        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14310        let mut selections = self.selections.all::<Point>(&display_map);
14311        let max_point = display_map.buffer_snapshot().max_point();
14312        for selection in &mut selections {
14313            let rows = selection.spanned_rows(true, &display_map);
14314            selection.start = Point::new(rows.start.0, 0);
14315            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14316            selection.reversed = false;
14317        }
14318        self.change_selections(Default::default(), window, cx, |s| {
14319            s.select(selections);
14320        });
14321    }
14322
14323    pub fn split_selection_into_lines(
14324        &mut self,
14325        action: &SplitSelectionIntoLines,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) {
14329        let selections = self
14330            .selections
14331            .all::<Point>(&self.display_snapshot(cx))
14332            .into_iter()
14333            .map(|selection| selection.start..selection.end)
14334            .collect::<Vec<_>>();
14335        self.unfold_ranges(&selections, true, true, cx);
14336
14337        let mut new_selection_ranges = Vec::new();
14338        {
14339            let buffer = self.buffer.read(cx).read(cx);
14340            for selection in selections {
14341                for row in selection.start.row..selection.end.row {
14342                    let line_start = Point::new(row, 0);
14343                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14344
14345                    if action.keep_selections {
14346                        // Keep the selection range for each line
14347                        let selection_start = if row == selection.start.row {
14348                            selection.start
14349                        } else {
14350                            line_start
14351                        };
14352                        new_selection_ranges.push(selection_start..line_end);
14353                    } else {
14354                        // Collapse to cursor at end of line
14355                        new_selection_ranges.push(line_end..line_end);
14356                    }
14357                }
14358
14359                let is_multiline_selection = selection.start.row != selection.end.row;
14360                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14361                // so this action feels more ergonomic when paired with other selection operations
14362                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14363                if !should_skip_last {
14364                    if action.keep_selections {
14365                        if is_multiline_selection {
14366                            let line_start = Point::new(selection.end.row, 0);
14367                            new_selection_ranges.push(line_start..selection.end);
14368                        } else {
14369                            new_selection_ranges.push(selection.start..selection.end);
14370                        }
14371                    } else {
14372                        new_selection_ranges.push(selection.end..selection.end);
14373                    }
14374                }
14375            }
14376        }
14377        self.change_selections(Default::default(), window, cx, |s| {
14378            s.select_ranges(new_selection_ranges);
14379        });
14380    }
14381
14382    pub fn add_selection_above(
14383        &mut self,
14384        action: &AddSelectionAbove,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) {
14388        self.add_selection(true, action.skip_soft_wrap, window, cx);
14389    }
14390
14391    pub fn add_selection_below(
14392        &mut self,
14393        action: &AddSelectionBelow,
14394        window: &mut Window,
14395        cx: &mut Context<Self>,
14396    ) {
14397        self.add_selection(false, action.skip_soft_wrap, window, cx);
14398    }
14399
14400    fn add_selection(
14401        &mut self,
14402        above: bool,
14403        skip_soft_wrap: bool,
14404        window: &mut Window,
14405        cx: &mut Context<Self>,
14406    ) {
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408
14409        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14410        let all_selections = self.selections.all::<Point>(&display_map);
14411        let text_layout_details = self.text_layout_details(window);
14412
14413        let (mut columnar_selections, new_selections_to_columnarize) = {
14414            if let Some(state) = self.add_selections_state.as_ref() {
14415                let columnar_selection_ids: HashSet<_> = state
14416                    .groups
14417                    .iter()
14418                    .flat_map(|group| group.stack.iter())
14419                    .copied()
14420                    .collect();
14421
14422                all_selections
14423                    .into_iter()
14424                    .partition(|s| columnar_selection_ids.contains(&s.id))
14425            } else {
14426                (Vec::new(), all_selections)
14427            }
14428        };
14429
14430        let mut state = self
14431            .add_selections_state
14432            .take()
14433            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14434
14435        for selection in new_selections_to_columnarize {
14436            let range = selection.display_range(&display_map).sorted();
14437            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14438            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14439            let positions = start_x.min(end_x)..start_x.max(end_x);
14440            let mut stack = Vec::new();
14441            for row in range.start.row().0..=range.end.row().0 {
14442                if let Some(selection) = self.selections.build_columnar_selection(
14443                    &display_map,
14444                    DisplayRow(row),
14445                    &positions,
14446                    selection.reversed,
14447                    &text_layout_details,
14448                ) {
14449                    stack.push(selection.id);
14450                    columnar_selections.push(selection);
14451                }
14452            }
14453            if !stack.is_empty() {
14454                if above {
14455                    stack.reverse();
14456                }
14457                state.groups.push(AddSelectionsGroup { above, stack });
14458            }
14459        }
14460
14461        let mut final_selections = Vec::new();
14462        let end_row = if above {
14463            DisplayRow(0)
14464        } else {
14465            display_map.max_point().row()
14466        };
14467
14468        let mut last_added_item_per_group = HashMap::default();
14469        for group in state.groups.iter_mut() {
14470            if let Some(last_id) = group.stack.last() {
14471                last_added_item_per_group.insert(*last_id, group);
14472            }
14473        }
14474
14475        for selection in columnar_selections {
14476            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14477                if above == group.above {
14478                    let range = selection.display_range(&display_map).sorted();
14479                    debug_assert_eq!(range.start.row(), range.end.row());
14480                    let mut row = range.start.row();
14481                    let positions =
14482                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14483                            Pixels::from(start)..Pixels::from(end)
14484                        } else {
14485                            let start_x =
14486                                display_map.x_for_display_point(range.start, &text_layout_details);
14487                            let end_x =
14488                                display_map.x_for_display_point(range.end, &text_layout_details);
14489                            start_x.min(end_x)..start_x.max(end_x)
14490                        };
14491
14492                    let mut maybe_new_selection = None;
14493                    let direction = if above { -1 } else { 1 };
14494
14495                    while row != end_row {
14496                        if skip_soft_wrap {
14497                            row = display_map
14498                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14499                                .row();
14500                        } else if above {
14501                            row.0 -= 1;
14502                        } else {
14503                            row.0 += 1;
14504                        }
14505
14506                        if let Some(new_selection) = self.selections.build_columnar_selection(
14507                            &display_map,
14508                            row,
14509                            &positions,
14510                            selection.reversed,
14511                            &text_layout_details,
14512                        ) {
14513                            maybe_new_selection = Some(new_selection);
14514                            break;
14515                        }
14516                    }
14517
14518                    if let Some(new_selection) = maybe_new_selection {
14519                        group.stack.push(new_selection.id);
14520                        if above {
14521                            final_selections.push(new_selection);
14522                            final_selections.push(selection);
14523                        } else {
14524                            final_selections.push(selection);
14525                            final_selections.push(new_selection);
14526                        }
14527                    } else {
14528                        final_selections.push(selection);
14529                    }
14530                } else {
14531                    group.stack.pop();
14532                }
14533            } else {
14534                final_selections.push(selection);
14535            }
14536        }
14537
14538        self.change_selections(Default::default(), window, cx, |s| {
14539            s.select(final_selections);
14540        });
14541
14542        let final_selection_ids: HashSet<_> = self
14543            .selections
14544            .all::<Point>(&display_map)
14545            .iter()
14546            .map(|s| s.id)
14547            .collect();
14548        state.groups.retain_mut(|group| {
14549            // selections might get merged above so we remove invalid items from stacks
14550            group.stack.retain(|id| final_selection_ids.contains(id));
14551
14552            // single selection in stack can be treated as initial state
14553            group.stack.len() > 1
14554        });
14555
14556        if !state.groups.is_empty() {
14557            self.add_selections_state = Some(state);
14558        }
14559    }
14560
14561    fn select_match_ranges(
14562        &mut self,
14563        range: Range<usize>,
14564        reversed: bool,
14565        replace_newest: bool,
14566        auto_scroll: Option<Autoscroll>,
14567        window: &mut Window,
14568        cx: &mut Context<Editor>,
14569    ) {
14570        self.unfold_ranges(
14571            std::slice::from_ref(&range),
14572            false,
14573            auto_scroll.is_some(),
14574            cx,
14575        );
14576        let effects = if let Some(scroll) = auto_scroll {
14577            SelectionEffects::scroll(scroll)
14578        } else {
14579            SelectionEffects::no_scroll()
14580        };
14581        self.change_selections(effects, window, cx, |s| {
14582            if replace_newest {
14583                s.delete(s.newest_anchor().id);
14584            }
14585            if reversed {
14586                s.insert_range(range.end..range.start);
14587            } else {
14588                s.insert_range(range);
14589            }
14590        });
14591    }
14592
14593    pub fn select_next_match_internal(
14594        &mut self,
14595        display_map: &DisplaySnapshot,
14596        replace_newest: bool,
14597        autoscroll: Option<Autoscroll>,
14598        window: &mut Window,
14599        cx: &mut Context<Self>,
14600    ) -> Result<()> {
14601        let buffer = display_map.buffer_snapshot();
14602        let mut selections = self.selections.all::<usize>(&display_map);
14603        if let Some(mut select_next_state) = self.select_next_state.take() {
14604            let query = &select_next_state.query;
14605            if !select_next_state.done {
14606                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14607                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14608                let mut next_selected_range = None;
14609
14610                let bytes_after_last_selection =
14611                    buffer.bytes_in_range(last_selection.end..buffer.len());
14612                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14613                let query_matches = query
14614                    .stream_find_iter(bytes_after_last_selection)
14615                    .map(|result| (last_selection.end, result))
14616                    .chain(
14617                        query
14618                            .stream_find_iter(bytes_before_first_selection)
14619                            .map(|result| (0, result)),
14620                    );
14621
14622                for (start_offset, query_match) in query_matches {
14623                    let query_match = query_match.unwrap(); // can only fail due to I/O
14624                    let offset_range =
14625                        start_offset + query_match.start()..start_offset + query_match.end();
14626
14627                    if !select_next_state.wordwise
14628                        || (!buffer.is_inside_word(offset_range.start, None)
14629                            && !buffer.is_inside_word(offset_range.end, None))
14630                    {
14631                        let idx = selections
14632                            .partition_point(|selection| selection.end <= offset_range.start);
14633                        let overlaps = selections
14634                            .get(idx)
14635                            .map_or(false, |selection| selection.start < offset_range.end);
14636
14637                        if !overlaps {
14638                            next_selected_range = Some(offset_range);
14639                            break;
14640                        }
14641                    }
14642                }
14643
14644                if let Some(next_selected_range) = next_selected_range {
14645                    self.select_match_ranges(
14646                        next_selected_range,
14647                        last_selection.reversed,
14648                        replace_newest,
14649                        autoscroll,
14650                        window,
14651                        cx,
14652                    );
14653                } else {
14654                    select_next_state.done = true;
14655                }
14656            }
14657
14658            self.select_next_state = Some(select_next_state);
14659        } else {
14660            let mut only_carets = true;
14661            let mut same_text_selected = true;
14662            let mut selected_text = None;
14663
14664            let mut selections_iter = selections.iter().peekable();
14665            while let Some(selection) = selections_iter.next() {
14666                if selection.start != selection.end {
14667                    only_carets = false;
14668                }
14669
14670                if same_text_selected {
14671                    if selected_text.is_none() {
14672                        selected_text =
14673                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14674                    }
14675
14676                    if let Some(next_selection) = selections_iter.peek() {
14677                        if next_selection.range().len() == selection.range().len() {
14678                            let next_selected_text = buffer
14679                                .text_for_range(next_selection.range())
14680                                .collect::<String>();
14681                            if Some(next_selected_text) != selected_text {
14682                                same_text_selected = false;
14683                                selected_text = None;
14684                            }
14685                        } else {
14686                            same_text_selected = false;
14687                            selected_text = None;
14688                        }
14689                    }
14690                }
14691            }
14692
14693            if only_carets {
14694                for selection in &mut selections {
14695                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14696                    selection.start = word_range.start;
14697                    selection.end = word_range.end;
14698                    selection.goal = SelectionGoal::None;
14699                    selection.reversed = false;
14700                    self.select_match_ranges(
14701                        selection.start..selection.end,
14702                        selection.reversed,
14703                        replace_newest,
14704                        autoscroll,
14705                        window,
14706                        cx,
14707                    );
14708                }
14709
14710                if selections.len() == 1 {
14711                    let selection = selections
14712                        .last()
14713                        .expect("ensured that there's only one selection");
14714                    let query = buffer
14715                        .text_for_range(selection.start..selection.end)
14716                        .collect::<String>();
14717                    let is_empty = query.is_empty();
14718                    let select_state = SelectNextState {
14719                        query: self.build_query(&[query], cx)?,
14720                        wordwise: true,
14721                        done: is_empty,
14722                    };
14723                    self.select_next_state = Some(select_state);
14724                } else {
14725                    self.select_next_state = None;
14726                }
14727            } else if let Some(selected_text) = selected_text {
14728                self.select_next_state = Some(SelectNextState {
14729                    query: self.build_query(&[selected_text], cx)?,
14730                    wordwise: false,
14731                    done: false,
14732                });
14733                self.select_next_match_internal(
14734                    display_map,
14735                    replace_newest,
14736                    autoscroll,
14737                    window,
14738                    cx,
14739                )?;
14740            }
14741        }
14742        Ok(())
14743    }
14744
14745    pub fn select_all_matches(
14746        &mut self,
14747        _action: &SelectAllMatches,
14748        window: &mut Window,
14749        cx: &mut Context<Self>,
14750    ) -> Result<()> {
14751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14752
14753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14754
14755        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14756        let Some(select_next_state) = self.select_next_state.as_mut() else {
14757            return Ok(());
14758        };
14759        if select_next_state.done {
14760            return Ok(());
14761        }
14762
14763        let mut new_selections = Vec::new();
14764
14765        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14766        let buffer = display_map.buffer_snapshot();
14767        let query_matches = select_next_state
14768            .query
14769            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14770
14771        for query_match in query_matches.into_iter() {
14772            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14773            let offset_range = if reversed {
14774                query_match.end()..query_match.start()
14775            } else {
14776                query_match.start()..query_match.end()
14777            };
14778
14779            if !select_next_state.wordwise
14780                || (!buffer.is_inside_word(offset_range.start, None)
14781                    && !buffer.is_inside_word(offset_range.end, None))
14782            {
14783                new_selections.push(offset_range.start..offset_range.end);
14784            }
14785        }
14786
14787        select_next_state.done = true;
14788
14789        if new_selections.is_empty() {
14790            log::error!("bug: new_selections is empty in select_all_matches");
14791            return Ok(());
14792        }
14793
14794        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14795        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14796            selections.select_ranges(new_selections)
14797        });
14798
14799        Ok(())
14800    }
14801
14802    pub fn select_next(
14803        &mut self,
14804        action: &SelectNext,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) -> Result<()> {
14808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14810        self.select_next_match_internal(
14811            &display_map,
14812            action.replace_newest,
14813            Some(Autoscroll::newest()),
14814            window,
14815            cx,
14816        )?;
14817        Ok(())
14818    }
14819
14820    pub fn select_previous(
14821        &mut self,
14822        action: &SelectPrevious,
14823        window: &mut Window,
14824        cx: &mut Context<Self>,
14825    ) -> Result<()> {
14826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14827        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14828        let buffer = display_map.buffer_snapshot();
14829        let mut selections = self.selections.all::<usize>(&display_map);
14830        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14831            let query = &select_prev_state.query;
14832            if !select_prev_state.done {
14833                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14834                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14835                let mut next_selected_range = None;
14836                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14837                let bytes_before_last_selection =
14838                    buffer.reversed_bytes_in_range(0..last_selection.start);
14839                let bytes_after_first_selection =
14840                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14841                let query_matches = query
14842                    .stream_find_iter(bytes_before_last_selection)
14843                    .map(|result| (last_selection.start, result))
14844                    .chain(
14845                        query
14846                            .stream_find_iter(bytes_after_first_selection)
14847                            .map(|result| (buffer.len(), result)),
14848                    );
14849                for (end_offset, query_match) in query_matches {
14850                    let query_match = query_match.unwrap(); // can only fail due to I/O
14851                    let offset_range =
14852                        end_offset - query_match.end()..end_offset - query_match.start();
14853
14854                    if !select_prev_state.wordwise
14855                        || (!buffer.is_inside_word(offset_range.start, None)
14856                            && !buffer.is_inside_word(offset_range.end, None))
14857                    {
14858                        next_selected_range = Some(offset_range);
14859                        break;
14860                    }
14861                }
14862
14863                if let Some(next_selected_range) = next_selected_range {
14864                    self.select_match_ranges(
14865                        next_selected_range,
14866                        last_selection.reversed,
14867                        action.replace_newest,
14868                        Some(Autoscroll::newest()),
14869                        window,
14870                        cx,
14871                    );
14872                } else {
14873                    select_prev_state.done = true;
14874                }
14875            }
14876
14877            self.select_prev_state = Some(select_prev_state);
14878        } else {
14879            let mut only_carets = true;
14880            let mut same_text_selected = true;
14881            let mut selected_text = None;
14882
14883            let mut selections_iter = selections.iter().peekable();
14884            while let Some(selection) = selections_iter.next() {
14885                if selection.start != selection.end {
14886                    only_carets = false;
14887                }
14888
14889                if same_text_selected {
14890                    if selected_text.is_none() {
14891                        selected_text =
14892                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14893                    }
14894
14895                    if let Some(next_selection) = selections_iter.peek() {
14896                        if next_selection.range().len() == selection.range().len() {
14897                            let next_selected_text = buffer
14898                                .text_for_range(next_selection.range())
14899                                .collect::<String>();
14900                            if Some(next_selected_text) != selected_text {
14901                                same_text_selected = false;
14902                                selected_text = None;
14903                            }
14904                        } else {
14905                            same_text_selected = false;
14906                            selected_text = None;
14907                        }
14908                    }
14909                }
14910            }
14911
14912            if only_carets {
14913                for selection in &mut selections {
14914                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14915                    selection.start = word_range.start;
14916                    selection.end = word_range.end;
14917                    selection.goal = SelectionGoal::None;
14918                    selection.reversed = false;
14919                    self.select_match_ranges(
14920                        selection.start..selection.end,
14921                        selection.reversed,
14922                        action.replace_newest,
14923                        Some(Autoscroll::newest()),
14924                        window,
14925                        cx,
14926                    );
14927                }
14928                if selections.len() == 1 {
14929                    let selection = selections
14930                        .last()
14931                        .expect("ensured that there's only one selection");
14932                    let query = buffer
14933                        .text_for_range(selection.start..selection.end)
14934                        .collect::<String>();
14935                    let is_empty = query.is_empty();
14936                    let select_state = SelectNextState {
14937                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14938                        wordwise: true,
14939                        done: is_empty,
14940                    };
14941                    self.select_prev_state = Some(select_state);
14942                } else {
14943                    self.select_prev_state = None;
14944                }
14945            } else if let Some(selected_text) = selected_text {
14946                self.select_prev_state = Some(SelectNextState {
14947                    query: self
14948                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
14949                    wordwise: false,
14950                    done: false,
14951                });
14952                self.select_previous(action, window, cx)?;
14953            }
14954        }
14955        Ok(())
14956    }
14957
14958    /// Builds an `AhoCorasick` automaton from the provided patterns, while
14959    /// setting the case sensitivity based on the global
14960    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
14961    /// editor's settings.
14962    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
14963    where
14964        I: IntoIterator<Item = P>,
14965        P: AsRef<[u8]>,
14966    {
14967        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
14968            || EditorSettings::get_global(cx).search.case_sensitive,
14969            |value| value,
14970        );
14971
14972        let mut builder = AhoCorasickBuilder::new();
14973        builder.ascii_case_insensitive(!case_sensitive);
14974        builder.build(patterns)
14975    }
14976
14977    pub fn find_next_match(
14978        &mut self,
14979        _: &FindNextMatch,
14980        window: &mut Window,
14981        cx: &mut Context<Self>,
14982    ) -> Result<()> {
14983        let selections = self.selections.disjoint_anchors_arc();
14984        match selections.first() {
14985            Some(first) if selections.len() >= 2 => {
14986                self.change_selections(Default::default(), window, cx, |s| {
14987                    s.select_ranges([first.range()]);
14988                });
14989            }
14990            _ => self.select_next(
14991                &SelectNext {
14992                    replace_newest: true,
14993                },
14994                window,
14995                cx,
14996            )?,
14997        }
14998        Ok(())
14999    }
15000
15001    pub fn find_previous_match(
15002        &mut self,
15003        _: &FindPreviousMatch,
15004        window: &mut Window,
15005        cx: &mut Context<Self>,
15006    ) -> Result<()> {
15007        let selections = self.selections.disjoint_anchors_arc();
15008        match selections.last() {
15009            Some(last) if selections.len() >= 2 => {
15010                self.change_selections(Default::default(), window, cx, |s| {
15011                    s.select_ranges([last.range()]);
15012                });
15013            }
15014            _ => self.select_previous(
15015                &SelectPrevious {
15016                    replace_newest: true,
15017                },
15018                window,
15019                cx,
15020            )?,
15021        }
15022        Ok(())
15023    }
15024
15025    pub fn toggle_comments(
15026        &mut self,
15027        action: &ToggleComments,
15028        window: &mut Window,
15029        cx: &mut Context<Self>,
15030    ) {
15031        if self.read_only(cx) {
15032            return;
15033        }
15034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15035        let text_layout_details = &self.text_layout_details(window);
15036        self.transact(window, cx, |this, window, cx| {
15037            let mut selections = this
15038                .selections
15039                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15040            let mut edits = Vec::new();
15041            let mut selection_edit_ranges = Vec::new();
15042            let mut last_toggled_row = None;
15043            let snapshot = this.buffer.read(cx).read(cx);
15044            let empty_str: Arc<str> = Arc::default();
15045            let mut suffixes_inserted = Vec::new();
15046            let ignore_indent = action.ignore_indent;
15047
15048            fn comment_prefix_range(
15049                snapshot: &MultiBufferSnapshot,
15050                row: MultiBufferRow,
15051                comment_prefix: &str,
15052                comment_prefix_whitespace: &str,
15053                ignore_indent: bool,
15054            ) -> Range<Point> {
15055                let indent_size = if ignore_indent {
15056                    0
15057                } else {
15058                    snapshot.indent_size_for_line(row).len
15059                };
15060
15061                let start = Point::new(row.0, indent_size);
15062
15063                let mut line_bytes = snapshot
15064                    .bytes_in_range(start..snapshot.max_point())
15065                    .flatten()
15066                    .copied();
15067
15068                // If this line currently begins with the line comment prefix, then record
15069                // the range containing the prefix.
15070                if line_bytes
15071                    .by_ref()
15072                    .take(comment_prefix.len())
15073                    .eq(comment_prefix.bytes())
15074                {
15075                    // Include any whitespace that matches the comment prefix.
15076                    let matching_whitespace_len = line_bytes
15077                        .zip(comment_prefix_whitespace.bytes())
15078                        .take_while(|(a, b)| a == b)
15079                        .count() as u32;
15080                    let end = Point::new(
15081                        start.row,
15082                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15083                    );
15084                    start..end
15085                } else {
15086                    start..start
15087                }
15088            }
15089
15090            fn comment_suffix_range(
15091                snapshot: &MultiBufferSnapshot,
15092                row: MultiBufferRow,
15093                comment_suffix: &str,
15094                comment_suffix_has_leading_space: bool,
15095            ) -> Range<Point> {
15096                let end = Point::new(row.0, snapshot.line_len(row));
15097                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15098
15099                let mut line_end_bytes = snapshot
15100                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15101                    .flatten()
15102                    .copied();
15103
15104                let leading_space_len = if suffix_start_column > 0
15105                    && line_end_bytes.next() == Some(b' ')
15106                    && comment_suffix_has_leading_space
15107                {
15108                    1
15109                } else {
15110                    0
15111                };
15112
15113                // If this line currently begins with the line comment prefix, then record
15114                // the range containing the prefix.
15115                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15116                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15117                    start..end
15118                } else {
15119                    end..end
15120                }
15121            }
15122
15123            // TODO: Handle selections that cross excerpts
15124            for selection in &mut selections {
15125                let start_column = snapshot
15126                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15127                    .len;
15128                let language = if let Some(language) =
15129                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15130                {
15131                    language
15132                } else {
15133                    continue;
15134                };
15135
15136                selection_edit_ranges.clear();
15137
15138                // If multiple selections contain a given row, avoid processing that
15139                // row more than once.
15140                let mut start_row = MultiBufferRow(selection.start.row);
15141                if last_toggled_row == Some(start_row) {
15142                    start_row = start_row.next_row();
15143                }
15144                let end_row =
15145                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15146                        MultiBufferRow(selection.end.row - 1)
15147                    } else {
15148                        MultiBufferRow(selection.end.row)
15149                    };
15150                last_toggled_row = Some(end_row);
15151
15152                if start_row > end_row {
15153                    continue;
15154                }
15155
15156                // If the language has line comments, toggle those.
15157                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15158
15159                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15160                if ignore_indent {
15161                    full_comment_prefixes = full_comment_prefixes
15162                        .into_iter()
15163                        .map(|s| Arc::from(s.trim_end()))
15164                        .collect();
15165                }
15166
15167                if !full_comment_prefixes.is_empty() {
15168                    let first_prefix = full_comment_prefixes
15169                        .first()
15170                        .expect("prefixes is non-empty");
15171                    let prefix_trimmed_lengths = full_comment_prefixes
15172                        .iter()
15173                        .map(|p| p.trim_end_matches(' ').len())
15174                        .collect::<SmallVec<[usize; 4]>>();
15175
15176                    let mut all_selection_lines_are_comments = true;
15177
15178                    for row in start_row.0..=end_row.0 {
15179                        let row = MultiBufferRow(row);
15180                        if start_row < end_row && snapshot.is_line_blank(row) {
15181                            continue;
15182                        }
15183
15184                        let prefix_range = full_comment_prefixes
15185                            .iter()
15186                            .zip(prefix_trimmed_lengths.iter().copied())
15187                            .map(|(prefix, trimmed_prefix_len)| {
15188                                comment_prefix_range(
15189                                    snapshot.deref(),
15190                                    row,
15191                                    &prefix[..trimmed_prefix_len],
15192                                    &prefix[trimmed_prefix_len..],
15193                                    ignore_indent,
15194                                )
15195                            })
15196                            .max_by_key(|range| range.end.column - range.start.column)
15197                            .expect("prefixes is non-empty");
15198
15199                        if prefix_range.is_empty() {
15200                            all_selection_lines_are_comments = false;
15201                        }
15202
15203                        selection_edit_ranges.push(prefix_range);
15204                    }
15205
15206                    if all_selection_lines_are_comments {
15207                        edits.extend(
15208                            selection_edit_ranges
15209                                .iter()
15210                                .cloned()
15211                                .map(|range| (range, empty_str.clone())),
15212                        );
15213                    } else {
15214                        let min_column = selection_edit_ranges
15215                            .iter()
15216                            .map(|range| range.start.column)
15217                            .min()
15218                            .unwrap_or(0);
15219                        edits.extend(selection_edit_ranges.iter().map(|range| {
15220                            let position = Point::new(range.start.row, min_column);
15221                            (position..position, first_prefix.clone())
15222                        }));
15223                    }
15224                } else if let Some(BlockCommentConfig {
15225                    start: full_comment_prefix,
15226                    end: comment_suffix,
15227                    ..
15228                }) = language.block_comment()
15229                {
15230                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15231                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15232                    let prefix_range = comment_prefix_range(
15233                        snapshot.deref(),
15234                        start_row,
15235                        comment_prefix,
15236                        comment_prefix_whitespace,
15237                        ignore_indent,
15238                    );
15239                    let suffix_range = comment_suffix_range(
15240                        snapshot.deref(),
15241                        end_row,
15242                        comment_suffix.trim_start_matches(' '),
15243                        comment_suffix.starts_with(' '),
15244                    );
15245
15246                    if prefix_range.is_empty() || suffix_range.is_empty() {
15247                        edits.push((
15248                            prefix_range.start..prefix_range.start,
15249                            full_comment_prefix.clone(),
15250                        ));
15251                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15252                        suffixes_inserted.push((end_row, comment_suffix.len()));
15253                    } else {
15254                        edits.push((prefix_range, empty_str.clone()));
15255                        edits.push((suffix_range, empty_str.clone()));
15256                    }
15257                } else {
15258                    continue;
15259                }
15260            }
15261
15262            drop(snapshot);
15263            this.buffer.update(cx, |buffer, cx| {
15264                buffer.edit(edits, None, cx);
15265            });
15266
15267            // Adjust selections so that they end before any comment suffixes that
15268            // were inserted.
15269            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15270            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15271            let snapshot = this.buffer.read(cx).read(cx);
15272            for selection in &mut selections {
15273                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15274                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15275                        Ordering::Less => {
15276                            suffixes_inserted.next();
15277                            continue;
15278                        }
15279                        Ordering::Greater => break,
15280                        Ordering::Equal => {
15281                            if selection.end.column == snapshot.line_len(row) {
15282                                if selection.is_empty() {
15283                                    selection.start.column -= suffix_len as u32;
15284                                }
15285                                selection.end.column -= suffix_len as u32;
15286                            }
15287                            break;
15288                        }
15289                    }
15290                }
15291            }
15292
15293            drop(snapshot);
15294            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15295
15296            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15297            let selections_on_single_row = selections.windows(2).all(|selections| {
15298                selections[0].start.row == selections[1].start.row
15299                    && selections[0].end.row == selections[1].end.row
15300                    && selections[0].start.row == selections[0].end.row
15301            });
15302            let selections_selecting = selections
15303                .iter()
15304                .any(|selection| selection.start != selection.end);
15305            let advance_downwards = action.advance_downwards
15306                && selections_on_single_row
15307                && !selections_selecting
15308                && !matches!(this.mode, EditorMode::SingleLine);
15309
15310            if advance_downwards {
15311                let snapshot = this.buffer.read(cx).snapshot(cx);
15312
15313                this.change_selections(Default::default(), window, cx, |s| {
15314                    s.move_cursors_with(|display_snapshot, display_point, _| {
15315                        let mut point = display_point.to_point(display_snapshot);
15316                        point.row += 1;
15317                        point = snapshot.clip_point(point, Bias::Left);
15318                        let display_point = point.to_display_point(display_snapshot);
15319                        let goal = SelectionGoal::HorizontalPosition(
15320                            display_snapshot
15321                                .x_for_display_point(display_point, text_layout_details)
15322                                .into(),
15323                        );
15324                        (display_point, goal)
15325                    })
15326                });
15327            }
15328        });
15329    }
15330
15331    pub fn select_enclosing_symbol(
15332        &mut self,
15333        _: &SelectEnclosingSymbol,
15334        window: &mut Window,
15335        cx: &mut Context<Self>,
15336    ) {
15337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15338
15339        let buffer = self.buffer.read(cx).snapshot(cx);
15340        let old_selections = self
15341            .selections
15342            .all::<usize>(&self.display_snapshot(cx))
15343            .into_boxed_slice();
15344
15345        fn update_selection(
15346            selection: &Selection<usize>,
15347            buffer_snap: &MultiBufferSnapshot,
15348        ) -> Option<Selection<usize>> {
15349            let cursor = selection.head();
15350            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15351            for symbol in symbols.iter().rev() {
15352                let start = symbol.range.start.to_offset(buffer_snap);
15353                let end = symbol.range.end.to_offset(buffer_snap);
15354                let new_range = start..end;
15355                if start < selection.start || end > selection.end {
15356                    return Some(Selection {
15357                        id: selection.id,
15358                        start: new_range.start,
15359                        end: new_range.end,
15360                        goal: SelectionGoal::None,
15361                        reversed: selection.reversed,
15362                    });
15363                }
15364            }
15365            None
15366        }
15367
15368        let mut selected_larger_symbol = false;
15369        let new_selections = old_selections
15370            .iter()
15371            .map(|selection| match update_selection(selection, &buffer) {
15372                Some(new_selection) => {
15373                    if new_selection.range() != selection.range() {
15374                        selected_larger_symbol = true;
15375                    }
15376                    new_selection
15377                }
15378                None => selection.clone(),
15379            })
15380            .collect::<Vec<_>>();
15381
15382        if selected_larger_symbol {
15383            self.change_selections(Default::default(), window, cx, |s| {
15384                s.select(new_selections);
15385            });
15386        }
15387    }
15388
15389    pub fn select_larger_syntax_node(
15390        &mut self,
15391        _: &SelectLargerSyntaxNode,
15392        window: &mut Window,
15393        cx: &mut Context<Self>,
15394    ) {
15395        let Some(visible_row_count) = self.visible_row_count() else {
15396            return;
15397        };
15398        let old_selections: Box<[_]> = self
15399            .selections
15400            .all::<usize>(&self.display_snapshot(cx))
15401            .into();
15402        if old_selections.is_empty() {
15403            return;
15404        }
15405
15406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15407
15408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15409        let buffer = self.buffer.read(cx).snapshot(cx);
15410
15411        let mut selected_larger_node = false;
15412        let mut new_selections = old_selections
15413            .iter()
15414            .map(|selection| {
15415                let old_range = selection.start..selection.end;
15416
15417                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15418                    // manually select word at selection
15419                    if ["string_content", "inline"].contains(&node.kind()) {
15420                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15421                        // ignore if word is already selected
15422                        if !word_range.is_empty() && old_range != word_range {
15423                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15424                            // only select word if start and end point belongs to same word
15425                            if word_range == last_word_range {
15426                                selected_larger_node = true;
15427                                return Selection {
15428                                    id: selection.id,
15429                                    start: word_range.start,
15430                                    end: word_range.end,
15431                                    goal: SelectionGoal::None,
15432                                    reversed: selection.reversed,
15433                                };
15434                            }
15435                        }
15436                    }
15437                }
15438
15439                let mut new_range = old_range.clone();
15440                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15441                    new_range = range;
15442                    if !node.is_named() {
15443                        continue;
15444                    }
15445                    if !display_map.intersects_fold(new_range.start)
15446                        && !display_map.intersects_fold(new_range.end)
15447                    {
15448                        break;
15449                    }
15450                }
15451
15452                selected_larger_node |= new_range != old_range;
15453                Selection {
15454                    id: selection.id,
15455                    start: new_range.start,
15456                    end: new_range.end,
15457                    goal: SelectionGoal::None,
15458                    reversed: selection.reversed,
15459                }
15460            })
15461            .collect::<Vec<_>>();
15462
15463        if !selected_larger_node {
15464            return; // don't put this call in the history
15465        }
15466
15467        // scroll based on transformation done to the last selection created by the user
15468        let (last_old, last_new) = old_selections
15469            .last()
15470            .zip(new_selections.last().cloned())
15471            .expect("old_selections isn't empty");
15472
15473        // revert selection
15474        let is_selection_reversed = {
15475            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15476            new_selections.last_mut().expect("checked above").reversed =
15477                should_newest_selection_be_reversed;
15478            should_newest_selection_be_reversed
15479        };
15480
15481        if selected_larger_node {
15482            self.select_syntax_node_history.disable_clearing = true;
15483            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15484                s.select(new_selections.clone());
15485            });
15486            self.select_syntax_node_history.disable_clearing = false;
15487        }
15488
15489        let start_row = last_new.start.to_display_point(&display_map).row().0;
15490        let end_row = last_new.end.to_display_point(&display_map).row().0;
15491        let selection_height = end_row - start_row + 1;
15492        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15493
15494        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15495        let scroll_behavior = if fits_on_the_screen {
15496            self.request_autoscroll(Autoscroll::fit(), cx);
15497            SelectSyntaxNodeScrollBehavior::FitSelection
15498        } else if is_selection_reversed {
15499            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15500            SelectSyntaxNodeScrollBehavior::CursorTop
15501        } else {
15502            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15503            SelectSyntaxNodeScrollBehavior::CursorBottom
15504        };
15505
15506        self.select_syntax_node_history.push((
15507            old_selections,
15508            scroll_behavior,
15509            is_selection_reversed,
15510        ));
15511    }
15512
15513    pub fn select_smaller_syntax_node(
15514        &mut self,
15515        _: &SelectSmallerSyntaxNode,
15516        window: &mut Window,
15517        cx: &mut Context<Self>,
15518    ) {
15519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15520
15521        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15522            self.select_syntax_node_history.pop()
15523        {
15524            if let Some(selection) = selections.last_mut() {
15525                selection.reversed = is_selection_reversed;
15526            }
15527
15528            self.select_syntax_node_history.disable_clearing = true;
15529            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15530                s.select(selections.to_vec());
15531            });
15532            self.select_syntax_node_history.disable_clearing = false;
15533
15534            match scroll_behavior {
15535                SelectSyntaxNodeScrollBehavior::CursorTop => {
15536                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15537                }
15538                SelectSyntaxNodeScrollBehavior::FitSelection => {
15539                    self.request_autoscroll(Autoscroll::fit(), cx);
15540                }
15541                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15542                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15543                }
15544            }
15545        }
15546    }
15547
15548    pub fn unwrap_syntax_node(
15549        &mut self,
15550        _: &UnwrapSyntaxNode,
15551        window: &mut Window,
15552        cx: &mut Context<Self>,
15553    ) {
15554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15555
15556        let buffer = self.buffer.read(cx).snapshot(cx);
15557        let selections = self
15558            .selections
15559            .all::<usize>(&self.display_snapshot(cx))
15560            .into_iter()
15561            // subtracting the offset requires sorting
15562            .sorted_by_key(|i| i.start);
15563
15564        let full_edits = selections
15565            .into_iter()
15566            .filter_map(|selection| {
15567                let child = if selection.is_empty()
15568                    && let Some((_, ancestor_range)) =
15569                        buffer.syntax_ancestor(selection.start..selection.end)
15570                {
15571                    ancestor_range
15572                } else {
15573                    selection.range()
15574                };
15575
15576                let mut parent = child.clone();
15577                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15578                    parent = ancestor_range;
15579                    if parent.start < child.start || parent.end > child.end {
15580                        break;
15581                    }
15582                }
15583
15584                if parent == child {
15585                    return None;
15586                }
15587                let text = buffer.text_for_range(child).collect::<String>();
15588                Some((selection.id, parent, text))
15589            })
15590            .collect::<Vec<_>>();
15591        if full_edits.is_empty() {
15592            return;
15593        }
15594
15595        self.transact(window, cx, |this, window, cx| {
15596            this.buffer.update(cx, |buffer, cx| {
15597                buffer.edit(
15598                    full_edits
15599                        .iter()
15600                        .map(|(_, p, t)| (p.clone(), t.clone()))
15601                        .collect::<Vec<_>>(),
15602                    None,
15603                    cx,
15604                );
15605            });
15606            this.change_selections(Default::default(), window, cx, |s| {
15607                let mut offset = 0;
15608                let mut selections = vec![];
15609                for (id, parent, text) in full_edits {
15610                    let start = parent.start - offset;
15611                    offset += parent.len() - text.len();
15612                    selections.push(Selection {
15613                        id,
15614                        start,
15615                        end: start + text.len(),
15616                        reversed: false,
15617                        goal: Default::default(),
15618                    });
15619                }
15620                s.select(selections);
15621            });
15622        });
15623    }
15624
15625    pub fn select_next_syntax_node(
15626        &mut self,
15627        _: &SelectNextSyntaxNode,
15628        window: &mut Window,
15629        cx: &mut Context<Self>,
15630    ) {
15631        let old_selections: Box<[_]> = self
15632            .selections
15633            .all::<usize>(&self.display_snapshot(cx))
15634            .into();
15635        if old_selections.is_empty() {
15636            return;
15637        }
15638
15639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15640
15641        let buffer = self.buffer.read(cx).snapshot(cx);
15642        let mut selected_sibling = false;
15643
15644        let new_selections = old_selections
15645            .iter()
15646            .map(|selection| {
15647                let old_range = selection.start..selection.end;
15648
15649                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15650                    let new_range = node.byte_range();
15651                    selected_sibling = true;
15652                    Selection {
15653                        id: selection.id,
15654                        start: new_range.start,
15655                        end: new_range.end,
15656                        goal: SelectionGoal::None,
15657                        reversed: selection.reversed,
15658                    }
15659                } else {
15660                    selection.clone()
15661                }
15662            })
15663            .collect::<Vec<_>>();
15664
15665        if selected_sibling {
15666            self.change_selections(
15667                SelectionEffects::scroll(Autoscroll::fit()),
15668                window,
15669                cx,
15670                |s| {
15671                    s.select(new_selections);
15672                },
15673            );
15674        }
15675    }
15676
15677    pub fn select_prev_syntax_node(
15678        &mut self,
15679        _: &SelectPreviousSyntaxNode,
15680        window: &mut Window,
15681        cx: &mut Context<Self>,
15682    ) {
15683        let old_selections: Box<[_]> = self
15684            .selections
15685            .all::<usize>(&self.display_snapshot(cx))
15686            .into();
15687        if old_selections.is_empty() {
15688            return;
15689        }
15690
15691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15692
15693        let buffer = self.buffer.read(cx).snapshot(cx);
15694        let mut selected_sibling = false;
15695
15696        let new_selections = old_selections
15697            .iter()
15698            .map(|selection| {
15699                let old_range = selection.start..selection.end;
15700
15701                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15702                    let new_range = node.byte_range();
15703                    selected_sibling = true;
15704                    Selection {
15705                        id: selection.id,
15706                        start: new_range.start,
15707                        end: new_range.end,
15708                        goal: SelectionGoal::None,
15709                        reversed: selection.reversed,
15710                    }
15711                } else {
15712                    selection.clone()
15713                }
15714            })
15715            .collect::<Vec<_>>();
15716
15717        if selected_sibling {
15718            self.change_selections(
15719                SelectionEffects::scroll(Autoscroll::fit()),
15720                window,
15721                cx,
15722                |s| {
15723                    s.select(new_selections);
15724                },
15725            );
15726        }
15727    }
15728
15729    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15730        if !EditorSettings::get_global(cx).gutter.runnables {
15731            self.clear_tasks();
15732            return Task::ready(());
15733        }
15734        let project = self.project().map(Entity::downgrade);
15735        let task_sources = self.lsp_task_sources(cx);
15736        let multi_buffer = self.buffer.downgrade();
15737        cx.spawn_in(window, async move |editor, cx| {
15738            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15739            let Some(project) = project.and_then(|p| p.upgrade()) else {
15740                return;
15741            };
15742            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15743                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15744            }) else {
15745                return;
15746            };
15747
15748            let hide_runnables = project
15749                .update(cx, |project, _| project.is_via_collab())
15750                .unwrap_or(true);
15751            if hide_runnables {
15752                return;
15753            }
15754            let new_rows =
15755                cx.background_spawn({
15756                    let snapshot = display_snapshot.clone();
15757                    async move {
15758                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15759                    }
15760                })
15761                    .await;
15762            let Ok(lsp_tasks) =
15763                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15764            else {
15765                return;
15766            };
15767            let lsp_tasks = lsp_tasks.await;
15768
15769            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15770                lsp_tasks
15771                    .into_iter()
15772                    .flat_map(|(kind, tasks)| {
15773                        tasks.into_iter().filter_map(move |(location, task)| {
15774                            Some((kind.clone(), location?, task))
15775                        })
15776                    })
15777                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15778                        let buffer = location.target.buffer;
15779                        let buffer_snapshot = buffer.read(cx).snapshot();
15780                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15781                            |(excerpt_id, snapshot, _)| {
15782                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15783                                    display_snapshot
15784                                        .buffer_snapshot()
15785                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15786                                } else {
15787                                    None
15788                                }
15789                            },
15790                        );
15791                        if let Some(offset) = offset {
15792                            let task_buffer_range =
15793                                location.target.range.to_point(&buffer_snapshot);
15794                            let context_buffer_range =
15795                                task_buffer_range.to_offset(&buffer_snapshot);
15796                            let context_range = BufferOffset(context_buffer_range.start)
15797                                ..BufferOffset(context_buffer_range.end);
15798
15799                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15800                                .or_insert_with(|| RunnableTasks {
15801                                    templates: Vec::new(),
15802                                    offset,
15803                                    column: task_buffer_range.start.column,
15804                                    extra_variables: HashMap::default(),
15805                                    context_range,
15806                                })
15807                                .templates
15808                                .push((kind, task.original_task().clone()));
15809                        }
15810
15811                        acc
15812                    })
15813            }) else {
15814                return;
15815            };
15816
15817            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15818                buffer.language_settings(cx).tasks.prefer_lsp
15819            }) else {
15820                return;
15821            };
15822
15823            let rows = Self::runnable_rows(
15824                project,
15825                display_snapshot,
15826                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15827                new_rows,
15828                cx.clone(),
15829            )
15830            .await;
15831            editor
15832                .update(cx, |editor, _| {
15833                    editor.clear_tasks();
15834                    for (key, mut value) in rows {
15835                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15836                            value.templates.extend(lsp_tasks.templates);
15837                        }
15838
15839                        editor.insert_tasks(key, value);
15840                    }
15841                    for (key, value) in lsp_tasks_by_rows {
15842                        editor.insert_tasks(key, value);
15843                    }
15844                })
15845                .ok();
15846        })
15847    }
15848    fn fetch_runnable_ranges(
15849        snapshot: &DisplaySnapshot,
15850        range: Range<Anchor>,
15851    ) -> Vec<language::RunnableRange> {
15852        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15853    }
15854
15855    fn runnable_rows(
15856        project: Entity<Project>,
15857        snapshot: DisplaySnapshot,
15858        prefer_lsp: bool,
15859        runnable_ranges: Vec<RunnableRange>,
15860        cx: AsyncWindowContext,
15861    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15862        cx.spawn(async move |cx| {
15863            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15864            for mut runnable in runnable_ranges {
15865                let Some(tasks) = cx
15866                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15867                    .ok()
15868                else {
15869                    continue;
15870                };
15871                let mut tasks = tasks.await;
15872
15873                if prefer_lsp {
15874                    tasks.retain(|(task_kind, _)| {
15875                        !matches!(task_kind, TaskSourceKind::Language { .. })
15876                    });
15877                }
15878                if tasks.is_empty() {
15879                    continue;
15880                }
15881
15882                let point = runnable
15883                    .run_range
15884                    .start
15885                    .to_point(&snapshot.buffer_snapshot());
15886                let Some(row) = snapshot
15887                    .buffer_snapshot()
15888                    .buffer_line_for_row(MultiBufferRow(point.row))
15889                    .map(|(_, range)| range.start.row)
15890                else {
15891                    continue;
15892                };
15893
15894                let context_range =
15895                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15896                runnable_rows.push((
15897                    (runnable.buffer_id, row),
15898                    RunnableTasks {
15899                        templates: tasks,
15900                        offset: snapshot
15901                            .buffer_snapshot()
15902                            .anchor_before(runnable.run_range.start),
15903                        context_range,
15904                        column: point.column,
15905                        extra_variables: runnable.extra_captures,
15906                    },
15907                ));
15908            }
15909            runnable_rows
15910        })
15911    }
15912
15913    fn templates_with_tags(
15914        project: &Entity<Project>,
15915        runnable: &mut Runnable,
15916        cx: &mut App,
15917    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15918        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15919            let (worktree_id, file) = project
15920                .buffer_for_id(runnable.buffer, cx)
15921                .and_then(|buffer| buffer.read(cx).file())
15922                .map(|file| (file.worktree_id(cx), file.clone()))
15923                .unzip();
15924
15925            (
15926                project.task_store().read(cx).task_inventory().cloned(),
15927                worktree_id,
15928                file,
15929            )
15930        });
15931
15932        let tags = mem::take(&mut runnable.tags);
15933        let language = runnable.language.clone();
15934        cx.spawn(async move |cx| {
15935            let mut templates_with_tags = Vec::new();
15936            if let Some(inventory) = inventory {
15937                for RunnableTag(tag) in tags {
15938                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15939                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15940                    }) else {
15941                        return templates_with_tags;
15942                    };
15943                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15944                        move |(_, template)| {
15945                            template.tags.iter().any(|source_tag| source_tag == &tag)
15946                        },
15947                    ));
15948                }
15949            }
15950            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15951
15952            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15953                // Strongest source wins; if we have worktree tag binding, prefer that to
15954                // global and language bindings;
15955                // if we have a global binding, prefer that to language binding.
15956                let first_mismatch = templates_with_tags
15957                    .iter()
15958                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15959                if let Some(index) = first_mismatch {
15960                    templates_with_tags.truncate(index);
15961                }
15962            }
15963
15964            templates_with_tags
15965        })
15966    }
15967
15968    pub fn move_to_enclosing_bracket(
15969        &mut self,
15970        _: &MoveToEnclosingBracket,
15971        window: &mut Window,
15972        cx: &mut Context<Self>,
15973    ) {
15974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15975        self.change_selections(Default::default(), window, cx, |s| {
15976            s.move_offsets_with(|snapshot, selection| {
15977                let Some(enclosing_bracket_ranges) =
15978                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15979                else {
15980                    return;
15981                };
15982
15983                let mut best_length = usize::MAX;
15984                let mut best_inside = false;
15985                let mut best_in_bracket_range = false;
15986                let mut best_destination = None;
15987                for (open, close) in enclosing_bracket_ranges {
15988                    let close = close.to_inclusive();
15989                    let length = close.end() - open.start;
15990                    let inside = selection.start >= open.end && selection.end <= *close.start();
15991                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15992                        || close.contains(&selection.head());
15993
15994                    // If best is next to a bracket and current isn't, skip
15995                    if !in_bracket_range && best_in_bracket_range {
15996                        continue;
15997                    }
15998
15999                    // Prefer smaller lengths unless best is inside and current isn't
16000                    if length > best_length && (best_inside || !inside) {
16001                        continue;
16002                    }
16003
16004                    best_length = length;
16005                    best_inside = inside;
16006                    best_in_bracket_range = in_bracket_range;
16007                    best_destination = Some(
16008                        if close.contains(&selection.start) && close.contains(&selection.end) {
16009                            if inside { open.end } else { open.start }
16010                        } else if inside {
16011                            *close.start()
16012                        } else {
16013                            *close.end()
16014                        },
16015                    );
16016                }
16017
16018                if let Some(destination) = best_destination {
16019                    selection.collapse_to(destination, SelectionGoal::None);
16020                }
16021            })
16022        });
16023    }
16024
16025    pub fn undo_selection(
16026        &mut self,
16027        _: &UndoSelection,
16028        window: &mut Window,
16029        cx: &mut Context<Self>,
16030    ) {
16031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16032        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16033            self.selection_history.mode = SelectionHistoryMode::Undoing;
16034            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16035                this.end_selection(window, cx);
16036                this.change_selections(
16037                    SelectionEffects::scroll(Autoscroll::newest()),
16038                    window,
16039                    cx,
16040                    |s| s.select_anchors(entry.selections.to_vec()),
16041                );
16042            });
16043            self.selection_history.mode = SelectionHistoryMode::Normal;
16044
16045            self.select_next_state = entry.select_next_state;
16046            self.select_prev_state = entry.select_prev_state;
16047            self.add_selections_state = entry.add_selections_state;
16048        }
16049    }
16050
16051    pub fn redo_selection(
16052        &mut self,
16053        _: &RedoSelection,
16054        window: &mut Window,
16055        cx: &mut Context<Self>,
16056    ) {
16057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16058        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16059            self.selection_history.mode = SelectionHistoryMode::Redoing;
16060            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16061                this.end_selection(window, cx);
16062                this.change_selections(
16063                    SelectionEffects::scroll(Autoscroll::newest()),
16064                    window,
16065                    cx,
16066                    |s| s.select_anchors(entry.selections.to_vec()),
16067                );
16068            });
16069            self.selection_history.mode = SelectionHistoryMode::Normal;
16070
16071            self.select_next_state = entry.select_next_state;
16072            self.select_prev_state = entry.select_prev_state;
16073            self.add_selections_state = entry.add_selections_state;
16074        }
16075    }
16076
16077    pub fn expand_excerpts(
16078        &mut self,
16079        action: &ExpandExcerpts,
16080        _: &mut Window,
16081        cx: &mut Context<Self>,
16082    ) {
16083        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16084    }
16085
16086    pub fn expand_excerpts_down(
16087        &mut self,
16088        action: &ExpandExcerptsDown,
16089        _: &mut Window,
16090        cx: &mut Context<Self>,
16091    ) {
16092        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16093    }
16094
16095    pub fn expand_excerpts_up(
16096        &mut self,
16097        action: &ExpandExcerptsUp,
16098        _: &mut Window,
16099        cx: &mut Context<Self>,
16100    ) {
16101        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16102    }
16103
16104    pub fn expand_excerpts_for_direction(
16105        &mut self,
16106        lines: u32,
16107        direction: ExpandExcerptDirection,
16108
16109        cx: &mut Context<Self>,
16110    ) {
16111        let selections = self.selections.disjoint_anchors_arc();
16112
16113        let lines = if lines == 0 {
16114            EditorSettings::get_global(cx).expand_excerpt_lines
16115        } else {
16116            lines
16117        };
16118
16119        self.buffer.update(cx, |buffer, cx| {
16120            let snapshot = buffer.snapshot(cx);
16121            let mut excerpt_ids = selections
16122                .iter()
16123                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16124                .collect::<Vec<_>>();
16125            excerpt_ids.sort();
16126            excerpt_ids.dedup();
16127            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16128        })
16129    }
16130
16131    pub fn expand_excerpt(
16132        &mut self,
16133        excerpt: ExcerptId,
16134        direction: ExpandExcerptDirection,
16135        window: &mut Window,
16136        cx: &mut Context<Self>,
16137    ) {
16138        let current_scroll_position = self.scroll_position(cx);
16139        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16140        let mut scroll = None;
16141
16142        if direction == ExpandExcerptDirection::Down {
16143            let multi_buffer = self.buffer.read(cx);
16144            let snapshot = multi_buffer.snapshot(cx);
16145            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16146                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16147                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16148            {
16149                let buffer_snapshot = buffer.read(cx).snapshot();
16150                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16151                let last_row = buffer_snapshot.max_point().row;
16152                let lines_below = last_row.saturating_sub(excerpt_end_row);
16153                if lines_below >= lines_to_expand {
16154                    scroll = Some(
16155                        current_scroll_position
16156                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16157                    );
16158                }
16159            }
16160        }
16161        if direction == ExpandExcerptDirection::Up
16162            && self
16163                .buffer
16164                .read(cx)
16165                .snapshot(cx)
16166                .excerpt_before(excerpt)
16167                .is_none()
16168        {
16169            scroll = Some(current_scroll_position);
16170        }
16171
16172        self.buffer.update(cx, |buffer, cx| {
16173            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16174        });
16175
16176        if let Some(new_scroll_position) = scroll {
16177            self.set_scroll_position(new_scroll_position, window, cx);
16178        }
16179    }
16180
16181    pub fn go_to_singleton_buffer_point(
16182        &mut self,
16183        point: Point,
16184        window: &mut Window,
16185        cx: &mut Context<Self>,
16186    ) {
16187        self.go_to_singleton_buffer_range(point..point, window, cx);
16188    }
16189
16190    pub fn go_to_singleton_buffer_range(
16191        &mut self,
16192        range: Range<Point>,
16193        window: &mut Window,
16194        cx: &mut Context<Self>,
16195    ) {
16196        let multibuffer = self.buffer().read(cx);
16197        let Some(buffer) = multibuffer.as_singleton() else {
16198            return;
16199        };
16200        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16201            return;
16202        };
16203        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16204            return;
16205        };
16206        self.change_selections(
16207            SelectionEffects::default().nav_history(true),
16208            window,
16209            cx,
16210            |s| s.select_anchor_ranges([start..end]),
16211        );
16212    }
16213
16214    pub fn go_to_diagnostic(
16215        &mut self,
16216        action: &GoToDiagnostic,
16217        window: &mut Window,
16218        cx: &mut Context<Self>,
16219    ) {
16220        if !self.diagnostics_enabled() {
16221            return;
16222        }
16223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16224        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16225    }
16226
16227    pub fn go_to_prev_diagnostic(
16228        &mut self,
16229        action: &GoToPreviousDiagnostic,
16230        window: &mut Window,
16231        cx: &mut Context<Self>,
16232    ) {
16233        if !self.diagnostics_enabled() {
16234            return;
16235        }
16236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16237        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16238    }
16239
16240    pub fn go_to_diagnostic_impl(
16241        &mut self,
16242        direction: Direction,
16243        severity: GoToDiagnosticSeverityFilter,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        let buffer = self.buffer.read(cx).snapshot(cx);
16248        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16249
16250        let mut active_group_id = None;
16251        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16252            && active_group.active_range.start.to_offset(&buffer) == selection.start
16253        {
16254            active_group_id = Some(active_group.group_id);
16255        }
16256
16257        fn filtered<'a>(
16258            severity: GoToDiagnosticSeverityFilter,
16259            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16260        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16261            diagnostics
16262                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16263                .filter(|entry| entry.range.start != entry.range.end)
16264                .filter(|entry| !entry.diagnostic.is_unnecessary)
16265        }
16266
16267        let before = filtered(
16268            severity,
16269            buffer
16270                .diagnostics_in_range(0..selection.start)
16271                .filter(|entry| entry.range.start <= selection.start),
16272        );
16273        let after = filtered(
16274            severity,
16275            buffer
16276                .diagnostics_in_range(selection.start..buffer.len())
16277                .filter(|entry| entry.range.start >= selection.start),
16278        );
16279
16280        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16281        if direction == Direction::Prev {
16282            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16283            {
16284                for diagnostic in prev_diagnostics.into_iter().rev() {
16285                    if diagnostic.range.start != selection.start
16286                        || active_group_id
16287                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16288                    {
16289                        found = Some(diagnostic);
16290                        break 'outer;
16291                    }
16292                }
16293            }
16294        } else {
16295            for diagnostic in after.chain(before) {
16296                if diagnostic.range.start != selection.start
16297                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16298                {
16299                    found = Some(diagnostic);
16300                    break;
16301                }
16302            }
16303        }
16304        let Some(next_diagnostic) = found else {
16305            return;
16306        };
16307
16308        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16309        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16310            return;
16311        };
16312        let snapshot = self.snapshot(window, cx);
16313        if snapshot.intersects_fold(next_diagnostic.range.start) {
16314            self.unfold_ranges(
16315                std::slice::from_ref(&next_diagnostic.range),
16316                true,
16317                false,
16318                cx,
16319            );
16320        }
16321        self.change_selections(Default::default(), window, cx, |s| {
16322            s.select_ranges(vec![
16323                next_diagnostic.range.start..next_diagnostic.range.start,
16324            ])
16325        });
16326        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16327        self.refresh_edit_prediction(false, true, window, cx);
16328    }
16329
16330    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16332        let snapshot = self.snapshot(window, cx);
16333        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16334        self.go_to_hunk_before_or_after_position(
16335            &snapshot,
16336            selection.head(),
16337            Direction::Next,
16338            window,
16339            cx,
16340        );
16341    }
16342
16343    pub fn go_to_hunk_before_or_after_position(
16344        &mut self,
16345        snapshot: &EditorSnapshot,
16346        position: Point,
16347        direction: Direction,
16348        window: &mut Window,
16349        cx: &mut Context<Editor>,
16350    ) {
16351        let row = if direction == Direction::Next {
16352            self.hunk_after_position(snapshot, position)
16353                .map(|hunk| hunk.row_range.start)
16354        } else {
16355            self.hunk_before_position(snapshot, position)
16356        };
16357
16358        if let Some(row) = row {
16359            let destination = Point::new(row.0, 0);
16360            let autoscroll = Autoscroll::center();
16361
16362            self.unfold_ranges(&[destination..destination], false, false, cx);
16363            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16364                s.select_ranges([destination..destination]);
16365            });
16366        }
16367    }
16368
16369    fn hunk_after_position(
16370        &mut self,
16371        snapshot: &EditorSnapshot,
16372        position: Point,
16373    ) -> Option<MultiBufferDiffHunk> {
16374        snapshot
16375            .buffer_snapshot()
16376            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16377            .find(|hunk| hunk.row_range.start.0 > position.row)
16378            .or_else(|| {
16379                snapshot
16380                    .buffer_snapshot()
16381                    .diff_hunks_in_range(Point::zero()..position)
16382                    .find(|hunk| hunk.row_range.end.0 < position.row)
16383            })
16384    }
16385
16386    fn go_to_prev_hunk(
16387        &mut self,
16388        _: &GoToPreviousHunk,
16389        window: &mut Window,
16390        cx: &mut Context<Self>,
16391    ) {
16392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16393        let snapshot = self.snapshot(window, cx);
16394        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16395        self.go_to_hunk_before_or_after_position(
16396            &snapshot,
16397            selection.head(),
16398            Direction::Prev,
16399            window,
16400            cx,
16401        );
16402    }
16403
16404    fn hunk_before_position(
16405        &mut self,
16406        snapshot: &EditorSnapshot,
16407        position: Point,
16408    ) -> Option<MultiBufferRow> {
16409        snapshot
16410            .buffer_snapshot()
16411            .diff_hunk_before(position)
16412            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16413    }
16414
16415    fn go_to_next_change(
16416        &mut self,
16417        _: &GoToNextChange,
16418        window: &mut Window,
16419        cx: &mut Context<Self>,
16420    ) {
16421        if let Some(selections) = self
16422            .change_list
16423            .next_change(1, Direction::Next)
16424            .map(|s| s.to_vec())
16425        {
16426            self.change_selections(Default::default(), window, cx, |s| {
16427                let map = s.display_snapshot();
16428                s.select_display_ranges(selections.iter().map(|a| {
16429                    let point = a.to_display_point(&map);
16430                    point..point
16431                }))
16432            })
16433        }
16434    }
16435
16436    fn go_to_previous_change(
16437        &mut self,
16438        _: &GoToPreviousChange,
16439        window: &mut Window,
16440        cx: &mut Context<Self>,
16441    ) {
16442        if let Some(selections) = self
16443            .change_list
16444            .next_change(1, Direction::Prev)
16445            .map(|s| s.to_vec())
16446        {
16447            self.change_selections(Default::default(), window, cx, |s| {
16448                let map = s.display_snapshot();
16449                s.select_display_ranges(selections.iter().map(|a| {
16450                    let point = a.to_display_point(&map);
16451                    point..point
16452                }))
16453            })
16454        }
16455    }
16456
16457    pub fn go_to_next_document_highlight(
16458        &mut self,
16459        _: &GoToNextDocumentHighlight,
16460        window: &mut Window,
16461        cx: &mut Context<Self>,
16462    ) {
16463        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16464    }
16465
16466    pub fn go_to_prev_document_highlight(
16467        &mut self,
16468        _: &GoToPreviousDocumentHighlight,
16469        window: &mut Window,
16470        cx: &mut Context<Self>,
16471    ) {
16472        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16473    }
16474
16475    pub fn go_to_document_highlight_before_or_after_position(
16476        &mut self,
16477        direction: Direction,
16478        window: &mut Window,
16479        cx: &mut Context<Editor>,
16480    ) {
16481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16482        let snapshot = self.snapshot(window, cx);
16483        let buffer = &snapshot.buffer_snapshot();
16484        let position = self
16485            .selections
16486            .newest::<Point>(&snapshot.display_snapshot)
16487            .head();
16488        let anchor_position = buffer.anchor_after(position);
16489
16490        // Get all document highlights (both read and write)
16491        let mut all_highlights = Vec::new();
16492
16493        if let Some((_, read_highlights)) = self
16494            .background_highlights
16495            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16496        {
16497            all_highlights.extend(read_highlights.iter());
16498        }
16499
16500        if let Some((_, write_highlights)) = self
16501            .background_highlights
16502            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16503        {
16504            all_highlights.extend(write_highlights.iter());
16505        }
16506
16507        if all_highlights.is_empty() {
16508            return;
16509        }
16510
16511        // Sort highlights by position
16512        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16513
16514        let target_highlight = match direction {
16515            Direction::Next => {
16516                // Find the first highlight after the current position
16517                all_highlights
16518                    .iter()
16519                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16520            }
16521            Direction::Prev => {
16522                // Find the last highlight before the current position
16523                all_highlights
16524                    .iter()
16525                    .rev()
16526                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16527            }
16528        };
16529
16530        if let Some(highlight) = target_highlight {
16531            let destination = highlight.start.to_point(buffer);
16532            let autoscroll = Autoscroll::center();
16533
16534            self.unfold_ranges(&[destination..destination], false, false, cx);
16535            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16536                s.select_ranges([destination..destination]);
16537            });
16538        }
16539    }
16540
16541    fn go_to_line<T: 'static>(
16542        &mut self,
16543        position: Anchor,
16544        highlight_color: Option<Hsla>,
16545        window: &mut Window,
16546        cx: &mut Context<Self>,
16547    ) {
16548        let snapshot = self.snapshot(window, cx).display_snapshot;
16549        let position = position.to_point(&snapshot.buffer_snapshot());
16550        let start = snapshot
16551            .buffer_snapshot()
16552            .clip_point(Point::new(position.row, 0), Bias::Left);
16553        let end = start + Point::new(1, 0);
16554        let start = snapshot.buffer_snapshot().anchor_before(start);
16555        let end = snapshot.buffer_snapshot().anchor_before(end);
16556
16557        self.highlight_rows::<T>(
16558            start..end,
16559            highlight_color
16560                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16561            Default::default(),
16562            cx,
16563        );
16564
16565        if self.buffer.read(cx).is_singleton() {
16566            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16567        }
16568    }
16569
16570    pub fn go_to_definition(
16571        &mut self,
16572        _: &GoToDefinition,
16573        window: &mut Window,
16574        cx: &mut Context<Self>,
16575    ) -> Task<Result<Navigated>> {
16576        let definition =
16577            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16578        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16579        cx.spawn_in(window, async move |editor, cx| {
16580            if definition.await? == Navigated::Yes {
16581                return Ok(Navigated::Yes);
16582            }
16583            match fallback_strategy {
16584                GoToDefinitionFallback::None => Ok(Navigated::No),
16585                GoToDefinitionFallback::FindAllReferences => {
16586                    match editor.update_in(cx, |editor, window, cx| {
16587                        editor.find_all_references(&FindAllReferences, window, cx)
16588                    })? {
16589                        Some(references) => references.await,
16590                        None => Ok(Navigated::No),
16591                    }
16592                }
16593            }
16594        })
16595    }
16596
16597    pub fn go_to_declaration(
16598        &mut self,
16599        _: &GoToDeclaration,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) -> Task<Result<Navigated>> {
16603        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16604    }
16605
16606    pub fn go_to_declaration_split(
16607        &mut self,
16608        _: &GoToDeclaration,
16609        window: &mut Window,
16610        cx: &mut Context<Self>,
16611    ) -> Task<Result<Navigated>> {
16612        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16613    }
16614
16615    pub fn go_to_implementation(
16616        &mut self,
16617        _: &GoToImplementation,
16618        window: &mut Window,
16619        cx: &mut Context<Self>,
16620    ) -> Task<Result<Navigated>> {
16621        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16622    }
16623
16624    pub fn go_to_implementation_split(
16625        &mut self,
16626        _: &GoToImplementationSplit,
16627        window: &mut Window,
16628        cx: &mut Context<Self>,
16629    ) -> Task<Result<Navigated>> {
16630        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16631    }
16632
16633    pub fn go_to_type_definition(
16634        &mut self,
16635        _: &GoToTypeDefinition,
16636        window: &mut Window,
16637        cx: &mut Context<Self>,
16638    ) -> Task<Result<Navigated>> {
16639        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16640    }
16641
16642    pub fn go_to_definition_split(
16643        &mut self,
16644        _: &GoToDefinitionSplit,
16645        window: &mut Window,
16646        cx: &mut Context<Self>,
16647    ) -> Task<Result<Navigated>> {
16648        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16649    }
16650
16651    pub fn go_to_type_definition_split(
16652        &mut self,
16653        _: &GoToTypeDefinitionSplit,
16654        window: &mut Window,
16655        cx: &mut Context<Self>,
16656    ) -> Task<Result<Navigated>> {
16657        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16658    }
16659
16660    fn go_to_definition_of_kind(
16661        &mut self,
16662        kind: GotoDefinitionKind,
16663        split: bool,
16664        window: &mut Window,
16665        cx: &mut Context<Self>,
16666    ) -> Task<Result<Navigated>> {
16667        let Some(provider) = self.semantics_provider.clone() else {
16668            return Task::ready(Ok(Navigated::No));
16669        };
16670        let head = self
16671            .selections
16672            .newest::<usize>(&self.display_snapshot(cx))
16673            .head();
16674        let buffer = self.buffer.read(cx);
16675        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16676            return Task::ready(Ok(Navigated::No));
16677        };
16678        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16679            return Task::ready(Ok(Navigated::No));
16680        };
16681
16682        cx.spawn_in(window, async move |editor, cx| {
16683            let Some(definitions) = definitions.await? else {
16684                return Ok(Navigated::No);
16685            };
16686            let navigated = editor
16687                .update_in(cx, |editor, window, cx| {
16688                    editor.navigate_to_hover_links(
16689                        Some(kind),
16690                        definitions
16691                            .into_iter()
16692                            .filter(|location| {
16693                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16694                            })
16695                            .map(HoverLink::Text)
16696                            .collect::<Vec<_>>(),
16697                        split,
16698                        window,
16699                        cx,
16700                    )
16701                })?
16702                .await?;
16703            anyhow::Ok(navigated)
16704        })
16705    }
16706
16707    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16708        let selection = self.selections.newest_anchor();
16709        let head = selection.head();
16710        let tail = selection.tail();
16711
16712        let Some((buffer, start_position)) =
16713            self.buffer.read(cx).text_anchor_for_position(head, cx)
16714        else {
16715            return;
16716        };
16717
16718        let end_position = if head != tail {
16719            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16720                return;
16721            };
16722            Some(pos)
16723        } else {
16724            None
16725        };
16726
16727        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16728            let url = if let Some(end_pos) = end_position {
16729                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16730            } else {
16731                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16732            };
16733
16734            if let Some(url) = url {
16735                cx.update(|window, cx| {
16736                    if parse_zed_link(&url, cx).is_some() {
16737                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16738                    } else {
16739                        cx.open_url(&url);
16740                    }
16741                })?;
16742            }
16743
16744            anyhow::Ok(())
16745        });
16746
16747        url_finder.detach();
16748    }
16749
16750    pub fn open_selected_filename(
16751        &mut self,
16752        _: &OpenSelectedFilename,
16753        window: &mut Window,
16754        cx: &mut Context<Self>,
16755    ) {
16756        let Some(workspace) = self.workspace() else {
16757            return;
16758        };
16759
16760        let position = self.selections.newest_anchor().head();
16761
16762        let Some((buffer, buffer_position)) =
16763            self.buffer.read(cx).text_anchor_for_position(position, cx)
16764        else {
16765            return;
16766        };
16767
16768        let project = self.project.clone();
16769
16770        cx.spawn_in(window, async move |_, cx| {
16771            let result = find_file(&buffer, project, buffer_position, cx).await;
16772
16773            if let Some((_, path)) = result {
16774                workspace
16775                    .update_in(cx, |workspace, window, cx| {
16776                        workspace.open_resolved_path(path, window, cx)
16777                    })?
16778                    .await?;
16779            }
16780            anyhow::Ok(())
16781        })
16782        .detach();
16783    }
16784
16785    pub(crate) fn navigate_to_hover_links(
16786        &mut self,
16787        kind: Option<GotoDefinitionKind>,
16788        definitions: Vec<HoverLink>,
16789        split: bool,
16790        window: &mut Window,
16791        cx: &mut Context<Editor>,
16792    ) -> Task<Result<Navigated>> {
16793        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16794        let mut first_url_or_file = None;
16795        let definitions: Vec<_> = definitions
16796            .into_iter()
16797            .filter_map(|def| match def {
16798                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16799                HoverLink::InlayHint(lsp_location, server_id) => {
16800                    let computation =
16801                        self.compute_target_location(lsp_location, server_id, window, cx);
16802                    Some(cx.background_spawn(computation))
16803                }
16804                HoverLink::Url(url) => {
16805                    first_url_or_file = Some(Either::Left(url));
16806                    None
16807                }
16808                HoverLink::File(path) => {
16809                    first_url_or_file = Some(Either::Right(path));
16810                    None
16811                }
16812            })
16813            .collect();
16814
16815        let workspace = self.workspace();
16816
16817        cx.spawn_in(window, async move |editor, cx| {
16818            let locations: Vec<Location> = future::join_all(definitions)
16819                .await
16820                .into_iter()
16821                .filter_map(|location| location.transpose())
16822                .collect::<Result<_>>()
16823                .context("location tasks")?;
16824            let mut locations = cx.update(|_, cx| {
16825                locations
16826                    .into_iter()
16827                    .map(|location| {
16828                        let buffer = location.buffer.read(cx);
16829                        (location.buffer, location.range.to_point(buffer))
16830                    })
16831                    .into_group_map()
16832            })?;
16833            let mut num_locations = 0;
16834            for ranges in locations.values_mut() {
16835                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16836                ranges.dedup();
16837                num_locations += ranges.len();
16838            }
16839
16840            if num_locations > 1 {
16841                let Some(workspace) = workspace else {
16842                    return Ok(Navigated::No);
16843                };
16844
16845                let tab_kind = match kind {
16846                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16847                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16848                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16849                    Some(GotoDefinitionKind::Type) => "Types",
16850                };
16851                let title = editor
16852                    .update_in(cx, |_, _, cx| {
16853                        let target = locations
16854                            .iter()
16855                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16856                            .map(|(buffer, location)| {
16857                                buffer
16858                                    .read(cx)
16859                                    .text_for_range(location.clone())
16860                                    .collect::<String>()
16861                            })
16862                            .filter(|text| !text.contains('\n'))
16863                            .unique()
16864                            .take(3)
16865                            .join(", ");
16866                        if target.is_empty() {
16867                            tab_kind.to_owned()
16868                        } else {
16869                            format!("{tab_kind} for {target}")
16870                        }
16871                    })
16872                    .context("buffer title")?;
16873
16874                let opened = workspace
16875                    .update_in(cx, |workspace, window, cx| {
16876                        Self::open_locations_in_multibuffer(
16877                            workspace,
16878                            locations,
16879                            title,
16880                            split,
16881                            MultibufferSelectionMode::First,
16882                            window,
16883                            cx,
16884                        )
16885                    })
16886                    .is_ok();
16887
16888                anyhow::Ok(Navigated::from_bool(opened))
16889            } else if num_locations == 0 {
16890                // If there is one url or file, open it directly
16891                match first_url_or_file {
16892                    Some(Either::Left(url)) => {
16893                        cx.update(|_, cx| cx.open_url(&url))?;
16894                        Ok(Navigated::Yes)
16895                    }
16896                    Some(Either::Right(path)) => {
16897                        let Some(workspace) = workspace else {
16898                            return Ok(Navigated::No);
16899                        };
16900
16901                        workspace
16902                            .update_in(cx, |workspace, window, cx| {
16903                                workspace.open_resolved_path(path, window, cx)
16904                            })?
16905                            .await?;
16906                        Ok(Navigated::Yes)
16907                    }
16908                    None => Ok(Navigated::No),
16909                }
16910            } else {
16911                let Some(workspace) = workspace else {
16912                    return Ok(Navigated::No);
16913                };
16914
16915                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16916                let target_range = target_ranges.first().unwrap().clone();
16917
16918                editor.update_in(cx, |editor, window, cx| {
16919                    let range = target_range.to_point(target_buffer.read(cx));
16920                    let range = editor.range_for_match(&range, false);
16921                    let range = collapse_multiline_range(range);
16922
16923                    if !split
16924                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16925                    {
16926                        editor.go_to_singleton_buffer_range(range, window, cx);
16927                    } else {
16928                        let pane = workspace.read(cx).active_pane().clone();
16929                        window.defer(cx, move |window, cx| {
16930                            let target_editor: Entity<Self> =
16931                                workspace.update(cx, |workspace, cx| {
16932                                    let pane = if split {
16933                                        workspace.adjacent_pane(window, cx)
16934                                    } else {
16935                                        workspace.active_pane().clone()
16936                                    };
16937
16938                                    workspace.open_project_item(
16939                                        pane,
16940                                        target_buffer.clone(),
16941                                        true,
16942                                        true,
16943                                        window,
16944                                        cx,
16945                                    )
16946                                });
16947                            target_editor.update(cx, |target_editor, cx| {
16948                                // When selecting a definition in a different buffer, disable the nav history
16949                                // to avoid creating a history entry at the previous cursor location.
16950                                pane.update(cx, |pane, _| pane.disable_history());
16951                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16952                                pane.update(cx, |pane, _| pane.enable_history());
16953                            });
16954                        });
16955                    }
16956                    Navigated::Yes
16957                })
16958            }
16959        })
16960    }
16961
16962    fn compute_target_location(
16963        &self,
16964        lsp_location: lsp::Location,
16965        server_id: LanguageServerId,
16966        window: &mut Window,
16967        cx: &mut Context<Self>,
16968    ) -> Task<anyhow::Result<Option<Location>>> {
16969        let Some(project) = self.project.clone() else {
16970            return Task::ready(Ok(None));
16971        };
16972
16973        cx.spawn_in(window, async move |editor, cx| {
16974            let location_task = editor.update(cx, |_, cx| {
16975                project.update(cx, |project, cx| {
16976                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16977                })
16978            })?;
16979            let location = Some({
16980                let target_buffer_handle = location_task.await.context("open local buffer")?;
16981                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16982                    let target_start = target_buffer
16983                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16984                    let target_end = target_buffer
16985                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16986                    target_buffer.anchor_after(target_start)
16987                        ..target_buffer.anchor_before(target_end)
16988                })?;
16989                Location {
16990                    buffer: target_buffer_handle,
16991                    range,
16992                }
16993            });
16994            Ok(location)
16995        })
16996    }
16997
16998    fn go_to_next_reference(
16999        &mut self,
17000        _: &GoToNextReference,
17001        window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) {
17004        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17005        if let Some(task) = task {
17006            task.detach();
17007        };
17008    }
17009
17010    fn go_to_prev_reference(
17011        &mut self,
17012        _: &GoToPreviousReference,
17013        window: &mut Window,
17014        cx: &mut Context<Self>,
17015    ) {
17016        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17017        if let Some(task) = task {
17018            task.detach();
17019        };
17020    }
17021
17022    pub fn go_to_reference_before_or_after_position(
17023        &mut self,
17024        direction: Direction,
17025        count: usize,
17026        window: &mut Window,
17027        cx: &mut Context<Self>,
17028    ) -> Option<Task<Result<()>>> {
17029        let selection = self.selections.newest_anchor();
17030        let head = selection.head();
17031
17032        let multi_buffer = self.buffer.read(cx);
17033
17034        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17035        let workspace = self.workspace()?;
17036        let project = workspace.read(cx).project().clone();
17037        let references =
17038            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17039        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17040            let Some(locations) = references.await? else {
17041                return Ok(());
17042            };
17043
17044            if locations.is_empty() {
17045                // totally normal - the cursor may be on something which is not
17046                // a symbol (e.g. a keyword)
17047                log::info!("no references found under cursor");
17048                return Ok(());
17049            }
17050
17051            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17052
17053            let multi_buffer_snapshot =
17054                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
17055
17056            let (locations, current_location_index) =
17057                multi_buffer.update(cx, |multi_buffer, cx| {
17058                    let mut locations = locations
17059                        .into_iter()
17060                        .filter_map(|loc| {
17061                            let start = multi_buffer.buffer_anchor_to_anchor(
17062                                &loc.buffer,
17063                                loc.range.start,
17064                                cx,
17065                            )?;
17066                            let end = multi_buffer.buffer_anchor_to_anchor(
17067                                &loc.buffer,
17068                                loc.range.end,
17069                                cx,
17070                            )?;
17071                            Some(start..end)
17072                        })
17073                        .collect::<Vec<_>>();
17074
17075                    // There is an O(n) implementation, but given this list will be
17076                    // small (usually <100 items), the extra O(log(n)) factor isn't
17077                    // worth the (surprisingly large amount of) extra complexity.
17078                    locations
17079                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17080
17081                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17082
17083                    let current_location_index = locations.iter().position(|loc| {
17084                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17085                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17086                    });
17087
17088                    (locations, current_location_index)
17089                })?;
17090
17091            let Some(current_location_index) = current_location_index else {
17092                // This indicates something has gone wrong, because we already
17093                // handle the "no references" case above
17094                log::error!(
17095                    "failed to find current reference under cursor. Total references: {}",
17096                    locations.len()
17097                );
17098                return Ok(());
17099            };
17100
17101            let destination_location_index = match direction {
17102                Direction::Next => (current_location_index + count) % locations.len(),
17103                Direction::Prev => {
17104                    (current_location_index + locations.len() - count % locations.len())
17105                        % locations.len()
17106                }
17107            };
17108
17109            // TODO(cameron): is this needed?
17110            // the thinking is to avoid "jumping to the current location" (avoid
17111            // polluting "jumplist" in vim terms)
17112            if current_location_index == destination_location_index {
17113                return Ok(());
17114            }
17115
17116            let Range { start, end } = locations[destination_location_index];
17117
17118            editor.update_in(cx, |editor, window, cx| {
17119                let effects = SelectionEffects::default();
17120
17121                editor.unfold_ranges(&[start..end], false, false, cx);
17122                editor.change_selections(effects, window, cx, |s| {
17123                    s.select_ranges([start..start]);
17124                });
17125            })?;
17126
17127            Ok(())
17128        }))
17129    }
17130
17131    pub fn find_all_references(
17132        &mut self,
17133        _: &FindAllReferences,
17134        window: &mut Window,
17135        cx: &mut Context<Self>,
17136    ) -> Option<Task<Result<Navigated>>> {
17137        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17138        let multi_buffer = self.buffer.read(cx);
17139        let head = selection.head();
17140
17141        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17142        let head_anchor = multi_buffer_snapshot.anchor_at(
17143            head,
17144            if head < selection.tail() {
17145                Bias::Right
17146            } else {
17147                Bias::Left
17148            },
17149        );
17150
17151        match self
17152            .find_all_references_task_sources
17153            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17154        {
17155            Ok(_) => {
17156                log::info!(
17157                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17158                );
17159                return None;
17160            }
17161            Err(i) => {
17162                self.find_all_references_task_sources.insert(i, head_anchor);
17163            }
17164        }
17165
17166        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17167        let workspace = self.workspace()?;
17168        let project = workspace.read(cx).project().clone();
17169        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17170        Some(cx.spawn_in(window, async move |editor, cx| {
17171            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17172                if let Ok(i) = editor
17173                    .find_all_references_task_sources
17174                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17175                {
17176                    editor.find_all_references_task_sources.remove(i);
17177                }
17178            });
17179
17180            let Some(locations) = references.await? else {
17181                return anyhow::Ok(Navigated::No);
17182            };
17183            let mut locations = cx.update(|_, cx| {
17184                locations
17185                    .into_iter()
17186                    .map(|location| {
17187                        let buffer = location.buffer.read(cx);
17188                        (location.buffer, location.range.to_point(buffer))
17189                    })
17190                    .into_group_map()
17191            })?;
17192            if locations.is_empty() {
17193                return anyhow::Ok(Navigated::No);
17194            }
17195            for ranges in locations.values_mut() {
17196                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17197                ranges.dedup();
17198            }
17199
17200            workspace.update_in(cx, |workspace, window, cx| {
17201                let target = locations
17202                    .iter()
17203                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17204                    .map(|(buffer, location)| {
17205                        buffer
17206                            .read(cx)
17207                            .text_for_range(location.clone())
17208                            .collect::<String>()
17209                    })
17210                    .filter(|text| !text.contains('\n'))
17211                    .unique()
17212                    .take(3)
17213                    .join(", ");
17214                let title = if target.is_empty() {
17215                    "References".to_owned()
17216                } else {
17217                    format!("References to {target}")
17218                };
17219                Self::open_locations_in_multibuffer(
17220                    workspace,
17221                    locations,
17222                    title,
17223                    false,
17224                    MultibufferSelectionMode::First,
17225                    window,
17226                    cx,
17227                );
17228                Navigated::Yes
17229            })
17230        }))
17231    }
17232
17233    /// Opens a multibuffer with the given project locations in it
17234    pub fn open_locations_in_multibuffer(
17235        workspace: &mut Workspace,
17236        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17237        title: String,
17238        split: bool,
17239        multibuffer_selection_mode: MultibufferSelectionMode,
17240        window: &mut Window,
17241        cx: &mut Context<Workspace>,
17242    ) {
17243        if locations.is_empty() {
17244            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17245            return;
17246        }
17247
17248        let capability = workspace.project().read(cx).capability();
17249        let mut ranges = <Vec<Range<Anchor>>>::new();
17250
17251        // a key to find existing multibuffer editors with the same set of locations
17252        // to prevent us from opening more and more multibuffer tabs for searches and the like
17253        let mut key = (title.clone(), vec![]);
17254        let excerpt_buffer = cx.new(|cx| {
17255            let key = &mut key.1;
17256            let mut multibuffer = MultiBuffer::new(capability);
17257            for (buffer, mut ranges_for_buffer) in locations {
17258                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17259                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17260                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17261                    PathKey::for_buffer(&buffer, cx),
17262                    buffer.clone(),
17263                    ranges_for_buffer,
17264                    multibuffer_context_lines(cx),
17265                    cx,
17266                );
17267                ranges.extend(new_ranges)
17268            }
17269
17270            multibuffer.with_title(title)
17271        });
17272        let existing = workspace.active_pane().update(cx, |pane, cx| {
17273            pane.items()
17274                .filter_map(|item| item.downcast::<Editor>())
17275                .find(|editor| {
17276                    editor
17277                        .read(cx)
17278                        .lookup_key
17279                        .as_ref()
17280                        .and_then(|it| {
17281                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17282                        })
17283                        .is_some_and(|it| *it == key)
17284                })
17285        });
17286        let editor = existing.unwrap_or_else(|| {
17287            cx.new(|cx| {
17288                let mut editor = Editor::for_multibuffer(
17289                    excerpt_buffer,
17290                    Some(workspace.project().clone()),
17291                    window,
17292                    cx,
17293                );
17294                editor.lookup_key = Some(Box::new(key));
17295                editor
17296            })
17297        });
17298        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17299            MultibufferSelectionMode::First => {
17300                if let Some(first_range) = ranges.first() {
17301                    editor.change_selections(
17302                        SelectionEffects::no_scroll(),
17303                        window,
17304                        cx,
17305                        |selections| {
17306                            selections.clear_disjoint();
17307                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17308                        },
17309                    );
17310                }
17311                editor.highlight_background::<Self>(
17312                    &ranges,
17313                    |theme| theme.colors().editor_highlighted_line_background,
17314                    cx,
17315                );
17316            }
17317            MultibufferSelectionMode::All => {
17318                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17319                    selections.clear_disjoint();
17320                    selections.select_anchor_ranges(ranges);
17321                });
17322            }
17323        });
17324
17325        let item = Box::new(editor);
17326        let item_id = item.item_id();
17327
17328        if split {
17329            let pane = workspace.adjacent_pane(window, cx);
17330            workspace.add_item(pane, item, None, true, true, window, cx);
17331        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17332            let (preview_item_id, preview_item_idx) =
17333                workspace.active_pane().read_with(cx, |pane, _| {
17334                    (pane.preview_item_id(), pane.preview_item_idx())
17335                });
17336
17337            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17338
17339            if let Some(preview_item_id) = preview_item_id {
17340                workspace.active_pane().update(cx, |pane, cx| {
17341                    pane.remove_item(preview_item_id, false, false, window, cx);
17342                });
17343            }
17344        } else {
17345            workspace.add_item_to_active_pane(item, None, true, window, cx);
17346        }
17347        workspace.active_pane().update(cx, |pane, cx| {
17348            pane.set_preview_item_id(Some(item_id), cx);
17349        });
17350    }
17351
17352    pub fn rename(
17353        &mut self,
17354        _: &Rename,
17355        window: &mut Window,
17356        cx: &mut Context<Self>,
17357    ) -> Option<Task<Result<()>>> {
17358        use language::ToOffset as _;
17359
17360        let provider = self.semantics_provider.clone()?;
17361        let selection = self.selections.newest_anchor().clone();
17362        let (cursor_buffer, cursor_buffer_position) = self
17363            .buffer
17364            .read(cx)
17365            .text_anchor_for_position(selection.head(), cx)?;
17366        let (tail_buffer, cursor_buffer_position_end) = self
17367            .buffer
17368            .read(cx)
17369            .text_anchor_for_position(selection.tail(), cx)?;
17370        if tail_buffer != cursor_buffer {
17371            return None;
17372        }
17373
17374        let snapshot = cursor_buffer.read(cx).snapshot();
17375        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17376        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17377        let prepare_rename = provider
17378            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17379            .unwrap_or_else(|| Task::ready(Ok(None)));
17380        drop(snapshot);
17381
17382        Some(cx.spawn_in(window, async move |this, cx| {
17383            let rename_range = if let Some(range) = prepare_rename.await? {
17384                Some(range)
17385            } else {
17386                this.update(cx, |this, cx| {
17387                    let buffer = this.buffer.read(cx).snapshot(cx);
17388                    let mut buffer_highlights = this
17389                        .document_highlights_for_position(selection.head(), &buffer)
17390                        .filter(|highlight| {
17391                            highlight.start.excerpt_id == selection.head().excerpt_id
17392                                && highlight.end.excerpt_id == selection.head().excerpt_id
17393                        });
17394                    buffer_highlights
17395                        .next()
17396                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17397                })?
17398            };
17399            if let Some(rename_range) = rename_range {
17400                this.update_in(cx, |this, window, cx| {
17401                    let snapshot = cursor_buffer.read(cx).snapshot();
17402                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17403                    let cursor_offset_in_rename_range =
17404                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17405                    let cursor_offset_in_rename_range_end =
17406                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17407
17408                    this.take_rename(false, window, cx);
17409                    let buffer = this.buffer.read(cx).read(cx);
17410                    let cursor_offset = selection.head().to_offset(&buffer);
17411                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17412                    let rename_end = rename_start + rename_buffer_range.len();
17413                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17414                    let mut old_highlight_id = None;
17415                    let old_name: Arc<str> = buffer
17416                        .chunks(rename_start..rename_end, true)
17417                        .map(|chunk| {
17418                            if old_highlight_id.is_none() {
17419                                old_highlight_id = chunk.syntax_highlight_id;
17420                            }
17421                            chunk.text
17422                        })
17423                        .collect::<String>()
17424                        .into();
17425
17426                    drop(buffer);
17427
17428                    // Position the selection in the rename editor so that it matches the current selection.
17429                    this.show_local_selections = false;
17430                    let rename_editor = cx.new(|cx| {
17431                        let mut editor = Editor::single_line(window, cx);
17432                        editor.buffer.update(cx, |buffer, cx| {
17433                            buffer.edit([(0..0, old_name.clone())], None, cx)
17434                        });
17435                        let rename_selection_range = match cursor_offset_in_rename_range
17436                            .cmp(&cursor_offset_in_rename_range_end)
17437                        {
17438                            Ordering::Equal => {
17439                                editor.select_all(&SelectAll, window, cx);
17440                                return editor;
17441                            }
17442                            Ordering::Less => {
17443                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17444                            }
17445                            Ordering::Greater => {
17446                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17447                            }
17448                        };
17449                        if rename_selection_range.end > old_name.len() {
17450                            editor.select_all(&SelectAll, window, cx);
17451                        } else {
17452                            editor.change_selections(Default::default(), window, cx, |s| {
17453                                s.select_ranges([rename_selection_range]);
17454                            });
17455                        }
17456                        editor
17457                    });
17458                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17459                        if e == &EditorEvent::Focused {
17460                            cx.emit(EditorEvent::FocusedIn)
17461                        }
17462                    })
17463                    .detach();
17464
17465                    let write_highlights =
17466                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17467                    let read_highlights =
17468                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17469                    let ranges = write_highlights
17470                        .iter()
17471                        .flat_map(|(_, ranges)| ranges.iter())
17472                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17473                        .cloned()
17474                        .collect();
17475
17476                    this.highlight_text::<Rename>(
17477                        ranges,
17478                        HighlightStyle {
17479                            fade_out: Some(0.6),
17480                            ..Default::default()
17481                        },
17482                        cx,
17483                    );
17484                    let rename_focus_handle = rename_editor.focus_handle(cx);
17485                    window.focus(&rename_focus_handle);
17486                    let block_id = this.insert_blocks(
17487                        [BlockProperties {
17488                            style: BlockStyle::Flex,
17489                            placement: BlockPlacement::Below(range.start),
17490                            height: Some(1),
17491                            render: Arc::new({
17492                                let rename_editor = rename_editor.clone();
17493                                move |cx: &mut BlockContext| {
17494                                    let mut text_style = cx.editor_style.text.clone();
17495                                    if let Some(highlight_style) = old_highlight_id
17496                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17497                                    {
17498                                        text_style = text_style.highlight(highlight_style);
17499                                    }
17500                                    div()
17501                                        .block_mouse_except_scroll()
17502                                        .pl(cx.anchor_x)
17503                                        .child(EditorElement::new(
17504                                            &rename_editor,
17505                                            EditorStyle {
17506                                                background: cx.theme().system().transparent,
17507                                                local_player: cx.editor_style.local_player,
17508                                                text: text_style,
17509                                                scrollbar_width: cx.editor_style.scrollbar_width,
17510                                                syntax: cx.editor_style.syntax.clone(),
17511                                                status: cx.editor_style.status.clone(),
17512                                                inlay_hints_style: HighlightStyle {
17513                                                    font_weight: Some(FontWeight::BOLD),
17514                                                    ..make_inlay_hints_style(cx.app)
17515                                                },
17516                                                edit_prediction_styles: make_suggestion_styles(
17517                                                    cx.app,
17518                                                ),
17519                                                ..EditorStyle::default()
17520                                            },
17521                                        ))
17522                                        .into_any_element()
17523                                }
17524                            }),
17525                            priority: 0,
17526                        }],
17527                        Some(Autoscroll::fit()),
17528                        cx,
17529                    )[0];
17530                    this.pending_rename = Some(RenameState {
17531                        range,
17532                        old_name,
17533                        editor: rename_editor,
17534                        block_id,
17535                    });
17536                })?;
17537            }
17538
17539            Ok(())
17540        }))
17541    }
17542
17543    pub fn confirm_rename(
17544        &mut self,
17545        _: &ConfirmRename,
17546        window: &mut Window,
17547        cx: &mut Context<Self>,
17548    ) -> Option<Task<Result<()>>> {
17549        let rename = self.take_rename(false, window, cx)?;
17550        let workspace = self.workspace()?.downgrade();
17551        let (buffer, start) = self
17552            .buffer
17553            .read(cx)
17554            .text_anchor_for_position(rename.range.start, cx)?;
17555        let (end_buffer, _) = self
17556            .buffer
17557            .read(cx)
17558            .text_anchor_for_position(rename.range.end, cx)?;
17559        if buffer != end_buffer {
17560            return None;
17561        }
17562
17563        let old_name = rename.old_name;
17564        let new_name = rename.editor.read(cx).text(cx);
17565
17566        let rename = self.semantics_provider.as_ref()?.perform_rename(
17567            &buffer,
17568            start,
17569            new_name.clone(),
17570            cx,
17571        )?;
17572
17573        Some(cx.spawn_in(window, async move |editor, cx| {
17574            let project_transaction = rename.await?;
17575            Self::open_project_transaction(
17576                &editor,
17577                workspace,
17578                project_transaction,
17579                format!("Rename: {}{}", old_name, new_name),
17580                cx,
17581            )
17582            .await?;
17583
17584            editor.update(cx, |editor, cx| {
17585                editor.refresh_document_highlights(cx);
17586            })?;
17587            Ok(())
17588        }))
17589    }
17590
17591    fn take_rename(
17592        &mut self,
17593        moving_cursor: bool,
17594        window: &mut Window,
17595        cx: &mut Context<Self>,
17596    ) -> Option<RenameState> {
17597        let rename = self.pending_rename.take()?;
17598        if rename.editor.focus_handle(cx).is_focused(window) {
17599            window.focus(&self.focus_handle);
17600        }
17601
17602        self.remove_blocks(
17603            [rename.block_id].into_iter().collect(),
17604            Some(Autoscroll::fit()),
17605            cx,
17606        );
17607        self.clear_highlights::<Rename>(cx);
17608        self.show_local_selections = true;
17609
17610        if moving_cursor {
17611            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17612                editor
17613                    .selections
17614                    .newest::<usize>(&editor.display_snapshot(cx))
17615                    .head()
17616            });
17617
17618            // Update the selection to match the position of the selection inside
17619            // the rename editor.
17620            let snapshot = self.buffer.read(cx).read(cx);
17621            let rename_range = rename.range.to_offset(&snapshot);
17622            let cursor_in_editor = snapshot
17623                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17624                .min(rename_range.end);
17625            drop(snapshot);
17626
17627            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17628                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17629            });
17630        } else {
17631            self.refresh_document_highlights(cx);
17632        }
17633
17634        Some(rename)
17635    }
17636
17637    pub fn pending_rename(&self) -> Option<&RenameState> {
17638        self.pending_rename.as_ref()
17639    }
17640
17641    fn format(
17642        &mut self,
17643        _: &Format,
17644        window: &mut Window,
17645        cx: &mut Context<Self>,
17646    ) -> Option<Task<Result<()>>> {
17647        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17648
17649        let project = match &self.project {
17650            Some(project) => project.clone(),
17651            None => return None,
17652        };
17653
17654        Some(self.perform_format(
17655            project,
17656            FormatTrigger::Manual,
17657            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17658            window,
17659            cx,
17660        ))
17661    }
17662
17663    fn format_selections(
17664        &mut self,
17665        _: &FormatSelections,
17666        window: &mut Window,
17667        cx: &mut Context<Self>,
17668    ) -> Option<Task<Result<()>>> {
17669        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17670
17671        let project = match &self.project {
17672            Some(project) => project.clone(),
17673            None => return None,
17674        };
17675
17676        let ranges = self
17677            .selections
17678            .all_adjusted(&self.display_snapshot(cx))
17679            .into_iter()
17680            .map(|selection| selection.range())
17681            .collect_vec();
17682
17683        Some(self.perform_format(
17684            project,
17685            FormatTrigger::Manual,
17686            FormatTarget::Ranges(ranges),
17687            window,
17688            cx,
17689        ))
17690    }
17691
17692    fn perform_format(
17693        &mut self,
17694        project: Entity<Project>,
17695        trigger: FormatTrigger,
17696        target: FormatTarget,
17697        window: &mut Window,
17698        cx: &mut Context<Self>,
17699    ) -> Task<Result<()>> {
17700        let buffer = self.buffer.clone();
17701        let (buffers, target) = match target {
17702            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17703            FormatTarget::Ranges(selection_ranges) => {
17704                let multi_buffer = buffer.read(cx);
17705                let snapshot = multi_buffer.read(cx);
17706                let mut buffers = HashSet::default();
17707                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17708                    BTreeMap::new();
17709                for selection_range in selection_ranges {
17710                    for (buffer, buffer_range, _) in
17711                        snapshot.range_to_buffer_ranges(selection_range)
17712                    {
17713                        let buffer_id = buffer.remote_id();
17714                        let start = buffer.anchor_before(buffer_range.start);
17715                        let end = buffer.anchor_after(buffer_range.end);
17716                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17717                        buffer_id_to_ranges
17718                            .entry(buffer_id)
17719                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17720                            .or_insert_with(|| vec![start..end]);
17721                    }
17722                }
17723                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17724            }
17725        };
17726
17727        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17728        let selections_prev = transaction_id_prev
17729            .and_then(|transaction_id_prev| {
17730                // default to selections as they were after the last edit, if we have them,
17731                // instead of how they are now.
17732                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17733                // will take you back to where you made the last edit, instead of staying where you scrolled
17734                self.selection_history
17735                    .transaction(transaction_id_prev)
17736                    .map(|t| t.0.clone())
17737            })
17738            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17739
17740        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17741        let format = project.update(cx, |project, cx| {
17742            project.format(buffers, target, true, trigger, cx)
17743        });
17744
17745        cx.spawn_in(window, async move |editor, cx| {
17746            let transaction = futures::select_biased! {
17747                transaction = format.log_err().fuse() => transaction,
17748                () = timeout => {
17749                    log::warn!("timed out waiting for formatting");
17750                    None
17751                }
17752            };
17753
17754            buffer
17755                .update(cx, |buffer, cx| {
17756                    if let Some(transaction) = transaction
17757                        && !buffer.is_singleton()
17758                    {
17759                        buffer.push_transaction(&transaction.0, cx);
17760                    }
17761                    cx.notify();
17762                })
17763                .ok();
17764
17765            if let Some(transaction_id_now) =
17766                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17767            {
17768                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17769                if has_new_transaction {
17770                    _ = editor.update(cx, |editor, _| {
17771                        editor
17772                            .selection_history
17773                            .insert_transaction(transaction_id_now, selections_prev);
17774                    });
17775                }
17776            }
17777
17778            Ok(())
17779        })
17780    }
17781
17782    fn organize_imports(
17783        &mut self,
17784        _: &OrganizeImports,
17785        window: &mut Window,
17786        cx: &mut Context<Self>,
17787    ) -> Option<Task<Result<()>>> {
17788        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17789        let project = match &self.project {
17790            Some(project) => project.clone(),
17791            None => return None,
17792        };
17793        Some(self.perform_code_action_kind(
17794            project,
17795            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17796            window,
17797            cx,
17798        ))
17799    }
17800
17801    fn perform_code_action_kind(
17802        &mut self,
17803        project: Entity<Project>,
17804        kind: CodeActionKind,
17805        window: &mut Window,
17806        cx: &mut Context<Self>,
17807    ) -> Task<Result<()>> {
17808        let buffer = self.buffer.clone();
17809        let buffers = buffer.read(cx).all_buffers();
17810        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17811        let apply_action = project.update(cx, |project, cx| {
17812            project.apply_code_action_kind(buffers, kind, true, cx)
17813        });
17814        cx.spawn_in(window, async move |_, cx| {
17815            let transaction = futures::select_biased! {
17816                () = timeout => {
17817                    log::warn!("timed out waiting for executing code action");
17818                    None
17819                }
17820                transaction = apply_action.log_err().fuse() => transaction,
17821            };
17822            buffer
17823                .update(cx, |buffer, cx| {
17824                    // check if we need this
17825                    if let Some(transaction) = transaction
17826                        && !buffer.is_singleton()
17827                    {
17828                        buffer.push_transaction(&transaction.0, cx);
17829                    }
17830                    cx.notify();
17831                })
17832                .ok();
17833            Ok(())
17834        })
17835    }
17836
17837    pub fn restart_language_server(
17838        &mut self,
17839        _: &RestartLanguageServer,
17840        _: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) {
17843        if let Some(project) = self.project.clone() {
17844            self.buffer.update(cx, |multi_buffer, cx| {
17845                project.update(cx, |project, cx| {
17846                    project.restart_language_servers_for_buffers(
17847                        multi_buffer.all_buffers().into_iter().collect(),
17848                        HashSet::default(),
17849                        cx,
17850                    );
17851                });
17852            })
17853        }
17854    }
17855
17856    pub fn stop_language_server(
17857        &mut self,
17858        _: &StopLanguageServer,
17859        _: &mut Window,
17860        cx: &mut Context<Self>,
17861    ) {
17862        if let Some(project) = self.project.clone() {
17863            self.buffer.update(cx, |multi_buffer, cx| {
17864                project.update(cx, |project, cx| {
17865                    project.stop_language_servers_for_buffers(
17866                        multi_buffer.all_buffers().into_iter().collect(),
17867                        HashSet::default(),
17868                        cx,
17869                    );
17870                });
17871            });
17872            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17873        }
17874    }
17875
17876    fn cancel_language_server_work(
17877        workspace: &mut Workspace,
17878        _: &actions::CancelLanguageServerWork,
17879        _: &mut Window,
17880        cx: &mut Context<Workspace>,
17881    ) {
17882        let project = workspace.project();
17883        let buffers = workspace
17884            .active_item(cx)
17885            .and_then(|item| item.act_as::<Editor>(cx))
17886            .map_or(HashSet::default(), |editor| {
17887                editor.read(cx).buffer.read(cx).all_buffers()
17888            });
17889        project.update(cx, |project, cx| {
17890            project.cancel_language_server_work_for_buffers(buffers, cx);
17891        });
17892    }
17893
17894    fn show_character_palette(
17895        &mut self,
17896        _: &ShowCharacterPalette,
17897        window: &mut Window,
17898        _: &mut Context<Self>,
17899    ) {
17900        window.show_character_palette();
17901    }
17902
17903    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17904        if !self.diagnostics_enabled() {
17905            return;
17906        }
17907
17908        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17909            let buffer = self.buffer.read(cx).snapshot(cx);
17910            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17911            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17912            let is_valid = buffer
17913                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17914                .any(|entry| {
17915                    entry.diagnostic.is_primary
17916                        && !entry.range.is_empty()
17917                        && entry.range.start == primary_range_start
17918                        && entry.diagnostic.message == active_diagnostics.active_message
17919                });
17920
17921            if !is_valid {
17922                self.dismiss_diagnostics(cx);
17923            }
17924        }
17925    }
17926
17927    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17928        match &self.active_diagnostics {
17929            ActiveDiagnostic::Group(group) => Some(group),
17930            _ => None,
17931        }
17932    }
17933
17934    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17935        if !self.diagnostics_enabled() {
17936            return;
17937        }
17938        self.dismiss_diagnostics(cx);
17939        self.active_diagnostics = ActiveDiagnostic::All;
17940    }
17941
17942    fn activate_diagnostics(
17943        &mut self,
17944        buffer_id: BufferId,
17945        diagnostic: DiagnosticEntryRef<'_, usize>,
17946        window: &mut Window,
17947        cx: &mut Context<Self>,
17948    ) {
17949        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17950            return;
17951        }
17952        self.dismiss_diagnostics(cx);
17953        let snapshot = self.snapshot(window, cx);
17954        let buffer = self.buffer.read(cx).snapshot(cx);
17955        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17956            return;
17957        };
17958
17959        let diagnostic_group = buffer
17960            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17961            .collect::<Vec<_>>();
17962
17963        let language_registry = self
17964            .project()
17965            .map(|project| project.read(cx).languages().clone());
17966
17967        let blocks = renderer.render_group(
17968            diagnostic_group,
17969            buffer_id,
17970            snapshot,
17971            cx.weak_entity(),
17972            language_registry,
17973            cx,
17974        );
17975
17976        let blocks = self.display_map.update(cx, |display_map, cx| {
17977            display_map.insert_blocks(blocks, cx).into_iter().collect()
17978        });
17979        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17980            active_range: buffer.anchor_before(diagnostic.range.start)
17981                ..buffer.anchor_after(diagnostic.range.end),
17982            active_message: diagnostic.diagnostic.message.clone(),
17983            group_id: diagnostic.diagnostic.group_id,
17984            blocks,
17985        });
17986        cx.notify();
17987    }
17988
17989    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17990        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17991            return;
17992        };
17993
17994        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17995        if let ActiveDiagnostic::Group(group) = prev {
17996            self.display_map.update(cx, |display_map, cx| {
17997                display_map.remove_blocks(group.blocks, cx);
17998            });
17999            cx.notify();
18000        }
18001    }
18002
18003    /// Disable inline diagnostics rendering for this editor.
18004    pub fn disable_inline_diagnostics(&mut self) {
18005        self.inline_diagnostics_enabled = false;
18006        self.inline_diagnostics_update = Task::ready(());
18007        self.inline_diagnostics.clear();
18008    }
18009
18010    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18011        self.diagnostics_enabled = false;
18012        self.dismiss_diagnostics(cx);
18013        self.inline_diagnostics_update = Task::ready(());
18014        self.inline_diagnostics.clear();
18015    }
18016
18017    pub fn disable_word_completions(&mut self) {
18018        self.word_completions_enabled = false;
18019    }
18020
18021    pub fn diagnostics_enabled(&self) -> bool {
18022        self.diagnostics_enabled && self.mode.is_full()
18023    }
18024
18025    pub fn inline_diagnostics_enabled(&self) -> bool {
18026        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18027    }
18028
18029    pub fn show_inline_diagnostics(&self) -> bool {
18030        self.show_inline_diagnostics
18031    }
18032
18033    pub fn toggle_inline_diagnostics(
18034        &mut self,
18035        _: &ToggleInlineDiagnostics,
18036        window: &mut Window,
18037        cx: &mut Context<Editor>,
18038    ) {
18039        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18040        self.refresh_inline_diagnostics(false, window, cx);
18041    }
18042
18043    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18044        self.diagnostics_max_severity = severity;
18045        self.display_map.update(cx, |display_map, _| {
18046            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18047        });
18048    }
18049
18050    pub fn toggle_diagnostics(
18051        &mut self,
18052        _: &ToggleDiagnostics,
18053        window: &mut Window,
18054        cx: &mut Context<Editor>,
18055    ) {
18056        if !self.diagnostics_enabled() {
18057            return;
18058        }
18059
18060        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18061            EditorSettings::get_global(cx)
18062                .diagnostics_max_severity
18063                .filter(|severity| severity != &DiagnosticSeverity::Off)
18064                .unwrap_or(DiagnosticSeverity::Hint)
18065        } else {
18066            DiagnosticSeverity::Off
18067        };
18068        self.set_max_diagnostics_severity(new_severity, cx);
18069        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18070            self.active_diagnostics = ActiveDiagnostic::None;
18071            self.inline_diagnostics_update = Task::ready(());
18072            self.inline_diagnostics.clear();
18073        } else {
18074            self.refresh_inline_diagnostics(false, window, cx);
18075        }
18076
18077        cx.notify();
18078    }
18079
18080    pub fn toggle_minimap(
18081        &mut self,
18082        _: &ToggleMinimap,
18083        window: &mut Window,
18084        cx: &mut Context<Editor>,
18085    ) {
18086        if self.supports_minimap(cx) {
18087            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18088        }
18089    }
18090
18091    fn refresh_inline_diagnostics(
18092        &mut self,
18093        debounce: bool,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) {
18097        let max_severity = ProjectSettings::get_global(cx)
18098            .diagnostics
18099            .inline
18100            .max_severity
18101            .unwrap_or(self.diagnostics_max_severity);
18102
18103        if !self.inline_diagnostics_enabled()
18104            || !self.diagnostics_enabled()
18105            || !self.show_inline_diagnostics
18106            || max_severity == DiagnosticSeverity::Off
18107        {
18108            self.inline_diagnostics_update = Task::ready(());
18109            self.inline_diagnostics.clear();
18110            return;
18111        }
18112
18113        let debounce_ms = ProjectSettings::get_global(cx)
18114            .diagnostics
18115            .inline
18116            .update_debounce_ms;
18117        let debounce = if debounce && debounce_ms > 0 {
18118            Some(Duration::from_millis(debounce_ms))
18119        } else {
18120            None
18121        };
18122        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18123            if let Some(debounce) = debounce {
18124                cx.background_executor().timer(debounce).await;
18125            }
18126            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18127                editor
18128                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18129                    .ok()
18130            }) else {
18131                return;
18132            };
18133
18134            let new_inline_diagnostics = cx
18135                .background_spawn(async move {
18136                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18137                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18138                        let message = diagnostic_entry
18139                            .diagnostic
18140                            .message
18141                            .split_once('\n')
18142                            .map(|(line, _)| line)
18143                            .map(SharedString::new)
18144                            .unwrap_or_else(|| {
18145                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18146                            });
18147                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18148                        let (Ok(i) | Err(i)) = inline_diagnostics
18149                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18150                        inline_diagnostics.insert(
18151                            i,
18152                            (
18153                                start_anchor,
18154                                InlineDiagnostic {
18155                                    message,
18156                                    group_id: diagnostic_entry.diagnostic.group_id,
18157                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18158                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18159                                    severity: diagnostic_entry.diagnostic.severity,
18160                                },
18161                            ),
18162                        );
18163                    }
18164                    inline_diagnostics
18165                })
18166                .await;
18167
18168            editor
18169                .update(cx, |editor, cx| {
18170                    editor.inline_diagnostics = new_inline_diagnostics;
18171                    cx.notify();
18172                })
18173                .ok();
18174        });
18175    }
18176
18177    fn pull_diagnostics(
18178        &mut self,
18179        buffer_id: Option<BufferId>,
18180        window: &Window,
18181        cx: &mut Context<Self>,
18182    ) -> Option<()> {
18183        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18184            return None;
18185        }
18186        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18187            .diagnostics
18188            .lsp_pull_diagnostics;
18189        if !pull_diagnostics_settings.enabled {
18190            return None;
18191        }
18192        let project = self.project()?.downgrade();
18193        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18194        let mut buffers = self.buffer.read(cx).all_buffers();
18195        buffers.retain(|buffer| {
18196            let buffer_id_to_retain = buffer.read(cx).remote_id();
18197            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18198                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18199        });
18200        if buffers.is_empty() {
18201            self.pull_diagnostics_task = Task::ready(());
18202            return None;
18203        }
18204
18205        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18206            cx.background_executor().timer(debounce).await;
18207
18208            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18209                buffers
18210                    .into_iter()
18211                    .filter_map(|buffer| {
18212                        project
18213                            .update(cx, |project, cx| {
18214                                project.lsp_store().update(cx, |lsp_store, cx| {
18215                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18216                                })
18217                            })
18218                            .ok()
18219                    })
18220                    .collect::<FuturesUnordered<_>>()
18221            }) else {
18222                return;
18223            };
18224
18225            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18226                match pull_task {
18227                    Ok(()) => {
18228                        if editor
18229                            .update_in(cx, |editor, window, cx| {
18230                                editor.update_diagnostics_state(window, cx);
18231                            })
18232                            .is_err()
18233                        {
18234                            return;
18235                        }
18236                    }
18237                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18238                }
18239            }
18240        });
18241
18242        Some(())
18243    }
18244
18245    pub fn set_selections_from_remote(
18246        &mut self,
18247        selections: Vec<Selection<Anchor>>,
18248        pending_selection: Option<Selection<Anchor>>,
18249        window: &mut Window,
18250        cx: &mut Context<Self>,
18251    ) {
18252        let old_cursor_position = self.selections.newest_anchor().head();
18253        self.selections
18254            .change_with(&self.display_snapshot(cx), |s| {
18255                s.select_anchors(selections);
18256                if let Some(pending_selection) = pending_selection {
18257                    s.set_pending(pending_selection, SelectMode::Character);
18258                } else {
18259                    s.clear_pending();
18260                }
18261            });
18262        self.selections_did_change(
18263            false,
18264            &old_cursor_position,
18265            SelectionEffects::default(),
18266            window,
18267            cx,
18268        );
18269    }
18270
18271    pub fn transact(
18272        &mut self,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18276    ) -> Option<TransactionId> {
18277        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18278            this.start_transaction_at(Instant::now(), window, cx);
18279            update(this, window, cx);
18280            this.end_transaction_at(Instant::now(), cx)
18281        })
18282    }
18283
18284    pub fn start_transaction_at(
18285        &mut self,
18286        now: Instant,
18287        window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) -> Option<TransactionId> {
18290        self.end_selection(window, cx);
18291        if let Some(tx_id) = self
18292            .buffer
18293            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18294        {
18295            self.selection_history
18296                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18297            cx.emit(EditorEvent::TransactionBegun {
18298                transaction_id: tx_id,
18299            });
18300            Some(tx_id)
18301        } else {
18302            None
18303        }
18304    }
18305
18306    pub fn end_transaction_at(
18307        &mut self,
18308        now: Instant,
18309        cx: &mut Context<Self>,
18310    ) -> Option<TransactionId> {
18311        if let Some(transaction_id) = self
18312            .buffer
18313            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18314        {
18315            if let Some((_, end_selections)) =
18316                self.selection_history.transaction_mut(transaction_id)
18317            {
18318                *end_selections = Some(self.selections.disjoint_anchors_arc());
18319            } else {
18320                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18321            }
18322
18323            cx.emit(EditorEvent::Edited { transaction_id });
18324            Some(transaction_id)
18325        } else {
18326            None
18327        }
18328    }
18329
18330    pub fn modify_transaction_selection_history(
18331        &mut self,
18332        transaction_id: TransactionId,
18333        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18334    ) -> bool {
18335        self.selection_history
18336            .transaction_mut(transaction_id)
18337            .map(modify)
18338            .is_some()
18339    }
18340
18341    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18342        if self.selection_mark_mode {
18343            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18344                s.move_with(|_, sel| {
18345                    sel.collapse_to(sel.head(), SelectionGoal::None);
18346                });
18347            })
18348        }
18349        self.selection_mark_mode = true;
18350        cx.notify();
18351    }
18352
18353    pub fn swap_selection_ends(
18354        &mut self,
18355        _: &actions::SwapSelectionEnds,
18356        window: &mut Window,
18357        cx: &mut Context<Self>,
18358    ) {
18359        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18360            s.move_with(|_, sel| {
18361                if sel.start != sel.end {
18362                    sel.reversed = !sel.reversed
18363                }
18364            });
18365        });
18366        self.request_autoscroll(Autoscroll::newest(), cx);
18367        cx.notify();
18368    }
18369
18370    pub fn toggle_focus(
18371        workspace: &mut Workspace,
18372        _: &actions::ToggleFocus,
18373        window: &mut Window,
18374        cx: &mut Context<Workspace>,
18375    ) {
18376        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18377            return;
18378        };
18379        workspace.activate_item(&item, true, true, window, cx);
18380    }
18381
18382    pub fn toggle_fold(
18383        &mut self,
18384        _: &actions::ToggleFold,
18385        window: &mut Window,
18386        cx: &mut Context<Self>,
18387    ) {
18388        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18389            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18390            let selection = self.selections.newest::<Point>(&display_map);
18391
18392            let range = if selection.is_empty() {
18393                let point = selection.head().to_display_point(&display_map);
18394                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18395                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18396                    .to_point(&display_map);
18397                start..end
18398            } else {
18399                selection.range()
18400            };
18401            if display_map.folds_in_range(range).next().is_some() {
18402                self.unfold_lines(&Default::default(), window, cx)
18403            } else {
18404                self.fold(&Default::default(), window, cx)
18405            }
18406        } else {
18407            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18408            let buffer_ids: HashSet<_> = self
18409                .selections
18410                .disjoint_anchor_ranges()
18411                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18412                .collect();
18413
18414            let should_unfold = buffer_ids
18415                .iter()
18416                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18417
18418            for buffer_id in buffer_ids {
18419                if should_unfold {
18420                    self.unfold_buffer(buffer_id, cx);
18421                } else {
18422                    self.fold_buffer(buffer_id, cx);
18423                }
18424            }
18425        }
18426    }
18427
18428    pub fn toggle_fold_recursive(
18429        &mut self,
18430        _: &actions::ToggleFoldRecursive,
18431        window: &mut Window,
18432        cx: &mut Context<Self>,
18433    ) {
18434        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18435
18436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18437        let range = if selection.is_empty() {
18438            let point = selection.head().to_display_point(&display_map);
18439            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18440            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18441                .to_point(&display_map);
18442            start..end
18443        } else {
18444            selection.range()
18445        };
18446        if display_map.folds_in_range(range).next().is_some() {
18447            self.unfold_recursive(&Default::default(), window, cx)
18448        } else {
18449            self.fold_recursive(&Default::default(), window, cx)
18450        }
18451    }
18452
18453    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18454        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18455            let mut to_fold = Vec::new();
18456            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18457            let selections = self.selections.all_adjusted(&display_map);
18458
18459            for selection in selections {
18460                let range = selection.range().sorted();
18461                let buffer_start_row = range.start.row;
18462
18463                if range.start.row != range.end.row {
18464                    let mut found = false;
18465                    let mut row = range.start.row;
18466                    while row <= range.end.row {
18467                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18468                        {
18469                            found = true;
18470                            row = crease.range().end.row + 1;
18471                            to_fold.push(crease);
18472                        } else {
18473                            row += 1
18474                        }
18475                    }
18476                    if found {
18477                        continue;
18478                    }
18479                }
18480
18481                for row in (0..=range.start.row).rev() {
18482                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18483                        && crease.range().end.row >= buffer_start_row
18484                    {
18485                        to_fold.push(crease);
18486                        if row <= range.start.row {
18487                            break;
18488                        }
18489                    }
18490                }
18491            }
18492
18493            self.fold_creases(to_fold, true, window, cx);
18494        } else {
18495            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18496            let buffer_ids = self
18497                .selections
18498                .disjoint_anchor_ranges()
18499                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18500                .collect::<HashSet<_>>();
18501            for buffer_id in buffer_ids {
18502                self.fold_buffer(buffer_id, cx);
18503            }
18504        }
18505    }
18506
18507    pub fn toggle_fold_all(
18508        &mut self,
18509        _: &actions::ToggleFoldAll,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        if self.buffer.read(cx).is_singleton() {
18514            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18515            let has_folds = display_map
18516                .folds_in_range(0..display_map.buffer_snapshot().len())
18517                .next()
18518                .is_some();
18519
18520            if has_folds {
18521                self.unfold_all(&actions::UnfoldAll, window, cx);
18522            } else {
18523                self.fold_all(&actions::FoldAll, window, cx);
18524            }
18525        } else {
18526            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18527            let should_unfold = buffer_ids
18528                .iter()
18529                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18530
18531            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18532                editor
18533                    .update_in(cx, |editor, _, cx| {
18534                        for buffer_id in buffer_ids {
18535                            if should_unfold {
18536                                editor.unfold_buffer(buffer_id, cx);
18537                            } else {
18538                                editor.fold_buffer(buffer_id, cx);
18539                            }
18540                        }
18541                    })
18542                    .ok();
18543            });
18544        }
18545    }
18546
18547    fn fold_at_level(
18548        &mut self,
18549        fold_at: &FoldAtLevel,
18550        window: &mut Window,
18551        cx: &mut Context<Self>,
18552    ) {
18553        if !self.buffer.read(cx).is_singleton() {
18554            return;
18555        }
18556
18557        let fold_at_level = fold_at.0;
18558        let snapshot = self.buffer.read(cx).snapshot(cx);
18559        let mut to_fold = Vec::new();
18560        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18561
18562        let row_ranges_to_keep: Vec<Range<u32>> = self
18563            .selections
18564            .all::<Point>(&self.display_snapshot(cx))
18565            .into_iter()
18566            .map(|sel| sel.start.row..sel.end.row)
18567            .collect();
18568
18569        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18570            while start_row < end_row {
18571                match self
18572                    .snapshot(window, cx)
18573                    .crease_for_buffer_row(MultiBufferRow(start_row))
18574                {
18575                    Some(crease) => {
18576                        let nested_start_row = crease.range().start.row + 1;
18577                        let nested_end_row = crease.range().end.row;
18578
18579                        if current_level < fold_at_level {
18580                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18581                        } else if current_level == fold_at_level {
18582                            // Fold iff there is no selection completely contained within the fold region
18583                            if !row_ranges_to_keep.iter().any(|selection| {
18584                                selection.end >= nested_start_row
18585                                    && selection.start <= nested_end_row
18586                            }) {
18587                                to_fold.push(crease);
18588                            }
18589                        }
18590
18591                        start_row = nested_end_row + 1;
18592                    }
18593                    None => start_row += 1,
18594                }
18595            }
18596        }
18597
18598        self.fold_creases(to_fold, true, window, cx);
18599    }
18600
18601    pub fn fold_at_level_1(
18602        &mut self,
18603        _: &actions::FoldAtLevel1,
18604        window: &mut Window,
18605        cx: &mut Context<Self>,
18606    ) {
18607        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18608    }
18609
18610    pub fn fold_at_level_2(
18611        &mut self,
18612        _: &actions::FoldAtLevel2,
18613        window: &mut Window,
18614        cx: &mut Context<Self>,
18615    ) {
18616        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18617    }
18618
18619    pub fn fold_at_level_3(
18620        &mut self,
18621        _: &actions::FoldAtLevel3,
18622        window: &mut Window,
18623        cx: &mut Context<Self>,
18624    ) {
18625        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18626    }
18627
18628    pub fn fold_at_level_4(
18629        &mut self,
18630        _: &actions::FoldAtLevel4,
18631        window: &mut Window,
18632        cx: &mut Context<Self>,
18633    ) {
18634        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18635    }
18636
18637    pub fn fold_at_level_5(
18638        &mut self,
18639        _: &actions::FoldAtLevel5,
18640        window: &mut Window,
18641        cx: &mut Context<Self>,
18642    ) {
18643        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18644    }
18645
18646    pub fn fold_at_level_6(
18647        &mut self,
18648        _: &actions::FoldAtLevel6,
18649        window: &mut Window,
18650        cx: &mut Context<Self>,
18651    ) {
18652        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18653    }
18654
18655    pub fn fold_at_level_7(
18656        &mut self,
18657        _: &actions::FoldAtLevel7,
18658        window: &mut Window,
18659        cx: &mut Context<Self>,
18660    ) {
18661        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18662    }
18663
18664    pub fn fold_at_level_8(
18665        &mut self,
18666        _: &actions::FoldAtLevel8,
18667        window: &mut Window,
18668        cx: &mut Context<Self>,
18669    ) {
18670        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18671    }
18672
18673    pub fn fold_at_level_9(
18674        &mut self,
18675        _: &actions::FoldAtLevel9,
18676        window: &mut Window,
18677        cx: &mut Context<Self>,
18678    ) {
18679        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18680    }
18681
18682    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18683        if self.buffer.read(cx).is_singleton() {
18684            let mut fold_ranges = Vec::new();
18685            let snapshot = self.buffer.read(cx).snapshot(cx);
18686
18687            for row in 0..snapshot.max_row().0 {
18688                if let Some(foldable_range) = self
18689                    .snapshot(window, cx)
18690                    .crease_for_buffer_row(MultiBufferRow(row))
18691                {
18692                    fold_ranges.push(foldable_range);
18693                }
18694            }
18695
18696            self.fold_creases(fold_ranges, true, window, cx);
18697        } else {
18698            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18699                editor
18700                    .update_in(cx, |editor, _, cx| {
18701                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18702                            editor.fold_buffer(buffer_id, cx);
18703                        }
18704                    })
18705                    .ok();
18706            });
18707        }
18708    }
18709
18710    pub fn fold_function_bodies(
18711        &mut self,
18712        _: &actions::FoldFunctionBodies,
18713        window: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) {
18716        let snapshot = self.buffer.read(cx).snapshot(cx);
18717
18718        let ranges = snapshot
18719            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18720            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18721            .collect::<Vec<_>>();
18722
18723        let creases = ranges
18724            .into_iter()
18725            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18726            .collect();
18727
18728        self.fold_creases(creases, true, window, cx);
18729    }
18730
18731    pub fn fold_recursive(
18732        &mut self,
18733        _: &actions::FoldRecursive,
18734        window: &mut Window,
18735        cx: &mut Context<Self>,
18736    ) {
18737        let mut to_fold = Vec::new();
18738        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18739        let selections = self.selections.all_adjusted(&display_map);
18740
18741        for selection in selections {
18742            let range = selection.range().sorted();
18743            let buffer_start_row = range.start.row;
18744
18745            if range.start.row != range.end.row {
18746                let mut found = false;
18747                for row in range.start.row..=range.end.row {
18748                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18749                        found = true;
18750                        to_fold.push(crease);
18751                    }
18752                }
18753                if found {
18754                    continue;
18755                }
18756            }
18757
18758            for row in (0..=range.start.row).rev() {
18759                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18760                    if crease.range().end.row >= buffer_start_row {
18761                        to_fold.push(crease);
18762                    } else {
18763                        break;
18764                    }
18765                }
18766            }
18767        }
18768
18769        self.fold_creases(to_fold, true, window, cx);
18770    }
18771
18772    pub fn fold_at(
18773        &mut self,
18774        buffer_row: MultiBufferRow,
18775        window: &mut Window,
18776        cx: &mut Context<Self>,
18777    ) {
18778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18779
18780        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18781            let autoscroll = self
18782                .selections
18783                .all::<Point>(&display_map)
18784                .iter()
18785                .any(|selection| crease.range().overlaps(&selection.range()));
18786
18787            self.fold_creases(vec![crease], autoscroll, window, cx);
18788        }
18789    }
18790
18791    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18792        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18793            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18794            let buffer = display_map.buffer_snapshot();
18795            let selections = self.selections.all::<Point>(&display_map);
18796            let ranges = selections
18797                .iter()
18798                .map(|s| {
18799                    let range = s.display_range(&display_map).sorted();
18800                    let mut start = range.start.to_point(&display_map);
18801                    let mut end = range.end.to_point(&display_map);
18802                    start.column = 0;
18803                    end.column = buffer.line_len(MultiBufferRow(end.row));
18804                    start..end
18805                })
18806                .collect::<Vec<_>>();
18807
18808            self.unfold_ranges(&ranges, true, true, cx);
18809        } else {
18810            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18811            let buffer_ids = self
18812                .selections
18813                .disjoint_anchor_ranges()
18814                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18815                .collect::<HashSet<_>>();
18816            for buffer_id in buffer_ids {
18817                self.unfold_buffer(buffer_id, cx);
18818            }
18819        }
18820    }
18821
18822    pub fn unfold_recursive(
18823        &mut self,
18824        _: &UnfoldRecursive,
18825        _window: &mut Window,
18826        cx: &mut Context<Self>,
18827    ) {
18828        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18829        let selections = self.selections.all::<Point>(&display_map);
18830        let ranges = selections
18831            .iter()
18832            .map(|s| {
18833                let mut range = s.display_range(&display_map).sorted();
18834                *range.start.column_mut() = 0;
18835                *range.end.column_mut() = display_map.line_len(range.end.row());
18836                let start = range.start.to_point(&display_map);
18837                let end = range.end.to_point(&display_map);
18838                start..end
18839            })
18840            .collect::<Vec<_>>();
18841
18842        self.unfold_ranges(&ranges, true, true, cx);
18843    }
18844
18845    pub fn unfold_at(
18846        &mut self,
18847        buffer_row: MultiBufferRow,
18848        _window: &mut Window,
18849        cx: &mut Context<Self>,
18850    ) {
18851        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18852
18853        let intersection_range = Point::new(buffer_row.0, 0)
18854            ..Point::new(
18855                buffer_row.0,
18856                display_map.buffer_snapshot().line_len(buffer_row),
18857            );
18858
18859        let autoscroll = self
18860            .selections
18861            .all::<Point>(&display_map)
18862            .iter()
18863            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18864
18865        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18866    }
18867
18868    pub fn unfold_all(
18869        &mut self,
18870        _: &actions::UnfoldAll,
18871        _window: &mut Window,
18872        cx: &mut Context<Self>,
18873    ) {
18874        if self.buffer.read(cx).is_singleton() {
18875            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18876            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18877        } else {
18878            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18879                editor
18880                    .update(cx, |editor, cx| {
18881                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18882                            editor.unfold_buffer(buffer_id, cx);
18883                        }
18884                    })
18885                    .ok();
18886            });
18887        }
18888    }
18889
18890    pub fn fold_selected_ranges(
18891        &mut self,
18892        _: &FoldSelectedRanges,
18893        window: &mut Window,
18894        cx: &mut Context<Self>,
18895    ) {
18896        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18897        let selections = self.selections.all_adjusted(&display_map);
18898        let ranges = selections
18899            .into_iter()
18900            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18901            .collect::<Vec<_>>();
18902        self.fold_creases(ranges, true, window, cx);
18903    }
18904
18905    pub fn fold_ranges<T: ToOffset + Clone>(
18906        &mut self,
18907        ranges: Vec<Range<T>>,
18908        auto_scroll: bool,
18909        window: &mut Window,
18910        cx: &mut Context<Self>,
18911    ) {
18912        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18913        let ranges = ranges
18914            .into_iter()
18915            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18916            .collect::<Vec<_>>();
18917        self.fold_creases(ranges, auto_scroll, window, cx);
18918    }
18919
18920    pub fn fold_creases<T: ToOffset + Clone>(
18921        &mut self,
18922        creases: Vec<Crease<T>>,
18923        auto_scroll: bool,
18924        _window: &mut Window,
18925        cx: &mut Context<Self>,
18926    ) {
18927        if creases.is_empty() {
18928            return;
18929        }
18930
18931        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18932
18933        if auto_scroll {
18934            self.request_autoscroll(Autoscroll::fit(), cx);
18935        }
18936
18937        cx.notify();
18938
18939        self.scrollbar_marker_state.dirty = true;
18940        self.folds_did_change(cx);
18941    }
18942
18943    /// Removes any folds whose ranges intersect any of the given ranges.
18944    pub fn unfold_ranges<T: ToOffset + Clone>(
18945        &mut self,
18946        ranges: &[Range<T>],
18947        inclusive: bool,
18948        auto_scroll: bool,
18949        cx: &mut Context<Self>,
18950    ) {
18951        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18952            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18953        });
18954        self.folds_did_change(cx);
18955    }
18956
18957    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18958        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18959            return;
18960        }
18961
18962        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18963        self.display_map.update(cx, |display_map, cx| {
18964            display_map.fold_buffers([buffer_id], cx)
18965        });
18966
18967        let snapshot = self.display_snapshot(cx);
18968        self.selections.change_with(&snapshot, |selections| {
18969            selections.remove_selections_from_buffer(buffer_id);
18970        });
18971
18972        cx.emit(EditorEvent::BufferFoldToggled {
18973            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18974            folded: true,
18975        });
18976        cx.notify();
18977    }
18978
18979    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18980        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18981            return;
18982        }
18983        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18984        self.display_map.update(cx, |display_map, cx| {
18985            display_map.unfold_buffers([buffer_id], cx);
18986        });
18987        cx.emit(EditorEvent::BufferFoldToggled {
18988            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18989            folded: false,
18990        });
18991        cx.notify();
18992    }
18993
18994    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18995        self.display_map.read(cx).is_buffer_folded(buffer)
18996    }
18997
18998    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18999        self.display_map.read(cx).folded_buffers()
19000    }
19001
19002    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19003        self.display_map.update(cx, |display_map, cx| {
19004            display_map.disable_header_for_buffer(buffer_id, cx);
19005        });
19006        cx.notify();
19007    }
19008
19009    /// Removes any folds with the given ranges.
19010    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19011        &mut self,
19012        ranges: &[Range<T>],
19013        type_id: TypeId,
19014        auto_scroll: bool,
19015        cx: &mut Context<Self>,
19016    ) {
19017        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19018            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19019        });
19020        self.folds_did_change(cx);
19021    }
19022
19023    fn remove_folds_with<T: ToOffset + Clone>(
19024        &mut self,
19025        ranges: &[Range<T>],
19026        auto_scroll: bool,
19027        cx: &mut Context<Self>,
19028        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19029    ) {
19030        if ranges.is_empty() {
19031            return;
19032        }
19033
19034        let mut buffers_affected = HashSet::default();
19035        let multi_buffer = self.buffer().read(cx);
19036        for range in ranges {
19037            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19038                buffers_affected.insert(buffer.read(cx).remote_id());
19039            };
19040        }
19041
19042        self.display_map.update(cx, update);
19043
19044        if auto_scroll {
19045            self.request_autoscroll(Autoscroll::fit(), cx);
19046        }
19047
19048        cx.notify();
19049        self.scrollbar_marker_state.dirty = true;
19050        self.active_indent_guides_state.dirty = true;
19051    }
19052
19053    pub fn update_renderer_widths(
19054        &mut self,
19055        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19056        cx: &mut Context<Self>,
19057    ) -> bool {
19058        self.display_map
19059            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19060    }
19061
19062    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19063        self.display_map.read(cx).fold_placeholder.clone()
19064    }
19065
19066    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19067        self.buffer.update(cx, |buffer, cx| {
19068            buffer.set_all_diff_hunks_expanded(cx);
19069        });
19070    }
19071
19072    pub fn expand_all_diff_hunks(
19073        &mut self,
19074        _: &ExpandAllDiffHunks,
19075        _window: &mut Window,
19076        cx: &mut Context<Self>,
19077    ) {
19078        self.buffer.update(cx, |buffer, cx| {
19079            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19080        });
19081    }
19082
19083    pub fn collapse_all_diff_hunks(
19084        &mut self,
19085        _: &CollapseAllDiffHunks,
19086        _window: &mut Window,
19087        cx: &mut Context<Self>,
19088    ) {
19089        self.buffer.update(cx, |buffer, cx| {
19090            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19091        });
19092    }
19093
19094    pub fn toggle_selected_diff_hunks(
19095        &mut self,
19096        _: &ToggleSelectedDiffHunks,
19097        _window: &mut Window,
19098        cx: &mut Context<Self>,
19099    ) {
19100        let ranges: Vec<_> = self
19101            .selections
19102            .disjoint_anchors()
19103            .iter()
19104            .map(|s| s.range())
19105            .collect();
19106        self.toggle_diff_hunks_in_ranges(ranges, cx);
19107    }
19108
19109    pub fn diff_hunks_in_ranges<'a>(
19110        &'a self,
19111        ranges: &'a [Range<Anchor>],
19112        buffer: &'a MultiBufferSnapshot,
19113    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19114        ranges.iter().flat_map(move |range| {
19115            let end_excerpt_id = range.end.excerpt_id;
19116            let range = range.to_point(buffer);
19117            let mut peek_end = range.end;
19118            if range.end.row < buffer.max_row().0 {
19119                peek_end = Point::new(range.end.row + 1, 0);
19120            }
19121            buffer
19122                .diff_hunks_in_range(range.start..peek_end)
19123                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19124        })
19125    }
19126
19127    pub fn has_stageable_diff_hunks_in_ranges(
19128        &self,
19129        ranges: &[Range<Anchor>],
19130        snapshot: &MultiBufferSnapshot,
19131    ) -> bool {
19132        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19133        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19134    }
19135
19136    pub fn toggle_staged_selected_diff_hunks(
19137        &mut self,
19138        _: &::git::ToggleStaged,
19139        _: &mut Window,
19140        cx: &mut Context<Self>,
19141    ) {
19142        let snapshot = self.buffer.read(cx).snapshot(cx);
19143        let ranges: Vec<_> = self
19144            .selections
19145            .disjoint_anchors()
19146            .iter()
19147            .map(|s| s.range())
19148            .collect();
19149        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19150        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19151    }
19152
19153    pub fn set_render_diff_hunk_controls(
19154        &mut self,
19155        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19156        cx: &mut Context<Self>,
19157    ) {
19158        self.render_diff_hunk_controls = render_diff_hunk_controls;
19159        cx.notify();
19160    }
19161
19162    pub fn stage_and_next(
19163        &mut self,
19164        _: &::git::StageAndNext,
19165        window: &mut Window,
19166        cx: &mut Context<Self>,
19167    ) {
19168        self.do_stage_or_unstage_and_next(true, window, cx);
19169    }
19170
19171    pub fn unstage_and_next(
19172        &mut self,
19173        _: &::git::UnstageAndNext,
19174        window: &mut Window,
19175        cx: &mut Context<Self>,
19176    ) {
19177        self.do_stage_or_unstage_and_next(false, window, cx);
19178    }
19179
19180    pub fn stage_or_unstage_diff_hunks(
19181        &mut self,
19182        stage: bool,
19183        ranges: Vec<Range<Anchor>>,
19184        cx: &mut Context<Self>,
19185    ) {
19186        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19187        cx.spawn(async move |this, cx| {
19188            task.await?;
19189            this.update(cx, |this, cx| {
19190                let snapshot = this.buffer.read(cx).snapshot(cx);
19191                let chunk_by = this
19192                    .diff_hunks_in_ranges(&ranges, &snapshot)
19193                    .chunk_by(|hunk| hunk.buffer_id);
19194                for (buffer_id, hunks) in &chunk_by {
19195                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19196                }
19197            })
19198        })
19199        .detach_and_log_err(cx);
19200    }
19201
19202    fn save_buffers_for_ranges_if_needed(
19203        &mut self,
19204        ranges: &[Range<Anchor>],
19205        cx: &mut Context<Editor>,
19206    ) -> Task<Result<()>> {
19207        let multibuffer = self.buffer.read(cx);
19208        let snapshot = multibuffer.read(cx);
19209        let buffer_ids: HashSet<_> = ranges
19210            .iter()
19211            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19212            .collect();
19213        drop(snapshot);
19214
19215        let mut buffers = HashSet::default();
19216        for buffer_id in buffer_ids {
19217            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19218                let buffer = buffer_entity.read(cx);
19219                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19220                {
19221                    buffers.insert(buffer_entity);
19222                }
19223            }
19224        }
19225
19226        if let Some(project) = &self.project {
19227            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19228        } else {
19229            Task::ready(Ok(()))
19230        }
19231    }
19232
19233    fn do_stage_or_unstage_and_next(
19234        &mut self,
19235        stage: bool,
19236        window: &mut Window,
19237        cx: &mut Context<Self>,
19238    ) {
19239        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19240
19241        if ranges.iter().any(|range| range.start != range.end) {
19242            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19243            return;
19244        }
19245
19246        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19247        let snapshot = self.snapshot(window, cx);
19248        let position = self
19249            .selections
19250            .newest::<Point>(&snapshot.display_snapshot)
19251            .head();
19252        let mut row = snapshot
19253            .buffer_snapshot()
19254            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19255            .find(|hunk| hunk.row_range.start.0 > position.row)
19256            .map(|hunk| hunk.row_range.start);
19257
19258        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19259        // Outside of the project diff editor, wrap around to the beginning.
19260        if !all_diff_hunks_expanded {
19261            row = row.or_else(|| {
19262                snapshot
19263                    .buffer_snapshot()
19264                    .diff_hunks_in_range(Point::zero()..position)
19265                    .find(|hunk| hunk.row_range.end.0 < position.row)
19266                    .map(|hunk| hunk.row_range.start)
19267            });
19268        }
19269
19270        if let Some(row) = row {
19271            let destination = Point::new(row.0, 0);
19272            let autoscroll = Autoscroll::center();
19273
19274            self.unfold_ranges(&[destination..destination], false, false, cx);
19275            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19276                s.select_ranges([destination..destination]);
19277            });
19278        }
19279    }
19280
19281    fn do_stage_or_unstage(
19282        &self,
19283        stage: bool,
19284        buffer_id: BufferId,
19285        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19286        cx: &mut App,
19287    ) -> Option<()> {
19288        let project = self.project()?;
19289        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19290        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19291        let buffer_snapshot = buffer.read(cx).snapshot();
19292        let file_exists = buffer_snapshot
19293            .file()
19294            .is_some_and(|file| file.disk_state().exists());
19295        diff.update(cx, |diff, cx| {
19296            diff.stage_or_unstage_hunks(
19297                stage,
19298                &hunks
19299                    .map(|hunk| buffer_diff::DiffHunk {
19300                        buffer_range: hunk.buffer_range,
19301                        diff_base_byte_range: hunk.diff_base_byte_range,
19302                        secondary_status: hunk.secondary_status,
19303                        range: Point::zero()..Point::zero(), // unused
19304                    })
19305                    .collect::<Vec<_>>(),
19306                &buffer_snapshot,
19307                file_exists,
19308                cx,
19309            )
19310        });
19311        None
19312    }
19313
19314    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19315        let ranges: Vec<_> = self
19316            .selections
19317            .disjoint_anchors()
19318            .iter()
19319            .map(|s| s.range())
19320            .collect();
19321        self.buffer
19322            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19323    }
19324
19325    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19326        self.buffer.update(cx, |buffer, cx| {
19327            let ranges = vec![Anchor::min()..Anchor::max()];
19328            if !buffer.all_diff_hunks_expanded()
19329                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19330            {
19331                buffer.collapse_diff_hunks(ranges, cx);
19332                true
19333            } else {
19334                false
19335            }
19336        })
19337    }
19338
19339    fn toggle_diff_hunks_in_ranges(
19340        &mut self,
19341        ranges: Vec<Range<Anchor>>,
19342        cx: &mut Context<Editor>,
19343    ) {
19344        self.buffer.update(cx, |buffer, cx| {
19345            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19346            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19347        })
19348    }
19349
19350    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19351        self.buffer.update(cx, |buffer, cx| {
19352            let snapshot = buffer.snapshot(cx);
19353            let excerpt_id = range.end.excerpt_id;
19354            let point_range = range.to_point(&snapshot);
19355            let expand = !buffer.single_hunk_is_expanded(range, cx);
19356            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19357        })
19358    }
19359
19360    pub(crate) fn apply_all_diff_hunks(
19361        &mut self,
19362        _: &ApplyAllDiffHunks,
19363        window: &mut Window,
19364        cx: &mut Context<Self>,
19365    ) {
19366        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19367
19368        let buffers = self.buffer.read(cx).all_buffers();
19369        for branch_buffer in buffers {
19370            branch_buffer.update(cx, |branch_buffer, cx| {
19371                branch_buffer.merge_into_base(Vec::new(), cx);
19372            });
19373        }
19374
19375        if let Some(project) = self.project.clone() {
19376            self.save(
19377                SaveOptions {
19378                    format: true,
19379                    autosave: false,
19380                },
19381                project,
19382                window,
19383                cx,
19384            )
19385            .detach_and_log_err(cx);
19386        }
19387    }
19388
19389    pub(crate) fn apply_selected_diff_hunks(
19390        &mut self,
19391        _: &ApplyDiffHunk,
19392        window: &mut Window,
19393        cx: &mut Context<Self>,
19394    ) {
19395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19396        let snapshot = self.snapshot(window, cx);
19397        let hunks = snapshot.hunks_for_ranges(
19398            self.selections
19399                .all(&snapshot.display_snapshot)
19400                .into_iter()
19401                .map(|selection| selection.range()),
19402        );
19403        let mut ranges_by_buffer = HashMap::default();
19404        self.transact(window, cx, |editor, _window, cx| {
19405            for hunk in hunks {
19406                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19407                    ranges_by_buffer
19408                        .entry(buffer.clone())
19409                        .or_insert_with(Vec::new)
19410                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19411                }
19412            }
19413
19414            for (buffer, ranges) in ranges_by_buffer {
19415                buffer.update(cx, |buffer, cx| {
19416                    buffer.merge_into_base(ranges, cx);
19417                });
19418            }
19419        });
19420
19421        if let Some(project) = self.project.clone() {
19422            self.save(
19423                SaveOptions {
19424                    format: true,
19425                    autosave: false,
19426                },
19427                project,
19428                window,
19429                cx,
19430            )
19431            .detach_and_log_err(cx);
19432        }
19433    }
19434
19435    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19436        if hovered != self.gutter_hovered {
19437            self.gutter_hovered = hovered;
19438            cx.notify();
19439        }
19440    }
19441
19442    pub fn insert_blocks(
19443        &mut self,
19444        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19445        autoscroll: Option<Autoscroll>,
19446        cx: &mut Context<Self>,
19447    ) -> Vec<CustomBlockId> {
19448        let blocks = self
19449            .display_map
19450            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19451        if let Some(autoscroll) = autoscroll {
19452            self.request_autoscroll(autoscroll, cx);
19453        }
19454        cx.notify();
19455        blocks
19456    }
19457
19458    pub fn resize_blocks(
19459        &mut self,
19460        heights: HashMap<CustomBlockId, u32>,
19461        autoscroll: Option<Autoscroll>,
19462        cx: &mut Context<Self>,
19463    ) {
19464        self.display_map
19465            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19466        if let Some(autoscroll) = autoscroll {
19467            self.request_autoscroll(autoscroll, cx);
19468        }
19469        cx.notify();
19470    }
19471
19472    pub fn replace_blocks(
19473        &mut self,
19474        renderers: HashMap<CustomBlockId, RenderBlock>,
19475        autoscroll: Option<Autoscroll>,
19476        cx: &mut Context<Self>,
19477    ) {
19478        self.display_map
19479            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19480        if let Some(autoscroll) = autoscroll {
19481            self.request_autoscroll(autoscroll, cx);
19482        }
19483        cx.notify();
19484    }
19485
19486    pub fn remove_blocks(
19487        &mut self,
19488        block_ids: HashSet<CustomBlockId>,
19489        autoscroll: Option<Autoscroll>,
19490        cx: &mut Context<Self>,
19491    ) {
19492        self.display_map.update(cx, |display_map, cx| {
19493            display_map.remove_blocks(block_ids, cx)
19494        });
19495        if let Some(autoscroll) = autoscroll {
19496            self.request_autoscroll(autoscroll, cx);
19497        }
19498        cx.notify();
19499    }
19500
19501    pub fn row_for_block(
19502        &self,
19503        block_id: CustomBlockId,
19504        cx: &mut Context<Self>,
19505    ) -> Option<DisplayRow> {
19506        self.display_map
19507            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19508    }
19509
19510    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19511        self.focused_block = Some(focused_block);
19512    }
19513
19514    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19515        self.focused_block.take()
19516    }
19517
19518    pub fn insert_creases(
19519        &mut self,
19520        creases: impl IntoIterator<Item = Crease<Anchor>>,
19521        cx: &mut Context<Self>,
19522    ) -> Vec<CreaseId> {
19523        self.display_map
19524            .update(cx, |map, cx| map.insert_creases(creases, cx))
19525    }
19526
19527    pub fn remove_creases(
19528        &mut self,
19529        ids: impl IntoIterator<Item = CreaseId>,
19530        cx: &mut Context<Self>,
19531    ) -> Vec<(CreaseId, Range<Anchor>)> {
19532        self.display_map
19533            .update(cx, |map, cx| map.remove_creases(ids, cx))
19534    }
19535
19536    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19537        self.display_map
19538            .update(cx, |map, cx| map.snapshot(cx))
19539            .longest_row()
19540    }
19541
19542    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19543        self.display_map
19544            .update(cx, |map, cx| map.snapshot(cx))
19545            .max_point()
19546    }
19547
19548    pub fn text(&self, cx: &App) -> String {
19549        self.buffer.read(cx).read(cx).text()
19550    }
19551
19552    pub fn is_empty(&self, cx: &App) -> bool {
19553        self.buffer.read(cx).read(cx).is_empty()
19554    }
19555
19556    pub fn text_option(&self, cx: &App) -> Option<String> {
19557        let text = self.text(cx);
19558        let text = text.trim();
19559
19560        if text.is_empty() {
19561            return None;
19562        }
19563
19564        Some(text.to_string())
19565    }
19566
19567    pub fn set_text(
19568        &mut self,
19569        text: impl Into<Arc<str>>,
19570        window: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) {
19573        self.transact(window, cx, |this, _, cx| {
19574            this.buffer
19575                .read(cx)
19576                .as_singleton()
19577                .expect("you can only call set_text on editors for singleton buffers")
19578                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19579        });
19580    }
19581
19582    pub fn display_text(&self, cx: &mut App) -> String {
19583        self.display_map
19584            .update(cx, |map, cx| map.snapshot(cx))
19585            .text()
19586    }
19587
19588    fn create_minimap(
19589        &self,
19590        minimap_settings: MinimapSettings,
19591        window: &mut Window,
19592        cx: &mut Context<Self>,
19593    ) -> Option<Entity<Self>> {
19594        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19595            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19596    }
19597
19598    fn initialize_new_minimap(
19599        &self,
19600        minimap_settings: MinimapSettings,
19601        window: &mut Window,
19602        cx: &mut Context<Self>,
19603    ) -> Entity<Self> {
19604        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19605
19606        let mut minimap = Editor::new_internal(
19607            EditorMode::Minimap {
19608                parent: cx.weak_entity(),
19609            },
19610            self.buffer.clone(),
19611            None,
19612            Some(self.display_map.clone()),
19613            window,
19614            cx,
19615        );
19616        minimap.scroll_manager.clone_state(&self.scroll_manager);
19617        minimap.set_text_style_refinement(TextStyleRefinement {
19618            font_size: Some(MINIMAP_FONT_SIZE),
19619            font_weight: Some(MINIMAP_FONT_WEIGHT),
19620            ..Default::default()
19621        });
19622        minimap.update_minimap_configuration(minimap_settings, cx);
19623        cx.new(|_| minimap)
19624    }
19625
19626    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19627        let current_line_highlight = minimap_settings
19628            .current_line_highlight
19629            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19630        self.set_current_line_highlight(Some(current_line_highlight));
19631    }
19632
19633    pub fn minimap(&self) -> Option<&Entity<Self>> {
19634        self.minimap
19635            .as_ref()
19636            .filter(|_| self.minimap_visibility.visible())
19637    }
19638
19639    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19640        let mut wrap_guides = smallvec![];
19641
19642        if self.show_wrap_guides == Some(false) {
19643            return wrap_guides;
19644        }
19645
19646        let settings = self.buffer.read(cx).language_settings(cx);
19647        if settings.show_wrap_guides {
19648            match self.soft_wrap_mode(cx) {
19649                SoftWrap::Column(soft_wrap) => {
19650                    wrap_guides.push((soft_wrap as usize, true));
19651                }
19652                SoftWrap::Bounded(soft_wrap) => {
19653                    wrap_guides.push((soft_wrap as usize, true));
19654                }
19655                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19656            }
19657            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19658        }
19659
19660        wrap_guides
19661    }
19662
19663    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19664        let settings = self.buffer.read(cx).language_settings(cx);
19665        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19666        match mode {
19667            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19668                SoftWrap::None
19669            }
19670            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19671            language_settings::SoftWrap::PreferredLineLength => {
19672                SoftWrap::Column(settings.preferred_line_length)
19673            }
19674            language_settings::SoftWrap::Bounded => {
19675                SoftWrap::Bounded(settings.preferred_line_length)
19676            }
19677        }
19678    }
19679
19680    pub fn set_soft_wrap_mode(
19681        &mut self,
19682        mode: language_settings::SoftWrap,
19683
19684        cx: &mut Context<Self>,
19685    ) {
19686        self.soft_wrap_mode_override = Some(mode);
19687        cx.notify();
19688    }
19689
19690    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19691        self.hard_wrap = hard_wrap;
19692        cx.notify();
19693    }
19694
19695    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19696        self.text_style_refinement = Some(style);
19697    }
19698
19699    /// called by the Element so we know what style we were most recently rendered with.
19700    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19701        // We intentionally do not inform the display map about the minimap style
19702        // so that wrapping is not recalculated and stays consistent for the editor
19703        // and its linked minimap.
19704        if !self.mode.is_minimap() {
19705            let font = style.text.font();
19706            let font_size = style.text.font_size.to_pixels(window.rem_size());
19707            let display_map = self
19708                .placeholder_display_map
19709                .as_ref()
19710                .filter(|_| self.is_empty(cx))
19711                .unwrap_or(&self.display_map);
19712
19713            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19714        }
19715        self.style = Some(style);
19716    }
19717
19718    pub fn style(&self) -> Option<&EditorStyle> {
19719        self.style.as_ref()
19720    }
19721
19722    // Called by the element. This method is not designed to be called outside of the editor
19723    // element's layout code because it does not notify when rewrapping is computed synchronously.
19724    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19725        if self.is_empty(cx) {
19726            self.placeholder_display_map
19727                .as_ref()
19728                .map_or(false, |display_map| {
19729                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19730                })
19731        } else {
19732            self.display_map
19733                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19734        }
19735    }
19736
19737    pub fn set_soft_wrap(&mut self) {
19738        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19739    }
19740
19741    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19742        if self.soft_wrap_mode_override.is_some() {
19743            self.soft_wrap_mode_override.take();
19744        } else {
19745            let soft_wrap = match self.soft_wrap_mode(cx) {
19746                SoftWrap::GitDiff => return,
19747                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19748                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19749                    language_settings::SoftWrap::None
19750                }
19751            };
19752            self.soft_wrap_mode_override = Some(soft_wrap);
19753        }
19754        cx.notify();
19755    }
19756
19757    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19758        let Some(workspace) = self.workspace() else {
19759            return;
19760        };
19761        let fs = workspace.read(cx).app_state().fs.clone();
19762        let current_show = TabBarSettings::get_global(cx).show;
19763        update_settings_file(fs, cx, move |setting, _| {
19764            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19765        });
19766    }
19767
19768    pub fn toggle_indent_guides(
19769        &mut self,
19770        _: &ToggleIndentGuides,
19771        _: &mut Window,
19772        cx: &mut Context<Self>,
19773    ) {
19774        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19775            self.buffer
19776                .read(cx)
19777                .language_settings(cx)
19778                .indent_guides
19779                .enabled
19780        });
19781        self.show_indent_guides = Some(!currently_enabled);
19782        cx.notify();
19783    }
19784
19785    fn should_show_indent_guides(&self) -> Option<bool> {
19786        self.show_indent_guides
19787    }
19788
19789    pub fn toggle_line_numbers(
19790        &mut self,
19791        _: &ToggleLineNumbers,
19792        _: &mut Window,
19793        cx: &mut Context<Self>,
19794    ) {
19795        let mut editor_settings = EditorSettings::get_global(cx).clone();
19796        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19797        EditorSettings::override_global(editor_settings, cx);
19798    }
19799
19800    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19801        if let Some(show_line_numbers) = self.show_line_numbers {
19802            return show_line_numbers;
19803        }
19804        EditorSettings::get_global(cx).gutter.line_numbers
19805    }
19806
19807    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19808        match (
19809            self.use_relative_line_numbers,
19810            EditorSettings::get_global(cx).relative_line_numbers,
19811        ) {
19812            (None, setting) => setting,
19813            (Some(false), _) => RelativeLineNumbers::Disabled,
19814            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19815            (Some(true), _) => RelativeLineNumbers::Enabled,
19816        }
19817    }
19818
19819    pub fn toggle_relative_line_numbers(
19820        &mut self,
19821        _: &ToggleRelativeLineNumbers,
19822        _: &mut Window,
19823        cx: &mut Context<Self>,
19824    ) {
19825        let is_relative = self.relative_line_numbers(cx);
19826        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19827    }
19828
19829    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19830        self.use_relative_line_numbers = is_relative;
19831        cx.notify();
19832    }
19833
19834    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19835        self.show_gutter = show_gutter;
19836        cx.notify();
19837    }
19838
19839    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19840        self.show_scrollbars = ScrollbarAxes {
19841            horizontal: show,
19842            vertical: show,
19843        };
19844        cx.notify();
19845    }
19846
19847    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19848        self.show_scrollbars.vertical = show;
19849        cx.notify();
19850    }
19851
19852    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19853        self.show_scrollbars.horizontal = show;
19854        cx.notify();
19855    }
19856
19857    pub fn set_minimap_visibility(
19858        &mut self,
19859        minimap_visibility: MinimapVisibility,
19860        window: &mut Window,
19861        cx: &mut Context<Self>,
19862    ) {
19863        if self.minimap_visibility != minimap_visibility {
19864            if minimap_visibility.visible() && self.minimap.is_none() {
19865                let minimap_settings = EditorSettings::get_global(cx).minimap;
19866                self.minimap =
19867                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19868            }
19869            self.minimap_visibility = minimap_visibility;
19870            cx.notify();
19871        }
19872    }
19873
19874    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19875        self.set_show_scrollbars(false, cx);
19876        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19877    }
19878
19879    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19880        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19881    }
19882
19883    /// Normally the text in full mode and auto height editors is padded on the
19884    /// left side by roughly half a character width for improved hit testing.
19885    ///
19886    /// Use this method to disable this for cases where this is not wanted (e.g.
19887    /// if you want to align the editor text with some other text above or below)
19888    /// or if you want to add this padding to single-line editors.
19889    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19890        self.offset_content = offset_content;
19891        cx.notify();
19892    }
19893
19894    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19895        self.show_line_numbers = Some(show_line_numbers);
19896        cx.notify();
19897    }
19898
19899    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19900        self.disable_expand_excerpt_buttons = true;
19901        cx.notify();
19902    }
19903
19904    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19905        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19906        cx.notify();
19907    }
19908
19909    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19910        self.show_code_actions = Some(show_code_actions);
19911        cx.notify();
19912    }
19913
19914    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19915        self.show_runnables = Some(show_runnables);
19916        cx.notify();
19917    }
19918
19919    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19920        self.show_breakpoints = Some(show_breakpoints);
19921        cx.notify();
19922    }
19923
19924    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19925        if self.display_map.read(cx).masked != masked {
19926            self.display_map.update(cx, |map, _| map.masked = masked);
19927        }
19928        cx.notify()
19929    }
19930
19931    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19932        self.show_wrap_guides = Some(show_wrap_guides);
19933        cx.notify();
19934    }
19935
19936    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19937        self.show_indent_guides = Some(show_indent_guides);
19938        cx.notify();
19939    }
19940
19941    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19942        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19943            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19944                && let Some(dir) = file.abs_path(cx).parent()
19945            {
19946                return Some(dir.to_owned());
19947            }
19948        }
19949
19950        None
19951    }
19952
19953    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19954        self.active_excerpt(cx)?
19955            .1
19956            .read(cx)
19957            .file()
19958            .and_then(|f| f.as_local())
19959    }
19960
19961    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19962        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19963            let buffer = buffer.read(cx);
19964            if let Some(project_path) = buffer.project_path(cx) {
19965                let project = self.project()?.read(cx);
19966                project.absolute_path(&project_path, cx)
19967            } else {
19968                buffer
19969                    .file()
19970                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19971            }
19972        })
19973    }
19974
19975    pub fn reveal_in_finder(
19976        &mut self,
19977        _: &RevealInFileManager,
19978        _window: &mut Window,
19979        cx: &mut Context<Self>,
19980    ) {
19981        if let Some(target) = self.target_file(cx) {
19982            cx.reveal_path(&target.abs_path(cx));
19983        }
19984    }
19985
19986    pub fn copy_path(
19987        &mut self,
19988        _: &zed_actions::workspace::CopyPath,
19989        _window: &mut Window,
19990        cx: &mut Context<Self>,
19991    ) {
19992        if let Some(path) = self.target_file_abs_path(cx)
19993            && let Some(path) = path.to_str()
19994        {
19995            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19996        } else {
19997            cx.propagate();
19998        }
19999    }
20000
20001    pub fn copy_relative_path(
20002        &mut self,
20003        _: &zed_actions::workspace::CopyRelativePath,
20004        _window: &mut Window,
20005        cx: &mut Context<Self>,
20006    ) {
20007        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20008            let project = self.project()?.read(cx);
20009            let path = buffer.read(cx).file()?.path();
20010            let path = path.display(project.path_style(cx));
20011            Some(path)
20012        }) {
20013            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20014        } else {
20015            cx.propagate();
20016        }
20017    }
20018
20019    /// Returns the project path for the editor's buffer, if any buffer is
20020    /// opened in the editor.
20021    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20022        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20023            buffer.read(cx).project_path(cx)
20024        } else {
20025            None
20026        }
20027    }
20028
20029    // Returns true if the editor handled a go-to-line request
20030    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20031        maybe!({
20032            let breakpoint_store = self.breakpoint_store.as_ref()?;
20033
20034            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20035            else {
20036                self.clear_row_highlights::<ActiveDebugLine>();
20037                return None;
20038            };
20039
20040            let position = active_stack_frame.position;
20041            let buffer_id = position.buffer_id?;
20042            let snapshot = self
20043                .project
20044                .as_ref()?
20045                .read(cx)
20046                .buffer_for_id(buffer_id, cx)?
20047                .read(cx)
20048                .snapshot();
20049
20050            let mut handled = false;
20051            for (id, ExcerptRange { context, .. }) in
20052                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20053            {
20054                if context.start.cmp(&position, &snapshot).is_ge()
20055                    || context.end.cmp(&position, &snapshot).is_lt()
20056                {
20057                    continue;
20058                }
20059                let snapshot = self.buffer.read(cx).snapshot(cx);
20060                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20061
20062                handled = true;
20063                self.clear_row_highlights::<ActiveDebugLine>();
20064
20065                self.go_to_line::<ActiveDebugLine>(
20066                    multibuffer_anchor,
20067                    Some(cx.theme().colors().editor_debugger_active_line_background),
20068                    window,
20069                    cx,
20070                );
20071
20072                cx.notify();
20073            }
20074
20075            handled.then_some(())
20076        })
20077        .is_some()
20078    }
20079
20080    pub fn copy_file_name_without_extension(
20081        &mut self,
20082        _: &CopyFileNameWithoutExtension,
20083        _: &mut Window,
20084        cx: &mut Context<Self>,
20085    ) {
20086        if let Some(file) = self.target_file(cx)
20087            && let Some(file_stem) = file.path().file_stem()
20088        {
20089            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20090        }
20091    }
20092
20093    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20094        if let Some(file) = self.target_file(cx)
20095            && let Some(name) = file.path().file_name()
20096        {
20097            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20098        }
20099    }
20100
20101    pub fn toggle_git_blame(
20102        &mut self,
20103        _: &::git::Blame,
20104        window: &mut Window,
20105        cx: &mut Context<Self>,
20106    ) {
20107        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20108
20109        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20110            self.start_git_blame(true, window, cx);
20111        }
20112
20113        cx.notify();
20114    }
20115
20116    pub fn toggle_git_blame_inline(
20117        &mut self,
20118        _: &ToggleGitBlameInline,
20119        window: &mut Window,
20120        cx: &mut Context<Self>,
20121    ) {
20122        self.toggle_git_blame_inline_internal(true, window, cx);
20123        cx.notify();
20124    }
20125
20126    pub fn open_git_blame_commit(
20127        &mut self,
20128        _: &OpenGitBlameCommit,
20129        window: &mut Window,
20130        cx: &mut Context<Self>,
20131    ) {
20132        self.open_git_blame_commit_internal(window, cx);
20133    }
20134
20135    fn open_git_blame_commit_internal(
20136        &mut self,
20137        window: &mut Window,
20138        cx: &mut Context<Self>,
20139    ) -> Option<()> {
20140        let blame = self.blame.as_ref()?;
20141        let snapshot = self.snapshot(window, cx);
20142        let cursor = self
20143            .selections
20144            .newest::<Point>(&snapshot.display_snapshot)
20145            .head();
20146        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20147        let (_, blame_entry) = blame
20148            .update(cx, |blame, cx| {
20149                blame
20150                    .blame_for_rows(
20151                        &[RowInfo {
20152                            buffer_id: Some(buffer.remote_id()),
20153                            buffer_row: Some(point.row),
20154                            ..Default::default()
20155                        }],
20156                        cx,
20157                    )
20158                    .next()
20159            })
20160            .flatten()?;
20161        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20162        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20163        let workspace = self.workspace()?.downgrade();
20164        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20165        None
20166    }
20167
20168    pub fn git_blame_inline_enabled(&self) -> bool {
20169        self.git_blame_inline_enabled
20170    }
20171
20172    pub fn toggle_selection_menu(
20173        &mut self,
20174        _: &ToggleSelectionMenu,
20175        _: &mut Window,
20176        cx: &mut Context<Self>,
20177    ) {
20178        self.show_selection_menu = self
20179            .show_selection_menu
20180            .map(|show_selections_menu| !show_selections_menu)
20181            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20182
20183        cx.notify();
20184    }
20185
20186    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20187        self.show_selection_menu
20188            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20189    }
20190
20191    fn start_git_blame(
20192        &mut self,
20193        user_triggered: bool,
20194        window: &mut Window,
20195        cx: &mut Context<Self>,
20196    ) {
20197        if let Some(project) = self.project() {
20198            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20199                && buffer.read(cx).file().is_none()
20200            {
20201                return;
20202            }
20203
20204            let focused = self.focus_handle(cx).contains_focused(window, cx);
20205
20206            let project = project.clone();
20207            let blame = cx
20208                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20209            self.blame_subscription =
20210                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20211            self.blame = Some(blame);
20212        }
20213    }
20214
20215    fn toggle_git_blame_inline_internal(
20216        &mut self,
20217        user_triggered: bool,
20218        window: &mut Window,
20219        cx: &mut Context<Self>,
20220    ) {
20221        if self.git_blame_inline_enabled {
20222            self.git_blame_inline_enabled = false;
20223            self.show_git_blame_inline = false;
20224            self.show_git_blame_inline_delay_task.take();
20225        } else {
20226            self.git_blame_inline_enabled = true;
20227            self.start_git_blame_inline(user_triggered, window, cx);
20228        }
20229
20230        cx.notify();
20231    }
20232
20233    fn start_git_blame_inline(
20234        &mut self,
20235        user_triggered: bool,
20236        window: &mut Window,
20237        cx: &mut Context<Self>,
20238    ) {
20239        self.start_git_blame(user_triggered, window, cx);
20240
20241        if ProjectSettings::get_global(cx)
20242            .git
20243            .inline_blame_delay()
20244            .is_some()
20245        {
20246            self.start_inline_blame_timer(window, cx);
20247        } else {
20248            self.show_git_blame_inline = true
20249        }
20250    }
20251
20252    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20253        self.blame.as_ref()
20254    }
20255
20256    pub fn show_git_blame_gutter(&self) -> bool {
20257        self.show_git_blame_gutter
20258    }
20259
20260    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20261        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20262    }
20263
20264    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20265        self.show_git_blame_inline
20266            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20267            && !self.newest_selection_head_on_empty_line(cx)
20268            && self.has_blame_entries(cx)
20269    }
20270
20271    fn has_blame_entries(&self, cx: &App) -> bool {
20272        self.blame()
20273            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20274    }
20275
20276    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20277        let cursor_anchor = self.selections.newest_anchor().head();
20278
20279        let snapshot = self.buffer.read(cx).snapshot(cx);
20280        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20281
20282        snapshot.line_len(buffer_row) == 0
20283    }
20284
20285    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20286        let buffer_and_selection = maybe!({
20287            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20288            let selection_range = selection.range();
20289
20290            let multi_buffer = self.buffer().read(cx);
20291            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20292            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20293
20294            let (buffer, range, _) = if selection.reversed {
20295                buffer_ranges.first()
20296            } else {
20297                buffer_ranges.last()
20298            }?;
20299
20300            let selection = text::ToPoint::to_point(&range.start, buffer).row
20301                ..text::ToPoint::to_point(&range.end, buffer).row;
20302            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20303        });
20304
20305        let Some((buffer, selection)) = buffer_and_selection else {
20306            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20307        };
20308
20309        let Some(project) = self.project() else {
20310            return Task::ready(Err(anyhow!("editor does not have project")));
20311        };
20312
20313        project.update(cx, |project, cx| {
20314            project.get_permalink_to_line(&buffer, selection, cx)
20315        })
20316    }
20317
20318    pub fn copy_permalink_to_line(
20319        &mut self,
20320        _: &CopyPermalinkToLine,
20321        window: &mut Window,
20322        cx: &mut Context<Self>,
20323    ) {
20324        let permalink_task = self.get_permalink_to_line(cx);
20325        let workspace = self.workspace();
20326
20327        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20328            Ok(permalink) => {
20329                cx.update(|_, cx| {
20330                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20331                })
20332                .ok();
20333            }
20334            Err(err) => {
20335                let message = format!("Failed to copy permalink: {err}");
20336
20337                anyhow::Result::<()>::Err(err).log_err();
20338
20339                if let Some(workspace) = workspace {
20340                    workspace
20341                        .update_in(cx, |workspace, _, cx| {
20342                            struct CopyPermalinkToLine;
20343
20344                            workspace.show_toast(
20345                                Toast::new(
20346                                    NotificationId::unique::<CopyPermalinkToLine>(),
20347                                    message,
20348                                ),
20349                                cx,
20350                            )
20351                        })
20352                        .ok();
20353                }
20354            }
20355        })
20356        .detach();
20357    }
20358
20359    pub fn copy_file_location(
20360        &mut self,
20361        _: &CopyFileLocation,
20362        _: &mut Window,
20363        cx: &mut Context<Self>,
20364    ) {
20365        let selection = self
20366            .selections
20367            .newest::<Point>(&self.display_snapshot(cx))
20368            .start
20369            .row
20370            + 1;
20371        if let Some(file) = self.target_file(cx) {
20372            let path = file.path().display(file.path_style(cx));
20373            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20374        }
20375    }
20376
20377    pub fn open_permalink_to_line(
20378        &mut self,
20379        _: &OpenPermalinkToLine,
20380        window: &mut Window,
20381        cx: &mut Context<Self>,
20382    ) {
20383        let permalink_task = self.get_permalink_to_line(cx);
20384        let workspace = self.workspace();
20385
20386        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20387            Ok(permalink) => {
20388                cx.update(|_, cx| {
20389                    cx.open_url(permalink.as_ref());
20390                })
20391                .ok();
20392            }
20393            Err(err) => {
20394                let message = format!("Failed to open permalink: {err}");
20395
20396                anyhow::Result::<()>::Err(err).log_err();
20397
20398                if let Some(workspace) = workspace {
20399                    workspace
20400                        .update(cx, |workspace, cx| {
20401                            struct OpenPermalinkToLine;
20402
20403                            workspace.show_toast(
20404                                Toast::new(
20405                                    NotificationId::unique::<OpenPermalinkToLine>(),
20406                                    message,
20407                                ),
20408                                cx,
20409                            )
20410                        })
20411                        .ok();
20412                }
20413            }
20414        })
20415        .detach();
20416    }
20417
20418    pub fn insert_uuid_v4(
20419        &mut self,
20420        _: &InsertUuidV4,
20421        window: &mut Window,
20422        cx: &mut Context<Self>,
20423    ) {
20424        self.insert_uuid(UuidVersion::V4, window, cx);
20425    }
20426
20427    pub fn insert_uuid_v7(
20428        &mut self,
20429        _: &InsertUuidV7,
20430        window: &mut Window,
20431        cx: &mut Context<Self>,
20432    ) {
20433        self.insert_uuid(UuidVersion::V7, window, cx);
20434    }
20435
20436    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20437        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20438        self.transact(window, cx, |this, window, cx| {
20439            let edits = this
20440                .selections
20441                .all::<Point>(&this.display_snapshot(cx))
20442                .into_iter()
20443                .map(|selection| {
20444                    let uuid = match version {
20445                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20446                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20447                    };
20448
20449                    (selection.range(), uuid.to_string())
20450                });
20451            this.edit(edits, cx);
20452            this.refresh_edit_prediction(true, false, window, cx);
20453        });
20454    }
20455
20456    pub fn open_selections_in_multibuffer(
20457        &mut self,
20458        _: &OpenSelectionsInMultibuffer,
20459        window: &mut Window,
20460        cx: &mut Context<Self>,
20461    ) {
20462        let multibuffer = self.buffer.read(cx);
20463
20464        let Some(buffer) = multibuffer.as_singleton() else {
20465            return;
20466        };
20467
20468        let Some(workspace) = self.workspace() else {
20469            return;
20470        };
20471
20472        let title = multibuffer.title(cx).to_string();
20473
20474        let locations = self
20475            .selections
20476            .all_anchors(&self.display_snapshot(cx))
20477            .iter()
20478            .map(|selection| {
20479                (
20480                    buffer.clone(),
20481                    (selection.start.text_anchor..selection.end.text_anchor)
20482                        .to_point(buffer.read(cx)),
20483                )
20484            })
20485            .into_group_map();
20486
20487        cx.spawn_in(window, async move |_, cx| {
20488            workspace.update_in(cx, |workspace, window, cx| {
20489                Self::open_locations_in_multibuffer(
20490                    workspace,
20491                    locations,
20492                    format!("Selections for '{title}'"),
20493                    false,
20494                    MultibufferSelectionMode::All,
20495                    window,
20496                    cx,
20497                );
20498            })
20499        })
20500        .detach();
20501    }
20502
20503    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20504    /// last highlight added will be used.
20505    ///
20506    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20507    pub fn highlight_rows<T: 'static>(
20508        &mut self,
20509        range: Range<Anchor>,
20510        color: Hsla,
20511        options: RowHighlightOptions,
20512        cx: &mut Context<Self>,
20513    ) {
20514        let snapshot = self.buffer().read(cx).snapshot(cx);
20515        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20516        let ix = row_highlights.binary_search_by(|highlight| {
20517            Ordering::Equal
20518                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20519                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20520        });
20521
20522        if let Err(mut ix) = ix {
20523            let index = post_inc(&mut self.highlight_order);
20524
20525            // If this range intersects with the preceding highlight, then merge it with
20526            // the preceding highlight. Otherwise insert a new highlight.
20527            let mut merged = false;
20528            if ix > 0 {
20529                let prev_highlight = &mut row_highlights[ix - 1];
20530                if prev_highlight
20531                    .range
20532                    .end
20533                    .cmp(&range.start, &snapshot)
20534                    .is_ge()
20535                {
20536                    ix -= 1;
20537                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20538                        prev_highlight.range.end = range.end;
20539                    }
20540                    merged = true;
20541                    prev_highlight.index = index;
20542                    prev_highlight.color = color;
20543                    prev_highlight.options = options;
20544                }
20545            }
20546
20547            if !merged {
20548                row_highlights.insert(
20549                    ix,
20550                    RowHighlight {
20551                        range,
20552                        index,
20553                        color,
20554                        options,
20555                        type_id: TypeId::of::<T>(),
20556                    },
20557                );
20558            }
20559
20560            // If any of the following highlights intersect with this one, merge them.
20561            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20562                let highlight = &row_highlights[ix];
20563                if next_highlight
20564                    .range
20565                    .start
20566                    .cmp(&highlight.range.end, &snapshot)
20567                    .is_le()
20568                {
20569                    if next_highlight
20570                        .range
20571                        .end
20572                        .cmp(&highlight.range.end, &snapshot)
20573                        .is_gt()
20574                    {
20575                        row_highlights[ix].range.end = next_highlight.range.end;
20576                    }
20577                    row_highlights.remove(ix + 1);
20578                } else {
20579                    break;
20580                }
20581            }
20582        }
20583    }
20584
20585    /// Remove any highlighted row ranges of the given type that intersect the
20586    /// given ranges.
20587    pub fn remove_highlighted_rows<T: 'static>(
20588        &mut self,
20589        ranges_to_remove: Vec<Range<Anchor>>,
20590        cx: &mut Context<Self>,
20591    ) {
20592        let snapshot = self.buffer().read(cx).snapshot(cx);
20593        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20594        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20595        row_highlights.retain(|highlight| {
20596            while let Some(range_to_remove) = ranges_to_remove.peek() {
20597                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20598                    Ordering::Less | Ordering::Equal => {
20599                        ranges_to_remove.next();
20600                    }
20601                    Ordering::Greater => {
20602                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20603                            Ordering::Less | Ordering::Equal => {
20604                                return false;
20605                            }
20606                            Ordering::Greater => break,
20607                        }
20608                    }
20609                }
20610            }
20611
20612            true
20613        })
20614    }
20615
20616    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20617    pub fn clear_row_highlights<T: 'static>(&mut self) {
20618        self.highlighted_rows.remove(&TypeId::of::<T>());
20619    }
20620
20621    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20622    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20623        self.highlighted_rows
20624            .get(&TypeId::of::<T>())
20625            .map_or(&[] as &[_], |vec| vec.as_slice())
20626            .iter()
20627            .map(|highlight| (highlight.range.clone(), highlight.color))
20628    }
20629
20630    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20631    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20632    /// Allows to ignore certain kinds of highlights.
20633    pub fn highlighted_display_rows(
20634        &self,
20635        window: &mut Window,
20636        cx: &mut App,
20637    ) -> BTreeMap<DisplayRow, LineHighlight> {
20638        let snapshot = self.snapshot(window, cx);
20639        let mut used_highlight_orders = HashMap::default();
20640        self.highlighted_rows
20641            .iter()
20642            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20643            .fold(
20644                BTreeMap::<DisplayRow, LineHighlight>::new(),
20645                |mut unique_rows, highlight| {
20646                    let start = highlight.range.start.to_display_point(&snapshot);
20647                    let end = highlight.range.end.to_display_point(&snapshot);
20648                    let start_row = start.row().0;
20649                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20650                        && end.column() == 0
20651                    {
20652                        end.row().0.saturating_sub(1)
20653                    } else {
20654                        end.row().0
20655                    };
20656                    for row in start_row..=end_row {
20657                        let used_index =
20658                            used_highlight_orders.entry(row).or_insert(highlight.index);
20659                        if highlight.index >= *used_index {
20660                            *used_index = highlight.index;
20661                            unique_rows.insert(
20662                                DisplayRow(row),
20663                                LineHighlight {
20664                                    include_gutter: highlight.options.include_gutter,
20665                                    border: None,
20666                                    background: highlight.color.into(),
20667                                    type_id: Some(highlight.type_id),
20668                                },
20669                            );
20670                        }
20671                    }
20672                    unique_rows
20673                },
20674            )
20675    }
20676
20677    pub fn highlighted_display_row_for_autoscroll(
20678        &self,
20679        snapshot: &DisplaySnapshot,
20680    ) -> Option<DisplayRow> {
20681        self.highlighted_rows
20682            .values()
20683            .flat_map(|highlighted_rows| highlighted_rows.iter())
20684            .filter_map(|highlight| {
20685                if highlight.options.autoscroll {
20686                    Some(highlight.range.start.to_display_point(snapshot).row())
20687                } else {
20688                    None
20689                }
20690            })
20691            .min()
20692    }
20693
20694    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20695        self.highlight_background::<SearchWithinRange>(
20696            ranges,
20697            |colors| colors.colors().editor_document_highlight_read_background,
20698            cx,
20699        )
20700    }
20701
20702    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20703        self.breadcrumb_header = Some(new_header);
20704    }
20705
20706    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20707        self.clear_background_highlights::<SearchWithinRange>(cx);
20708    }
20709
20710    pub fn highlight_background<T: 'static>(
20711        &mut self,
20712        ranges: &[Range<Anchor>],
20713        color_fetcher: fn(&Theme) -> Hsla,
20714        cx: &mut Context<Self>,
20715    ) {
20716        self.background_highlights.insert(
20717            HighlightKey::Type(TypeId::of::<T>()),
20718            (color_fetcher, Arc::from(ranges)),
20719        );
20720        self.scrollbar_marker_state.dirty = true;
20721        cx.notify();
20722    }
20723
20724    pub fn highlight_background_key<T: 'static>(
20725        &mut self,
20726        key: usize,
20727        ranges: &[Range<Anchor>],
20728        color_fetcher: fn(&Theme) -> Hsla,
20729        cx: &mut Context<Self>,
20730    ) {
20731        self.background_highlights.insert(
20732            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20733            (color_fetcher, Arc::from(ranges)),
20734        );
20735        self.scrollbar_marker_state.dirty = true;
20736        cx.notify();
20737    }
20738
20739    pub fn clear_background_highlights<T: 'static>(
20740        &mut self,
20741        cx: &mut Context<Self>,
20742    ) -> Option<BackgroundHighlight> {
20743        let text_highlights = self
20744            .background_highlights
20745            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20746        if !text_highlights.1.is_empty() {
20747            self.scrollbar_marker_state.dirty = true;
20748            cx.notify();
20749        }
20750        Some(text_highlights)
20751    }
20752
20753    pub fn highlight_gutter<T: 'static>(
20754        &mut self,
20755        ranges: impl Into<Vec<Range<Anchor>>>,
20756        color_fetcher: fn(&App) -> Hsla,
20757        cx: &mut Context<Self>,
20758    ) {
20759        self.gutter_highlights
20760            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20761        cx.notify();
20762    }
20763
20764    pub fn clear_gutter_highlights<T: 'static>(
20765        &mut self,
20766        cx: &mut Context<Self>,
20767    ) -> Option<GutterHighlight> {
20768        cx.notify();
20769        self.gutter_highlights.remove(&TypeId::of::<T>())
20770    }
20771
20772    pub fn insert_gutter_highlight<T: 'static>(
20773        &mut self,
20774        range: Range<Anchor>,
20775        color_fetcher: fn(&App) -> Hsla,
20776        cx: &mut Context<Self>,
20777    ) {
20778        let snapshot = self.buffer().read(cx).snapshot(cx);
20779        let mut highlights = self
20780            .gutter_highlights
20781            .remove(&TypeId::of::<T>())
20782            .map(|(_, highlights)| highlights)
20783            .unwrap_or_default();
20784        let ix = highlights.binary_search_by(|highlight| {
20785            Ordering::Equal
20786                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20787                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20788        });
20789        if let Err(ix) = ix {
20790            highlights.insert(ix, range);
20791        }
20792        self.gutter_highlights
20793            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20794    }
20795
20796    pub fn remove_gutter_highlights<T: 'static>(
20797        &mut self,
20798        ranges_to_remove: Vec<Range<Anchor>>,
20799        cx: &mut Context<Self>,
20800    ) {
20801        let snapshot = self.buffer().read(cx).snapshot(cx);
20802        let Some((color_fetcher, mut gutter_highlights)) =
20803            self.gutter_highlights.remove(&TypeId::of::<T>())
20804        else {
20805            return;
20806        };
20807        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20808        gutter_highlights.retain(|highlight| {
20809            while let Some(range_to_remove) = ranges_to_remove.peek() {
20810                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20811                    Ordering::Less | Ordering::Equal => {
20812                        ranges_to_remove.next();
20813                    }
20814                    Ordering::Greater => {
20815                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20816                            Ordering::Less | Ordering::Equal => {
20817                                return false;
20818                            }
20819                            Ordering::Greater => break,
20820                        }
20821                    }
20822                }
20823            }
20824
20825            true
20826        });
20827        self.gutter_highlights
20828            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20829    }
20830
20831    #[cfg(feature = "test-support")]
20832    pub fn all_text_highlights(
20833        &self,
20834        window: &mut Window,
20835        cx: &mut Context<Self>,
20836    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20837        let snapshot = self.snapshot(window, cx);
20838        self.display_map.update(cx, |display_map, _| {
20839            display_map
20840                .all_text_highlights()
20841                .map(|highlight| {
20842                    let (style, ranges) = highlight.as_ref();
20843                    (
20844                        *style,
20845                        ranges
20846                            .iter()
20847                            .map(|range| range.clone().to_display_points(&snapshot))
20848                            .collect(),
20849                    )
20850                })
20851                .collect()
20852        })
20853    }
20854
20855    #[cfg(feature = "test-support")]
20856    pub fn all_text_background_highlights(
20857        &self,
20858        window: &mut Window,
20859        cx: &mut Context<Self>,
20860    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20861        let snapshot = self.snapshot(window, cx);
20862        let buffer = &snapshot.buffer_snapshot();
20863        let start = buffer.anchor_before(0);
20864        let end = buffer.anchor_after(buffer.len());
20865        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20866    }
20867
20868    #[cfg(any(test, feature = "test-support"))]
20869    pub fn sorted_background_highlights_in_range(
20870        &self,
20871        search_range: Range<Anchor>,
20872        display_snapshot: &DisplaySnapshot,
20873        theme: &Theme,
20874    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20875        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20876        res.sort_by(|a, b| {
20877            a.0.start
20878                .cmp(&b.0.start)
20879                .then_with(|| a.0.end.cmp(&b.0.end))
20880                .then_with(|| a.1.cmp(&b.1))
20881        });
20882        res
20883    }
20884
20885    #[cfg(feature = "test-support")]
20886    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20887        let snapshot = self.buffer().read(cx).snapshot(cx);
20888
20889        let highlights = self
20890            .background_highlights
20891            .get(&HighlightKey::Type(TypeId::of::<
20892                items::BufferSearchHighlights,
20893            >()));
20894
20895        if let Some((_color, ranges)) = highlights {
20896            ranges
20897                .iter()
20898                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20899                .collect_vec()
20900        } else {
20901            vec![]
20902        }
20903    }
20904
20905    fn document_highlights_for_position<'a>(
20906        &'a self,
20907        position: Anchor,
20908        buffer: &'a MultiBufferSnapshot,
20909    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20910        let read_highlights = self
20911            .background_highlights
20912            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20913            .map(|h| &h.1);
20914        let write_highlights = self
20915            .background_highlights
20916            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20917            .map(|h| &h.1);
20918        let left_position = position.bias_left(buffer);
20919        let right_position = position.bias_right(buffer);
20920        read_highlights
20921            .into_iter()
20922            .chain(write_highlights)
20923            .flat_map(move |ranges| {
20924                let start_ix = match ranges.binary_search_by(|probe| {
20925                    let cmp = probe.end.cmp(&left_position, buffer);
20926                    if cmp.is_ge() {
20927                        Ordering::Greater
20928                    } else {
20929                        Ordering::Less
20930                    }
20931                }) {
20932                    Ok(i) | Err(i) => i,
20933                };
20934
20935                ranges[start_ix..]
20936                    .iter()
20937                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20938            })
20939    }
20940
20941    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20942        self.background_highlights
20943            .get(&HighlightKey::Type(TypeId::of::<T>()))
20944            .is_some_and(|(_, highlights)| !highlights.is_empty())
20945    }
20946
20947    /// Returns all background highlights for a given range.
20948    ///
20949    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20950    pub fn background_highlights_in_range(
20951        &self,
20952        search_range: Range<Anchor>,
20953        display_snapshot: &DisplaySnapshot,
20954        theme: &Theme,
20955    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20956        let mut results = Vec::new();
20957        for (color_fetcher, ranges) in self.background_highlights.values() {
20958            let color = color_fetcher(theme);
20959            let start_ix = match ranges.binary_search_by(|probe| {
20960                let cmp = probe
20961                    .end
20962                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20963                if cmp.is_gt() {
20964                    Ordering::Greater
20965                } else {
20966                    Ordering::Less
20967                }
20968            }) {
20969                Ok(i) | Err(i) => i,
20970            };
20971            for range in &ranges[start_ix..] {
20972                if range
20973                    .start
20974                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20975                    .is_ge()
20976                {
20977                    break;
20978                }
20979
20980                let start = range.start.to_display_point(display_snapshot);
20981                let end = range.end.to_display_point(display_snapshot);
20982                results.push((start..end, color))
20983            }
20984        }
20985        results
20986    }
20987
20988    pub fn gutter_highlights_in_range(
20989        &self,
20990        search_range: Range<Anchor>,
20991        display_snapshot: &DisplaySnapshot,
20992        cx: &App,
20993    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20994        let mut results = Vec::new();
20995        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20996            let color = color_fetcher(cx);
20997            let start_ix = match ranges.binary_search_by(|probe| {
20998                let cmp = probe
20999                    .end
21000                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21001                if cmp.is_gt() {
21002                    Ordering::Greater
21003                } else {
21004                    Ordering::Less
21005                }
21006            }) {
21007                Ok(i) | Err(i) => i,
21008            };
21009            for range in &ranges[start_ix..] {
21010                if range
21011                    .start
21012                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21013                    .is_ge()
21014                {
21015                    break;
21016                }
21017
21018                let start = range.start.to_display_point(display_snapshot);
21019                let end = range.end.to_display_point(display_snapshot);
21020                results.push((start..end, color))
21021            }
21022        }
21023        results
21024    }
21025
21026    /// Get the text ranges corresponding to the redaction query
21027    pub fn redacted_ranges(
21028        &self,
21029        search_range: Range<Anchor>,
21030        display_snapshot: &DisplaySnapshot,
21031        cx: &App,
21032    ) -> Vec<Range<DisplayPoint>> {
21033        display_snapshot
21034            .buffer_snapshot()
21035            .redacted_ranges(search_range, |file| {
21036                if let Some(file) = file {
21037                    file.is_private()
21038                        && EditorSettings::get(
21039                            Some(SettingsLocation {
21040                                worktree_id: file.worktree_id(cx),
21041                                path: file.path().as_ref(),
21042                            }),
21043                            cx,
21044                        )
21045                        .redact_private_values
21046                } else {
21047                    false
21048                }
21049            })
21050            .map(|range| {
21051                range.start.to_display_point(display_snapshot)
21052                    ..range.end.to_display_point(display_snapshot)
21053            })
21054            .collect()
21055    }
21056
21057    pub fn highlight_text_key<T: 'static>(
21058        &mut self,
21059        key: usize,
21060        ranges: Vec<Range<Anchor>>,
21061        style: HighlightStyle,
21062        cx: &mut Context<Self>,
21063    ) {
21064        self.display_map.update(cx, |map, _| {
21065            map.highlight_text(
21066                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21067                ranges,
21068                style,
21069            );
21070        });
21071        cx.notify();
21072    }
21073
21074    pub fn highlight_text<T: 'static>(
21075        &mut self,
21076        ranges: Vec<Range<Anchor>>,
21077        style: HighlightStyle,
21078        cx: &mut Context<Self>,
21079    ) {
21080        self.display_map.update(cx, |map, _| {
21081            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
21082        });
21083        cx.notify();
21084    }
21085
21086    pub fn text_highlights<'a, T: 'static>(
21087        &'a self,
21088        cx: &'a App,
21089    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21090        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21091    }
21092
21093    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21094        let cleared = self
21095            .display_map
21096            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21097        if cleared {
21098            cx.notify();
21099        }
21100    }
21101
21102    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21103        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21104            && self.focus_handle.is_focused(window)
21105    }
21106
21107    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21108        self.show_cursor_when_unfocused = is_enabled;
21109        cx.notify();
21110    }
21111
21112    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21113        cx.notify();
21114    }
21115
21116    fn on_debug_session_event(
21117        &mut self,
21118        _session: Entity<Session>,
21119        event: &SessionEvent,
21120        cx: &mut Context<Self>,
21121    ) {
21122        if let SessionEvent::InvalidateInlineValue = event {
21123            self.refresh_inline_values(cx);
21124        }
21125    }
21126
21127    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21128        let Some(project) = self.project.clone() else {
21129            return;
21130        };
21131
21132        if !self.inline_value_cache.enabled {
21133            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21134            self.splice_inlays(&inlays, Vec::new(), cx);
21135            return;
21136        }
21137
21138        let current_execution_position = self
21139            .highlighted_rows
21140            .get(&TypeId::of::<ActiveDebugLine>())
21141            .and_then(|lines| lines.last().map(|line| line.range.end));
21142
21143        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21144            let inline_values = editor
21145                .update(cx, |editor, cx| {
21146                    let Some(current_execution_position) = current_execution_position else {
21147                        return Some(Task::ready(Ok(Vec::new())));
21148                    };
21149
21150                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21151                        let snapshot = buffer.snapshot(cx);
21152
21153                        let excerpt = snapshot.excerpt_containing(
21154                            current_execution_position..current_execution_position,
21155                        )?;
21156
21157                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21158                    })?;
21159
21160                    let range =
21161                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21162
21163                    project.inline_values(buffer, range, cx)
21164                })
21165                .ok()
21166                .flatten()?
21167                .await
21168                .context("refreshing debugger inlays")
21169                .log_err()?;
21170
21171            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21172
21173            for (buffer_id, inline_value) in inline_values
21174                .into_iter()
21175                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21176            {
21177                buffer_inline_values
21178                    .entry(buffer_id)
21179                    .or_default()
21180                    .push(inline_value);
21181            }
21182
21183            editor
21184                .update(cx, |editor, cx| {
21185                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21186                    let mut new_inlays = Vec::default();
21187
21188                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21189                        let buffer_id = buffer_snapshot.remote_id();
21190                        buffer_inline_values
21191                            .get(&buffer_id)
21192                            .into_iter()
21193                            .flatten()
21194                            .for_each(|hint| {
21195                                let inlay = Inlay::debugger(
21196                                    post_inc(&mut editor.next_inlay_id),
21197                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21198                                    hint.text(),
21199                                );
21200                                if !inlay.text().chars().contains(&'\n') {
21201                                    new_inlays.push(inlay);
21202                                }
21203                            });
21204                    }
21205
21206                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21207                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21208
21209                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21210                })
21211                .ok()?;
21212            Some(())
21213        });
21214    }
21215
21216    fn on_buffer_event(
21217        &mut self,
21218        multibuffer: &Entity<MultiBuffer>,
21219        event: &multi_buffer::Event,
21220        window: &mut Window,
21221        cx: &mut Context<Self>,
21222    ) {
21223        match event {
21224            multi_buffer::Event::Edited { edited_buffer } => {
21225                self.scrollbar_marker_state.dirty = true;
21226                self.active_indent_guides_state.dirty = true;
21227                self.refresh_active_diagnostics(cx);
21228                self.refresh_code_actions(window, cx);
21229                self.refresh_selected_text_highlights(true, window, cx);
21230                self.refresh_single_line_folds(window, cx);
21231                self.refresh_matching_bracket_highlights(window, cx);
21232                if self.has_active_edit_prediction() {
21233                    self.update_visible_edit_prediction(window, cx);
21234                }
21235
21236                if let Some(buffer) = edited_buffer {
21237                    if buffer.read(cx).file().is_none() {
21238                        cx.emit(EditorEvent::TitleChanged);
21239                    }
21240
21241                    if self.project.is_some() {
21242                        let buffer_id = buffer.read(cx).remote_id();
21243                        self.register_buffer(buffer_id, cx);
21244                        self.update_lsp_data(Some(buffer_id), window, cx);
21245                        self.refresh_inlay_hints(
21246                            InlayHintRefreshReason::BufferEdited(buffer_id),
21247                            cx,
21248                        );
21249                    }
21250                }
21251
21252                cx.emit(EditorEvent::BufferEdited);
21253                cx.emit(SearchEvent::MatchesInvalidated);
21254
21255                let Some(project) = &self.project else { return };
21256                let (telemetry, is_via_ssh) = {
21257                    let project = project.read(cx);
21258                    let telemetry = project.client().telemetry().clone();
21259                    let is_via_ssh = project.is_via_remote_server();
21260                    (telemetry, is_via_ssh)
21261                };
21262                telemetry.log_edit_event("editor", is_via_ssh);
21263            }
21264            multi_buffer::Event::ExcerptsAdded {
21265                buffer,
21266                predecessor,
21267                excerpts,
21268            } => {
21269                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21270                let buffer_id = buffer.read(cx).remote_id();
21271                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21272                    && let Some(project) = &self.project
21273                {
21274                    update_uncommitted_diff_for_buffer(
21275                        cx.entity(),
21276                        project,
21277                        [buffer.clone()],
21278                        self.buffer.clone(),
21279                        cx,
21280                    )
21281                    .detach();
21282                }
21283                self.update_lsp_data(Some(buffer_id), window, cx);
21284                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21285                cx.emit(EditorEvent::ExcerptsAdded {
21286                    buffer: buffer.clone(),
21287                    predecessor: *predecessor,
21288                    excerpts: excerpts.clone(),
21289                });
21290            }
21291            multi_buffer::Event::ExcerptsRemoved {
21292                ids,
21293                removed_buffer_ids,
21294            } => {
21295                if let Some(inlay_hints) = &mut self.inlay_hints {
21296                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21297                }
21298                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21299                for buffer_id in removed_buffer_ids {
21300                    self.registered_buffers.remove(buffer_id);
21301                }
21302                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21303                cx.emit(EditorEvent::ExcerptsRemoved {
21304                    ids: ids.clone(),
21305                    removed_buffer_ids: removed_buffer_ids.clone(),
21306                });
21307            }
21308            multi_buffer::Event::ExcerptsEdited {
21309                excerpt_ids,
21310                buffer_ids,
21311            } => {
21312                self.display_map.update(cx, |map, cx| {
21313                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21314                });
21315                cx.emit(EditorEvent::ExcerptsEdited {
21316                    ids: excerpt_ids.clone(),
21317                });
21318            }
21319            multi_buffer::Event::ExcerptsExpanded { ids } => {
21320                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21321                self.refresh_document_highlights(cx);
21322                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21323            }
21324            multi_buffer::Event::Reparsed(buffer_id) => {
21325                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21326                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21327
21328                cx.emit(EditorEvent::Reparsed(*buffer_id));
21329            }
21330            multi_buffer::Event::DiffHunksToggled => {
21331                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21332            }
21333            multi_buffer::Event::LanguageChanged(buffer_id) => {
21334                self.registered_buffers.remove(&buffer_id);
21335                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21336                cx.emit(EditorEvent::Reparsed(*buffer_id));
21337                cx.notify();
21338            }
21339            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21340            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21341            multi_buffer::Event::FileHandleChanged
21342            | multi_buffer::Event::Reloaded
21343            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21344            multi_buffer::Event::DiagnosticsUpdated => {
21345                self.update_diagnostics_state(window, cx);
21346            }
21347            _ => {}
21348        };
21349    }
21350
21351    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21352        if !self.diagnostics_enabled() {
21353            return;
21354        }
21355        self.refresh_active_diagnostics(cx);
21356        self.refresh_inline_diagnostics(true, window, cx);
21357        self.scrollbar_marker_state.dirty = true;
21358        cx.notify();
21359    }
21360
21361    pub fn start_temporary_diff_override(&mut self) {
21362        self.load_diff_task.take();
21363        self.temporary_diff_override = true;
21364    }
21365
21366    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21367        self.temporary_diff_override = false;
21368        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21369        self.buffer.update(cx, |buffer, cx| {
21370            buffer.set_all_diff_hunks_collapsed(cx);
21371        });
21372
21373        if let Some(project) = self.project.clone() {
21374            self.load_diff_task = Some(
21375                update_uncommitted_diff_for_buffer(
21376                    cx.entity(),
21377                    &project,
21378                    self.buffer.read(cx).all_buffers(),
21379                    self.buffer.clone(),
21380                    cx,
21381                )
21382                .shared(),
21383            );
21384        }
21385    }
21386
21387    fn on_display_map_changed(
21388        &mut self,
21389        _: Entity<DisplayMap>,
21390        _: &mut Window,
21391        cx: &mut Context<Self>,
21392    ) {
21393        cx.notify();
21394    }
21395
21396    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21397        if self.diagnostics_enabled() {
21398            let new_severity = EditorSettings::get_global(cx)
21399                .diagnostics_max_severity
21400                .unwrap_or(DiagnosticSeverity::Hint);
21401            self.set_max_diagnostics_severity(new_severity, cx);
21402        }
21403        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21404        self.update_edit_prediction_settings(cx);
21405        self.refresh_edit_prediction(true, false, window, cx);
21406        self.refresh_inline_values(cx);
21407        self.refresh_inlay_hints(
21408            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21409                self.selections.newest_anchor().head(),
21410                &self.buffer.read(cx).snapshot(cx),
21411                cx,
21412            )),
21413            cx,
21414        );
21415
21416        let old_cursor_shape = self.cursor_shape;
21417        let old_show_breadcrumbs = self.show_breadcrumbs;
21418
21419        {
21420            let editor_settings = EditorSettings::get_global(cx);
21421            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21422            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21423            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21424            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21425        }
21426
21427        if old_cursor_shape != self.cursor_shape {
21428            cx.emit(EditorEvent::CursorShapeChanged);
21429        }
21430
21431        if old_show_breadcrumbs != self.show_breadcrumbs {
21432            cx.emit(EditorEvent::BreadcrumbsChanged);
21433        }
21434
21435        let project_settings = ProjectSettings::get_global(cx);
21436        self.buffer_serialization = self
21437            .should_serialize_buffer()
21438            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21439
21440        if self.mode.is_full() {
21441            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21442            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21443            if self.show_inline_diagnostics != show_inline_diagnostics {
21444                self.show_inline_diagnostics = show_inline_diagnostics;
21445                self.refresh_inline_diagnostics(false, window, cx);
21446            }
21447
21448            if self.git_blame_inline_enabled != inline_blame_enabled {
21449                self.toggle_git_blame_inline_internal(false, window, cx);
21450            }
21451
21452            let minimap_settings = EditorSettings::get_global(cx).minimap;
21453            if self.minimap_visibility != MinimapVisibility::Disabled {
21454                if self.minimap_visibility.settings_visibility()
21455                    != minimap_settings.minimap_enabled()
21456                {
21457                    self.set_minimap_visibility(
21458                        MinimapVisibility::for_mode(self.mode(), cx),
21459                        window,
21460                        cx,
21461                    );
21462                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21463                    minimap_entity.update(cx, |minimap_editor, cx| {
21464                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21465                    })
21466                }
21467            }
21468        }
21469
21470        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21471            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21472        }) {
21473            if !inlay_splice.is_empty() {
21474                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21475            }
21476            self.refresh_colors_for_visible_range(None, window, cx);
21477        }
21478
21479        cx.notify();
21480    }
21481
21482    pub fn set_searchable(&mut self, searchable: bool) {
21483        self.searchable = searchable;
21484    }
21485
21486    pub fn searchable(&self) -> bool {
21487        self.searchable
21488    }
21489
21490    pub fn open_excerpts_in_split(
21491        &mut self,
21492        _: &OpenExcerptsSplit,
21493        window: &mut Window,
21494        cx: &mut Context<Self>,
21495    ) {
21496        self.open_excerpts_common(None, true, window, cx)
21497    }
21498
21499    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21500        self.open_excerpts_common(None, false, window, cx)
21501    }
21502
21503    fn open_excerpts_common(
21504        &mut self,
21505        jump_data: Option<JumpData>,
21506        split: bool,
21507        window: &mut Window,
21508        cx: &mut Context<Self>,
21509    ) {
21510        let Some(workspace) = self.workspace() else {
21511            cx.propagate();
21512            return;
21513        };
21514
21515        if self.buffer.read(cx).is_singleton() {
21516            cx.propagate();
21517            return;
21518        }
21519
21520        let mut new_selections_by_buffer = HashMap::default();
21521        match &jump_data {
21522            Some(JumpData::MultiBufferPoint {
21523                excerpt_id,
21524                position,
21525                anchor,
21526                line_offset_from_top,
21527            }) => {
21528                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21529                if let Some(buffer) = multi_buffer_snapshot
21530                    .buffer_id_for_excerpt(*excerpt_id)
21531                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21532                {
21533                    let buffer_snapshot = buffer.read(cx).snapshot();
21534                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21535                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21536                    } else {
21537                        buffer_snapshot.clip_point(*position, Bias::Left)
21538                    };
21539                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21540                    new_selections_by_buffer.insert(
21541                        buffer,
21542                        (
21543                            vec![jump_to_offset..jump_to_offset],
21544                            Some(*line_offset_from_top),
21545                        ),
21546                    );
21547                }
21548            }
21549            Some(JumpData::MultiBufferRow {
21550                row,
21551                line_offset_from_top,
21552            }) => {
21553                let point = MultiBufferPoint::new(row.0, 0);
21554                if let Some((buffer, buffer_point, _)) =
21555                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21556                {
21557                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21558                    new_selections_by_buffer
21559                        .entry(buffer)
21560                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21561                        .0
21562                        .push(buffer_offset..buffer_offset)
21563                }
21564            }
21565            None => {
21566                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21567                let multi_buffer = self.buffer.read(cx);
21568                for selection in selections {
21569                    for (snapshot, range, _, anchor) in multi_buffer
21570                        .snapshot(cx)
21571                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21572                    {
21573                        if let Some(anchor) = anchor {
21574                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21575                            else {
21576                                continue;
21577                            };
21578                            let offset = text::ToOffset::to_offset(
21579                                &anchor.text_anchor,
21580                                &buffer_handle.read(cx).snapshot(),
21581                            );
21582                            let range = offset..offset;
21583                            new_selections_by_buffer
21584                                .entry(buffer_handle)
21585                                .or_insert((Vec::new(), None))
21586                                .0
21587                                .push(range)
21588                        } else {
21589                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21590                            else {
21591                                continue;
21592                            };
21593                            new_selections_by_buffer
21594                                .entry(buffer_handle)
21595                                .or_insert((Vec::new(), None))
21596                                .0
21597                                .push(range)
21598                        }
21599                    }
21600                }
21601            }
21602        }
21603
21604        new_selections_by_buffer
21605            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21606
21607        if new_selections_by_buffer.is_empty() {
21608            return;
21609        }
21610
21611        // We defer the pane interaction because we ourselves are a workspace item
21612        // and activating a new item causes the pane to call a method on us reentrantly,
21613        // which panics if we're on the stack.
21614        window.defer(cx, move |window, cx| {
21615            workspace.update(cx, |workspace, cx| {
21616                let pane = if split {
21617                    workspace.adjacent_pane(window, cx)
21618                } else {
21619                    workspace.active_pane().clone()
21620                };
21621
21622                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21623                    let editor = buffer
21624                        .read(cx)
21625                        .file()
21626                        .is_none()
21627                        .then(|| {
21628                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21629                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21630                            // Instead, we try to activate the existing editor in the pane first.
21631                            let (editor, pane_item_index) =
21632                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21633                                    let editor = item.downcast::<Editor>()?;
21634                                    let singleton_buffer =
21635                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21636                                    if singleton_buffer == buffer {
21637                                        Some((editor, i))
21638                                    } else {
21639                                        None
21640                                    }
21641                                })?;
21642                            pane.update(cx, |pane, cx| {
21643                                pane.activate_item(pane_item_index, true, true, window, cx)
21644                            });
21645                            Some(editor)
21646                        })
21647                        .flatten()
21648                        .unwrap_or_else(|| {
21649                            workspace.open_project_item::<Self>(
21650                                pane.clone(),
21651                                buffer,
21652                                true,
21653                                true,
21654                                window,
21655                                cx,
21656                            )
21657                        });
21658
21659                    editor.update(cx, |editor, cx| {
21660                        let autoscroll = match scroll_offset {
21661                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21662                            None => Autoscroll::newest(),
21663                        };
21664                        let nav_history = editor.nav_history.take();
21665                        editor.change_selections(
21666                            SelectionEffects::scroll(autoscroll),
21667                            window,
21668                            cx,
21669                            |s| {
21670                                s.select_ranges(ranges);
21671                            },
21672                        );
21673                        editor.nav_history = nav_history;
21674                    });
21675                }
21676            })
21677        });
21678    }
21679
21680    // For now, don't allow opening excerpts in buffers that aren't backed by
21681    // regular project files.
21682    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21683        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21684    }
21685
21686    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21687        let snapshot = self.buffer.read(cx).read(cx);
21688        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21689        Some(
21690            ranges
21691                .iter()
21692                .map(move |range| {
21693                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21694                })
21695                .collect(),
21696        )
21697    }
21698
21699    fn selection_replacement_ranges(
21700        &self,
21701        range: Range<OffsetUtf16>,
21702        cx: &mut App,
21703    ) -> Vec<Range<OffsetUtf16>> {
21704        let selections = self
21705            .selections
21706            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21707        let newest_selection = selections
21708            .iter()
21709            .max_by_key(|selection| selection.id)
21710            .unwrap();
21711        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21712        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21713        let snapshot = self.buffer.read(cx).read(cx);
21714        selections
21715            .into_iter()
21716            .map(|mut selection| {
21717                selection.start.0 =
21718                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21719                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21720                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21721                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21722            })
21723            .collect()
21724    }
21725
21726    fn report_editor_event(
21727        &self,
21728        reported_event: ReportEditorEvent,
21729        file_extension: Option<String>,
21730        cx: &App,
21731    ) {
21732        if cfg!(any(test, feature = "test-support")) {
21733            return;
21734        }
21735
21736        let Some(project) = &self.project else { return };
21737
21738        // If None, we are in a file without an extension
21739        let file = self
21740            .buffer
21741            .read(cx)
21742            .as_singleton()
21743            .and_then(|b| b.read(cx).file());
21744        let file_extension = file_extension.or(file
21745            .as_ref()
21746            .and_then(|file| Path::new(file.file_name(cx)).extension())
21747            .and_then(|e| e.to_str())
21748            .map(|a| a.to_string()));
21749
21750        let vim_mode = vim_flavor(cx).is_some();
21751
21752        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21753        let copilot_enabled = edit_predictions_provider
21754            == language::language_settings::EditPredictionProvider::Copilot;
21755        let copilot_enabled_for_language = self
21756            .buffer
21757            .read(cx)
21758            .language_settings(cx)
21759            .show_edit_predictions;
21760
21761        let project = project.read(cx);
21762        let event_type = reported_event.event_type();
21763
21764        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21765            telemetry::event!(
21766                event_type,
21767                type = if auto_saved {"autosave"} else {"manual"},
21768                file_extension,
21769                vim_mode,
21770                copilot_enabled,
21771                copilot_enabled_for_language,
21772                edit_predictions_provider,
21773                is_via_ssh = project.is_via_remote_server(),
21774            );
21775        } else {
21776            telemetry::event!(
21777                event_type,
21778                file_extension,
21779                vim_mode,
21780                copilot_enabled,
21781                copilot_enabled_for_language,
21782                edit_predictions_provider,
21783                is_via_ssh = project.is_via_remote_server(),
21784            );
21785        };
21786    }
21787
21788    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21789    /// with each line being an array of {text, highlight} objects.
21790    fn copy_highlight_json(
21791        &mut self,
21792        _: &CopyHighlightJson,
21793        window: &mut Window,
21794        cx: &mut Context<Self>,
21795    ) {
21796        #[derive(Serialize)]
21797        struct Chunk<'a> {
21798            text: String,
21799            highlight: Option<&'a str>,
21800        }
21801
21802        let snapshot = self.buffer.read(cx).snapshot(cx);
21803        let range = self
21804            .selected_text_range(false, window, cx)
21805            .and_then(|selection| {
21806                if selection.range.is_empty() {
21807                    None
21808                } else {
21809                    Some(
21810                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21811                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21812                    )
21813                }
21814            })
21815            .unwrap_or_else(|| 0..snapshot.len());
21816
21817        let chunks = snapshot.chunks(range, true);
21818        let mut lines = Vec::new();
21819        let mut line: VecDeque<Chunk> = VecDeque::new();
21820
21821        let Some(style) = self.style.as_ref() else {
21822            return;
21823        };
21824
21825        for chunk in chunks {
21826            let highlight = chunk
21827                .syntax_highlight_id
21828                .and_then(|id| id.name(&style.syntax));
21829            let mut chunk_lines = chunk.text.split('\n').peekable();
21830            while let Some(text) = chunk_lines.next() {
21831                let mut merged_with_last_token = false;
21832                if let Some(last_token) = line.back_mut()
21833                    && last_token.highlight == highlight
21834                {
21835                    last_token.text.push_str(text);
21836                    merged_with_last_token = true;
21837                }
21838
21839                if !merged_with_last_token {
21840                    line.push_back(Chunk {
21841                        text: text.into(),
21842                        highlight,
21843                    });
21844                }
21845
21846                if chunk_lines.peek().is_some() {
21847                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21848                        line.pop_front();
21849                    }
21850                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21851                        line.pop_back();
21852                    }
21853
21854                    lines.push(mem::take(&mut line));
21855                }
21856            }
21857        }
21858
21859        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21860            return;
21861        };
21862        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21863    }
21864
21865    pub fn open_context_menu(
21866        &mut self,
21867        _: &OpenContextMenu,
21868        window: &mut Window,
21869        cx: &mut Context<Self>,
21870    ) {
21871        self.request_autoscroll(Autoscroll::newest(), cx);
21872        let position = self
21873            .selections
21874            .newest_display(&self.display_snapshot(cx))
21875            .start;
21876        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21877    }
21878
21879    pub fn replay_insert_event(
21880        &mut self,
21881        text: &str,
21882        relative_utf16_range: Option<Range<isize>>,
21883        window: &mut Window,
21884        cx: &mut Context<Self>,
21885    ) {
21886        if !self.input_enabled {
21887            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21888            return;
21889        }
21890        if let Some(relative_utf16_range) = relative_utf16_range {
21891            let selections = self
21892                .selections
21893                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21894            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21895                let new_ranges = selections.into_iter().map(|range| {
21896                    let start = OffsetUtf16(
21897                        range
21898                            .head()
21899                            .0
21900                            .saturating_add_signed(relative_utf16_range.start),
21901                    );
21902                    let end = OffsetUtf16(
21903                        range
21904                            .head()
21905                            .0
21906                            .saturating_add_signed(relative_utf16_range.end),
21907                    );
21908                    start..end
21909                });
21910                s.select_ranges(new_ranges);
21911            });
21912        }
21913
21914        self.handle_input(text, window, cx);
21915    }
21916
21917    pub fn is_focused(&self, window: &Window) -> bool {
21918        self.focus_handle.is_focused(window)
21919    }
21920
21921    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21922        cx.emit(EditorEvent::Focused);
21923
21924        if let Some(descendant) = self
21925            .last_focused_descendant
21926            .take()
21927            .and_then(|descendant| descendant.upgrade())
21928        {
21929            window.focus(&descendant);
21930        } else {
21931            if let Some(blame) = self.blame.as_ref() {
21932                blame.update(cx, GitBlame::focus)
21933            }
21934
21935            self.blink_manager.update(cx, BlinkManager::enable);
21936            self.show_cursor_names(window, cx);
21937            self.buffer.update(cx, |buffer, cx| {
21938                buffer.finalize_last_transaction(cx);
21939                if self.leader_id.is_none() {
21940                    buffer.set_active_selections(
21941                        &self.selections.disjoint_anchors_arc(),
21942                        self.selections.line_mode(),
21943                        self.cursor_shape,
21944                        cx,
21945                    );
21946                }
21947            });
21948        }
21949    }
21950
21951    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21952        cx.emit(EditorEvent::FocusedIn)
21953    }
21954
21955    fn handle_focus_out(
21956        &mut self,
21957        event: FocusOutEvent,
21958        _window: &mut Window,
21959        cx: &mut Context<Self>,
21960    ) {
21961        if event.blurred != self.focus_handle {
21962            self.last_focused_descendant = Some(event.blurred);
21963        }
21964        self.selection_drag_state = SelectionDragState::None;
21965        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21966    }
21967
21968    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21969        self.blink_manager.update(cx, BlinkManager::disable);
21970        self.buffer
21971            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21972
21973        if let Some(blame) = self.blame.as_ref() {
21974            blame.update(cx, GitBlame::blur)
21975        }
21976        if !self.hover_state.focused(window, cx) {
21977            hide_hover(self, cx);
21978        }
21979        if !self
21980            .context_menu
21981            .borrow()
21982            .as_ref()
21983            .is_some_and(|context_menu| context_menu.focused(window, cx))
21984        {
21985            self.hide_context_menu(window, cx);
21986        }
21987        self.take_active_edit_prediction(cx);
21988        cx.emit(EditorEvent::Blurred);
21989        cx.notify();
21990    }
21991
21992    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21993        let mut pending: String = window
21994            .pending_input_keystrokes()
21995            .into_iter()
21996            .flatten()
21997            .filter_map(|keystroke| {
21998                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21999                    keystroke.key_char.clone()
22000                } else {
22001                    None
22002                }
22003            })
22004            .collect();
22005
22006        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22007            pending = "".to_string();
22008        }
22009
22010        let existing_pending = self
22011            .text_highlights::<PendingInput>(cx)
22012            .map(|(_, ranges)| ranges.to_vec());
22013        if existing_pending.is_none() && pending.is_empty() {
22014            return;
22015        }
22016        let transaction =
22017            self.transact(window, cx, |this, window, cx| {
22018                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
22019                let edits = selections
22020                    .iter()
22021                    .map(|selection| (selection.end..selection.end, pending.clone()));
22022                this.edit(edits, cx);
22023                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22024                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22025                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22026                    }));
22027                });
22028                if let Some(existing_ranges) = existing_pending {
22029                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22030                    this.edit(edits, cx);
22031                }
22032            });
22033
22034        let snapshot = self.snapshot(window, cx);
22035        let ranges = self
22036            .selections
22037            .all::<usize>(&snapshot.display_snapshot)
22038            .into_iter()
22039            .map(|selection| {
22040                snapshot.buffer_snapshot().anchor_after(selection.end)
22041                    ..snapshot
22042                        .buffer_snapshot()
22043                        .anchor_before(selection.end + pending.len())
22044            })
22045            .collect();
22046
22047        if pending.is_empty() {
22048            self.clear_highlights::<PendingInput>(cx);
22049        } else {
22050            self.highlight_text::<PendingInput>(
22051                ranges,
22052                HighlightStyle {
22053                    underline: Some(UnderlineStyle {
22054                        thickness: px(1.),
22055                        color: None,
22056                        wavy: false,
22057                    }),
22058                    ..Default::default()
22059                },
22060                cx,
22061            );
22062        }
22063
22064        self.ime_transaction = self.ime_transaction.or(transaction);
22065        if let Some(transaction) = self.ime_transaction {
22066            self.buffer.update(cx, |buffer, cx| {
22067                buffer.group_until_transaction(transaction, cx);
22068            });
22069        }
22070
22071        if self.text_highlights::<PendingInput>(cx).is_none() {
22072            self.ime_transaction.take();
22073        }
22074    }
22075
22076    pub fn register_action_renderer(
22077        &mut self,
22078        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22079    ) -> Subscription {
22080        let id = self.next_editor_action_id.post_inc();
22081        self.editor_actions
22082            .borrow_mut()
22083            .insert(id, Box::new(listener));
22084
22085        let editor_actions = self.editor_actions.clone();
22086        Subscription::new(move || {
22087            editor_actions.borrow_mut().remove(&id);
22088        })
22089    }
22090
22091    pub fn register_action<A: Action>(
22092        &mut self,
22093        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22094    ) -> Subscription {
22095        let id = self.next_editor_action_id.post_inc();
22096        let listener = Arc::new(listener);
22097        self.editor_actions.borrow_mut().insert(
22098            id,
22099            Box::new(move |_, window, _| {
22100                let listener = listener.clone();
22101                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22102                    let action = action.downcast_ref().unwrap();
22103                    if phase == DispatchPhase::Bubble {
22104                        listener(action, window, cx)
22105                    }
22106                })
22107            }),
22108        );
22109
22110        let editor_actions = self.editor_actions.clone();
22111        Subscription::new(move || {
22112            editor_actions.borrow_mut().remove(&id);
22113        })
22114    }
22115
22116    pub fn file_header_size(&self) -> u32 {
22117        FILE_HEADER_HEIGHT
22118    }
22119
22120    pub fn restore(
22121        &mut self,
22122        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22123        window: &mut Window,
22124        cx: &mut Context<Self>,
22125    ) {
22126        let workspace = self.workspace();
22127        let project = self.project();
22128        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22129            let mut tasks = Vec::new();
22130            for (buffer_id, changes) in revert_changes {
22131                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22132                    buffer.update(cx, |buffer, cx| {
22133                        buffer.edit(
22134                            changes
22135                                .into_iter()
22136                                .map(|(range, text)| (range, text.to_string())),
22137                            None,
22138                            cx,
22139                        );
22140                    });
22141
22142                    if let Some(project) =
22143                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22144                    {
22145                        project.update(cx, |project, cx| {
22146                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22147                        })
22148                    }
22149                }
22150            }
22151            tasks
22152        });
22153        cx.spawn_in(window, async move |_, cx| {
22154            for (buffer, task) in save_tasks {
22155                let result = task.await;
22156                if result.is_err() {
22157                    let Some(path) = buffer
22158                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22159                        .ok()
22160                    else {
22161                        continue;
22162                    };
22163                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22164                        let Some(task) = cx
22165                            .update_window_entity(workspace, |workspace, window, cx| {
22166                                workspace
22167                                    .open_path_preview(path, None, false, false, false, window, cx)
22168                            })
22169                            .ok()
22170                        else {
22171                            continue;
22172                        };
22173                        task.await.log_err();
22174                    }
22175                }
22176            }
22177        })
22178        .detach();
22179        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22180            selections.refresh()
22181        });
22182    }
22183
22184    pub fn to_pixel_point(
22185        &self,
22186        source: multi_buffer::Anchor,
22187        editor_snapshot: &EditorSnapshot,
22188        window: &mut Window,
22189    ) -> Option<gpui::Point<Pixels>> {
22190        let source_point = source.to_display_point(editor_snapshot);
22191        self.display_to_pixel_point(source_point, editor_snapshot, window)
22192    }
22193
22194    pub fn display_to_pixel_point(
22195        &self,
22196        source: DisplayPoint,
22197        editor_snapshot: &EditorSnapshot,
22198        window: &mut Window,
22199    ) -> Option<gpui::Point<Pixels>> {
22200        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22201        let text_layout_details = self.text_layout_details(window);
22202        let scroll_top = text_layout_details
22203            .scroll_anchor
22204            .scroll_position(editor_snapshot)
22205            .y;
22206
22207        if source.row().as_f64() < scroll_top.floor() {
22208            return None;
22209        }
22210        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22211        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22212        Some(gpui::Point::new(source_x, source_y))
22213    }
22214
22215    pub fn has_visible_completions_menu(&self) -> bool {
22216        !self.edit_prediction_preview_is_active()
22217            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22218                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22219            })
22220    }
22221
22222    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22223        if self.mode.is_minimap() {
22224            return;
22225        }
22226        self.addons
22227            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22228    }
22229
22230    pub fn unregister_addon<T: Addon>(&mut self) {
22231        self.addons.remove(&std::any::TypeId::of::<T>());
22232    }
22233
22234    pub fn addon<T: Addon>(&self) -> Option<&T> {
22235        let type_id = std::any::TypeId::of::<T>();
22236        self.addons
22237            .get(&type_id)
22238            .and_then(|item| item.to_any().downcast_ref::<T>())
22239    }
22240
22241    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22242        let type_id = std::any::TypeId::of::<T>();
22243        self.addons
22244            .get_mut(&type_id)
22245            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22246    }
22247
22248    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22249        let text_layout_details = self.text_layout_details(window);
22250        let style = &text_layout_details.editor_style;
22251        let font_id = window.text_system().resolve_font(&style.text.font());
22252        let font_size = style.text.font_size.to_pixels(window.rem_size());
22253        let line_height = style.text.line_height_in_pixels(window.rem_size());
22254        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22255        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22256
22257        CharacterDimensions {
22258            em_width,
22259            em_advance,
22260            line_height,
22261        }
22262    }
22263
22264    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22265        self.load_diff_task.clone()
22266    }
22267
22268    fn read_metadata_from_db(
22269        &mut self,
22270        item_id: u64,
22271        workspace_id: WorkspaceId,
22272        window: &mut Window,
22273        cx: &mut Context<Editor>,
22274    ) {
22275        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22276            && !self.mode.is_minimap()
22277            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22278        {
22279            let buffer_snapshot = OnceCell::new();
22280
22281            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22282                && !folds.is_empty()
22283            {
22284                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22285                self.fold_ranges(
22286                    folds
22287                        .into_iter()
22288                        .map(|(start, end)| {
22289                            snapshot.clip_offset(start, Bias::Left)
22290                                ..snapshot.clip_offset(end, Bias::Right)
22291                        })
22292                        .collect(),
22293                    false,
22294                    window,
22295                    cx,
22296                );
22297            }
22298
22299            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22300                && !selections.is_empty()
22301            {
22302                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22303                // skip adding the initial selection to selection history
22304                self.selection_history.mode = SelectionHistoryMode::Skipping;
22305                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22306                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22307                        snapshot.clip_offset(start, Bias::Left)
22308                            ..snapshot.clip_offset(end, Bias::Right)
22309                    }));
22310                });
22311                self.selection_history.mode = SelectionHistoryMode::Normal;
22312            };
22313        }
22314
22315        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22316    }
22317
22318    fn update_lsp_data(
22319        &mut self,
22320        for_buffer: Option<BufferId>,
22321        window: &mut Window,
22322        cx: &mut Context<'_, Self>,
22323    ) {
22324        self.pull_diagnostics(for_buffer, window, cx);
22325        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22326    }
22327
22328    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22329        if self.ignore_lsp_data() {
22330            return;
22331        }
22332        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22333            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22334        }
22335    }
22336
22337    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22338        if self.ignore_lsp_data() {
22339            return;
22340        }
22341
22342        if !self.registered_buffers.contains_key(&buffer_id)
22343            && let Some(project) = self.project.as_ref()
22344        {
22345            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22346                project.update(cx, |project, cx| {
22347                    self.registered_buffers.insert(
22348                        buffer_id,
22349                        project.register_buffer_with_language_servers(&buffer, cx),
22350                    );
22351                });
22352            } else {
22353                self.registered_buffers.remove(&buffer_id);
22354            }
22355        }
22356    }
22357
22358    fn ignore_lsp_data(&self) -> bool {
22359        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22360        // skip any LSP updates for it.
22361        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22362    }
22363}
22364
22365fn edit_for_markdown_paste<'a>(
22366    buffer: &MultiBufferSnapshot,
22367    range: Range<usize>,
22368    to_insert: &'a str,
22369    url: Option<url::Url>,
22370) -> (Range<usize>, Cow<'a, str>) {
22371    if url.is_none() {
22372        return (range, Cow::Borrowed(to_insert));
22373    };
22374
22375    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22376
22377    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22378        Cow::Borrowed(to_insert)
22379    } else {
22380        Cow::Owned(format!("[{old_text}]({to_insert})"))
22381    };
22382    (range, new_text)
22383}
22384
22385#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22386pub enum VimFlavor {
22387    Vim,
22388    Helix,
22389}
22390
22391pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22392    if vim_mode_setting::HelixModeSetting::try_get(cx)
22393        .map(|helix_mode| helix_mode.0)
22394        .unwrap_or(false)
22395    {
22396        Some(VimFlavor::Helix)
22397    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22398        .map(|vim_mode| vim_mode.0)
22399        .unwrap_or(false)
22400    {
22401        Some(VimFlavor::Vim)
22402    } else {
22403        None // neither vim nor helix mode
22404    }
22405}
22406
22407fn process_completion_for_edit(
22408    completion: &Completion,
22409    intent: CompletionIntent,
22410    buffer: &Entity<Buffer>,
22411    cursor_position: &text::Anchor,
22412    cx: &mut Context<Editor>,
22413) -> CompletionEdit {
22414    let buffer = buffer.read(cx);
22415    let buffer_snapshot = buffer.snapshot();
22416    let (snippet, new_text) = if completion.is_snippet() {
22417        let mut snippet_source = completion.new_text.clone();
22418        // Workaround for typescript language server issues so that methods don't expand within
22419        // strings and functions with type expressions. The previous point is used because the query
22420        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22421        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22422        let previous_point = if previous_point.column > 0 {
22423            cursor_position.to_previous_offset(&buffer_snapshot)
22424        } else {
22425            cursor_position.to_offset(&buffer_snapshot)
22426        };
22427        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22428            && scope.prefers_label_for_snippet_in_completion()
22429            && let Some(label) = completion.label()
22430            && matches!(
22431                completion.kind(),
22432                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22433            )
22434        {
22435            snippet_source = label;
22436        }
22437        match Snippet::parse(&snippet_source).log_err() {
22438            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22439            None => (None, completion.new_text.clone()),
22440        }
22441    } else {
22442        (None, completion.new_text.clone())
22443    };
22444
22445    let mut range_to_replace = {
22446        let replace_range = &completion.replace_range;
22447        if let CompletionSource::Lsp {
22448            insert_range: Some(insert_range),
22449            ..
22450        } = &completion.source
22451        {
22452            debug_assert_eq!(
22453                insert_range.start, replace_range.start,
22454                "insert_range and replace_range should start at the same position"
22455            );
22456            debug_assert!(
22457                insert_range
22458                    .start
22459                    .cmp(cursor_position, &buffer_snapshot)
22460                    .is_le(),
22461                "insert_range should start before or at cursor position"
22462            );
22463            debug_assert!(
22464                replace_range
22465                    .start
22466                    .cmp(cursor_position, &buffer_snapshot)
22467                    .is_le(),
22468                "replace_range should start before or at cursor position"
22469            );
22470
22471            let should_replace = match intent {
22472                CompletionIntent::CompleteWithInsert => false,
22473                CompletionIntent::CompleteWithReplace => true,
22474                CompletionIntent::Complete | CompletionIntent::Compose => {
22475                    let insert_mode =
22476                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22477                            .completions
22478                            .lsp_insert_mode;
22479                    match insert_mode {
22480                        LspInsertMode::Insert => false,
22481                        LspInsertMode::Replace => true,
22482                        LspInsertMode::ReplaceSubsequence => {
22483                            let mut text_to_replace = buffer.chars_for_range(
22484                                buffer.anchor_before(replace_range.start)
22485                                    ..buffer.anchor_after(replace_range.end),
22486                            );
22487                            let mut current_needle = text_to_replace.next();
22488                            for haystack_ch in completion.label.text.chars() {
22489                                if let Some(needle_ch) = current_needle
22490                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22491                                {
22492                                    current_needle = text_to_replace.next();
22493                                }
22494                            }
22495                            current_needle.is_none()
22496                        }
22497                        LspInsertMode::ReplaceSuffix => {
22498                            if replace_range
22499                                .end
22500                                .cmp(cursor_position, &buffer_snapshot)
22501                                .is_gt()
22502                            {
22503                                let range_after_cursor = *cursor_position..replace_range.end;
22504                                let text_after_cursor = buffer
22505                                    .text_for_range(
22506                                        buffer.anchor_before(range_after_cursor.start)
22507                                            ..buffer.anchor_after(range_after_cursor.end),
22508                                    )
22509                                    .collect::<String>()
22510                                    .to_ascii_lowercase();
22511                                completion
22512                                    .label
22513                                    .text
22514                                    .to_ascii_lowercase()
22515                                    .ends_with(&text_after_cursor)
22516                            } else {
22517                                true
22518                            }
22519                        }
22520                    }
22521                }
22522            };
22523
22524            if should_replace {
22525                replace_range.clone()
22526            } else {
22527                insert_range.clone()
22528            }
22529        } else {
22530            replace_range.clone()
22531        }
22532    };
22533
22534    if range_to_replace
22535        .end
22536        .cmp(cursor_position, &buffer_snapshot)
22537        .is_lt()
22538    {
22539        range_to_replace.end = *cursor_position;
22540    }
22541
22542    CompletionEdit {
22543        new_text,
22544        replace_range: range_to_replace.to_offset(buffer),
22545        snippet,
22546    }
22547}
22548
22549struct CompletionEdit {
22550    new_text: String,
22551    replace_range: Range<usize>,
22552    snippet: Option<Snippet>,
22553}
22554
22555fn insert_extra_newline_brackets(
22556    buffer: &MultiBufferSnapshot,
22557    range: Range<usize>,
22558    language: &language::LanguageScope,
22559) -> bool {
22560    let leading_whitespace_len = buffer
22561        .reversed_chars_at(range.start)
22562        .take_while(|c| c.is_whitespace() && *c != '\n')
22563        .map(|c| c.len_utf8())
22564        .sum::<usize>();
22565    let trailing_whitespace_len = buffer
22566        .chars_at(range.end)
22567        .take_while(|c| c.is_whitespace() && *c != '\n')
22568        .map(|c| c.len_utf8())
22569        .sum::<usize>();
22570    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22571
22572    language.brackets().any(|(pair, enabled)| {
22573        let pair_start = pair.start.trim_end();
22574        let pair_end = pair.end.trim_start();
22575
22576        enabled
22577            && pair.newline
22578            && buffer.contains_str_at(range.end, pair_end)
22579            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22580    })
22581}
22582
22583fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22584    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22585        [(buffer, range, _)] => (*buffer, range.clone()),
22586        _ => return false,
22587    };
22588    let pair = {
22589        let mut result: Option<BracketMatch> = None;
22590
22591        for pair in buffer
22592            .all_bracket_ranges(range.clone())
22593            .filter(move |pair| {
22594                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22595            })
22596        {
22597            let len = pair.close_range.end - pair.open_range.start;
22598
22599            if let Some(existing) = &result {
22600                let existing_len = existing.close_range.end - existing.open_range.start;
22601                if len > existing_len {
22602                    continue;
22603                }
22604            }
22605
22606            result = Some(pair);
22607        }
22608
22609        result
22610    };
22611    let Some(pair) = pair else {
22612        return false;
22613    };
22614    pair.newline_only
22615        && buffer
22616            .chars_for_range(pair.open_range.end..range.start)
22617            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22618            .all(|c| c.is_whitespace() && c != '\n')
22619}
22620
22621fn update_uncommitted_diff_for_buffer(
22622    editor: Entity<Editor>,
22623    project: &Entity<Project>,
22624    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22625    buffer: Entity<MultiBuffer>,
22626    cx: &mut App,
22627) -> Task<()> {
22628    let mut tasks = Vec::new();
22629    project.update(cx, |project, cx| {
22630        for buffer in buffers {
22631            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22632                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22633            }
22634        }
22635    });
22636    cx.spawn(async move |cx| {
22637        let diffs = future::join_all(tasks).await;
22638        if editor
22639            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22640            .unwrap_or(false)
22641        {
22642            return;
22643        }
22644
22645        buffer
22646            .update(cx, |buffer, cx| {
22647                for diff in diffs.into_iter().flatten() {
22648                    buffer.add_diff(diff, cx);
22649                }
22650            })
22651            .ok();
22652    })
22653}
22654
22655fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22656    let tab_size = tab_size.get() as usize;
22657    let mut width = offset;
22658
22659    for ch in text.chars() {
22660        width += if ch == '\t' {
22661            tab_size - (width % tab_size)
22662        } else {
22663            1
22664        };
22665    }
22666
22667    width - offset
22668}
22669
22670#[cfg(test)]
22671mod tests {
22672    use super::*;
22673
22674    #[test]
22675    fn test_string_size_with_expanded_tabs() {
22676        let nz = |val| NonZeroU32::new(val).unwrap();
22677        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22678        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22679        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22680        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22681        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22682        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22683        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22684        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22685    }
22686}
22687
22688/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22689struct WordBreakingTokenizer<'a> {
22690    input: &'a str,
22691}
22692
22693impl<'a> WordBreakingTokenizer<'a> {
22694    fn new(input: &'a str) -> Self {
22695        Self { input }
22696    }
22697}
22698
22699fn is_char_ideographic(ch: char) -> bool {
22700    use unicode_script::Script::*;
22701    use unicode_script::UnicodeScript;
22702    matches!(ch.script(), Han | Tangut | Yi)
22703}
22704
22705fn is_grapheme_ideographic(text: &str) -> bool {
22706    text.chars().any(is_char_ideographic)
22707}
22708
22709fn is_grapheme_whitespace(text: &str) -> bool {
22710    text.chars().any(|x| x.is_whitespace())
22711}
22712
22713fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22714    text.chars()
22715        .next()
22716        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22717}
22718
22719#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22720enum WordBreakToken<'a> {
22721    Word { token: &'a str, grapheme_len: usize },
22722    InlineWhitespace { token: &'a str, grapheme_len: usize },
22723    Newline,
22724}
22725
22726impl<'a> Iterator for WordBreakingTokenizer<'a> {
22727    /// Yields a span, the count of graphemes in the token, and whether it was
22728    /// whitespace. Note that it also breaks at word boundaries.
22729    type Item = WordBreakToken<'a>;
22730
22731    fn next(&mut self) -> Option<Self::Item> {
22732        use unicode_segmentation::UnicodeSegmentation;
22733        if self.input.is_empty() {
22734            return None;
22735        }
22736
22737        let mut iter = self.input.graphemes(true).peekable();
22738        let mut offset = 0;
22739        let mut grapheme_len = 0;
22740        if let Some(first_grapheme) = iter.next() {
22741            let is_newline = first_grapheme == "\n";
22742            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22743            offset += first_grapheme.len();
22744            grapheme_len += 1;
22745            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22746                if let Some(grapheme) = iter.peek().copied()
22747                    && should_stay_with_preceding_ideograph(grapheme)
22748                {
22749                    offset += grapheme.len();
22750                    grapheme_len += 1;
22751                }
22752            } else {
22753                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22754                let mut next_word_bound = words.peek().copied();
22755                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22756                    next_word_bound = words.next();
22757                }
22758                while let Some(grapheme) = iter.peek().copied() {
22759                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22760                        break;
22761                    };
22762                    if is_grapheme_whitespace(grapheme) != is_whitespace
22763                        || (grapheme == "\n") != is_newline
22764                    {
22765                        break;
22766                    };
22767                    offset += grapheme.len();
22768                    grapheme_len += 1;
22769                    iter.next();
22770                }
22771            }
22772            let token = &self.input[..offset];
22773            self.input = &self.input[offset..];
22774            if token == "\n" {
22775                Some(WordBreakToken::Newline)
22776            } else if is_whitespace {
22777                Some(WordBreakToken::InlineWhitespace {
22778                    token,
22779                    grapheme_len,
22780                })
22781            } else {
22782                Some(WordBreakToken::Word {
22783                    token,
22784                    grapheme_len,
22785                })
22786            }
22787        } else {
22788            None
22789        }
22790    }
22791}
22792
22793#[test]
22794fn test_word_breaking_tokenizer() {
22795    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22796        ("", &[]),
22797        ("  ", &[whitespace("  ", 2)]),
22798        ("Ʒ", &[word("Ʒ", 1)]),
22799        ("Ǽ", &[word("Ǽ", 1)]),
22800        ("", &[word("", 1)]),
22801        ("⋑⋑", &[word("⋑⋑", 2)]),
22802        (
22803            "原理,进而",
22804            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22805        ),
22806        (
22807            "hello world",
22808            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22809        ),
22810        (
22811            "hello, world",
22812            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22813        ),
22814        (
22815            "  hello world",
22816            &[
22817                whitespace("  ", 2),
22818                word("hello", 5),
22819                whitespace(" ", 1),
22820                word("world", 5),
22821            ],
22822        ),
22823        (
22824            "这是什么 \n 钢笔",
22825            &[
22826                word("", 1),
22827                word("", 1),
22828                word("", 1),
22829                word("", 1),
22830                whitespace(" ", 1),
22831                newline(),
22832                whitespace(" ", 1),
22833                word("", 1),
22834                word("", 1),
22835            ],
22836        ),
22837        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22838    ];
22839
22840    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22841        WordBreakToken::Word {
22842            token,
22843            grapheme_len,
22844        }
22845    }
22846
22847    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22848        WordBreakToken::InlineWhitespace {
22849            token,
22850            grapheme_len,
22851        }
22852    }
22853
22854    fn newline() -> WordBreakToken<'static> {
22855        WordBreakToken::Newline
22856    }
22857
22858    for (input, result) in tests {
22859        assert_eq!(
22860            WordBreakingTokenizer::new(input)
22861                .collect::<Vec<_>>()
22862                .as_slice(),
22863            *result,
22864        );
22865    }
22866}
22867
22868fn wrap_with_prefix(
22869    first_line_prefix: String,
22870    subsequent_lines_prefix: String,
22871    unwrapped_text: String,
22872    wrap_column: usize,
22873    tab_size: NonZeroU32,
22874    preserve_existing_whitespace: bool,
22875) -> String {
22876    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22877    let subsequent_lines_prefix_len =
22878        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22879    let mut wrapped_text = String::new();
22880    let mut current_line = first_line_prefix;
22881    let mut is_first_line = true;
22882
22883    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22884    let mut current_line_len = first_line_prefix_len;
22885    let mut in_whitespace = false;
22886    for token in tokenizer {
22887        let have_preceding_whitespace = in_whitespace;
22888        match token {
22889            WordBreakToken::Word {
22890                token,
22891                grapheme_len,
22892            } => {
22893                in_whitespace = false;
22894                let current_prefix_len = if is_first_line {
22895                    first_line_prefix_len
22896                } else {
22897                    subsequent_lines_prefix_len
22898                };
22899                if current_line_len + grapheme_len > wrap_column
22900                    && current_line_len != current_prefix_len
22901                {
22902                    wrapped_text.push_str(current_line.trim_end());
22903                    wrapped_text.push('\n');
22904                    is_first_line = false;
22905                    current_line = subsequent_lines_prefix.clone();
22906                    current_line_len = subsequent_lines_prefix_len;
22907                }
22908                current_line.push_str(token);
22909                current_line_len += grapheme_len;
22910            }
22911            WordBreakToken::InlineWhitespace {
22912                mut token,
22913                mut grapheme_len,
22914            } => {
22915                in_whitespace = true;
22916                if have_preceding_whitespace && !preserve_existing_whitespace {
22917                    continue;
22918                }
22919                if !preserve_existing_whitespace {
22920                    // Keep a single whitespace grapheme as-is
22921                    if let Some(first) =
22922                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22923                    {
22924                        token = first;
22925                    } else {
22926                        token = " ";
22927                    }
22928                    grapheme_len = 1;
22929                }
22930                let current_prefix_len = if is_first_line {
22931                    first_line_prefix_len
22932                } else {
22933                    subsequent_lines_prefix_len
22934                };
22935                if current_line_len + grapheme_len > wrap_column {
22936                    wrapped_text.push_str(current_line.trim_end());
22937                    wrapped_text.push('\n');
22938                    is_first_line = false;
22939                    current_line = subsequent_lines_prefix.clone();
22940                    current_line_len = subsequent_lines_prefix_len;
22941                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22942                    current_line.push_str(token);
22943                    current_line_len += grapheme_len;
22944                }
22945            }
22946            WordBreakToken::Newline => {
22947                in_whitespace = true;
22948                let current_prefix_len = if is_first_line {
22949                    first_line_prefix_len
22950                } else {
22951                    subsequent_lines_prefix_len
22952                };
22953                if preserve_existing_whitespace {
22954                    wrapped_text.push_str(current_line.trim_end());
22955                    wrapped_text.push('\n');
22956                    is_first_line = false;
22957                    current_line = subsequent_lines_prefix.clone();
22958                    current_line_len = subsequent_lines_prefix_len;
22959                } else if have_preceding_whitespace {
22960                    continue;
22961                } else if current_line_len + 1 > wrap_column
22962                    && current_line_len != current_prefix_len
22963                {
22964                    wrapped_text.push_str(current_line.trim_end());
22965                    wrapped_text.push('\n');
22966                    is_first_line = false;
22967                    current_line = subsequent_lines_prefix.clone();
22968                    current_line_len = subsequent_lines_prefix_len;
22969                } else if current_line_len != current_prefix_len {
22970                    current_line.push(' ');
22971                    current_line_len += 1;
22972                }
22973            }
22974        }
22975    }
22976
22977    if !current_line.is_empty() {
22978        wrapped_text.push_str(&current_line);
22979    }
22980    wrapped_text
22981}
22982
22983#[test]
22984fn test_wrap_with_prefix() {
22985    assert_eq!(
22986        wrap_with_prefix(
22987            "# ".to_string(),
22988            "# ".to_string(),
22989            "abcdefg".to_string(),
22990            4,
22991            NonZeroU32::new(4).unwrap(),
22992            false,
22993        ),
22994        "# abcdefg"
22995    );
22996    assert_eq!(
22997        wrap_with_prefix(
22998            "".to_string(),
22999            "".to_string(),
23000            "\thello world".to_string(),
23001            8,
23002            NonZeroU32::new(4).unwrap(),
23003            false,
23004        ),
23005        "hello\nworld"
23006    );
23007    assert_eq!(
23008        wrap_with_prefix(
23009            "// ".to_string(),
23010            "// ".to_string(),
23011            "xx \nyy zz aa bb cc".to_string(),
23012            12,
23013            NonZeroU32::new(4).unwrap(),
23014            false,
23015        ),
23016        "// xx yy zz\n// aa bb cc"
23017    );
23018    assert_eq!(
23019        wrap_with_prefix(
23020            String::new(),
23021            String::new(),
23022            "这是什么 \n 钢笔".to_string(),
23023            3,
23024            NonZeroU32::new(4).unwrap(),
23025            false,
23026        ),
23027        "这是什\n么 钢\n"
23028    );
23029    assert_eq!(
23030        wrap_with_prefix(
23031            String::new(),
23032            String::new(),
23033            format!("foo{}bar", '\u{2009}'), // thin space
23034            80,
23035            NonZeroU32::new(4).unwrap(),
23036            false,
23037        ),
23038        format!("foo{}bar", '\u{2009}')
23039    );
23040}
23041
23042pub trait CollaborationHub {
23043    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23044    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23045    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23046}
23047
23048impl CollaborationHub for Entity<Project> {
23049    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23050        self.read(cx).collaborators()
23051    }
23052
23053    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23054        self.read(cx).user_store().read(cx).participant_indices()
23055    }
23056
23057    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23058        let this = self.read(cx);
23059        let user_ids = this.collaborators().values().map(|c| c.user_id);
23060        this.user_store().read(cx).participant_names(user_ids, cx)
23061    }
23062}
23063
23064pub trait SemanticsProvider {
23065    fn hover(
23066        &self,
23067        buffer: &Entity<Buffer>,
23068        position: text::Anchor,
23069        cx: &mut App,
23070    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23071
23072    fn inline_values(
23073        &self,
23074        buffer_handle: Entity<Buffer>,
23075        range: Range<text::Anchor>,
23076        cx: &mut App,
23077    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23078
23079    fn applicable_inlay_chunks(
23080        &self,
23081        buffer: &Entity<Buffer>,
23082        ranges: &[Range<text::Anchor>],
23083        cx: &mut App,
23084    ) -> Vec<Range<BufferRow>>;
23085
23086    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23087
23088    fn inlay_hints(
23089        &self,
23090        invalidate: InvalidationStrategy,
23091        buffer: Entity<Buffer>,
23092        ranges: Vec<Range<text::Anchor>>,
23093        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23094        cx: &mut App,
23095    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23096
23097    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23098
23099    fn document_highlights(
23100        &self,
23101        buffer: &Entity<Buffer>,
23102        position: text::Anchor,
23103        cx: &mut App,
23104    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23105
23106    fn definitions(
23107        &self,
23108        buffer: &Entity<Buffer>,
23109        position: text::Anchor,
23110        kind: GotoDefinitionKind,
23111        cx: &mut App,
23112    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23113
23114    fn range_for_rename(
23115        &self,
23116        buffer: &Entity<Buffer>,
23117        position: text::Anchor,
23118        cx: &mut App,
23119    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23120
23121    fn perform_rename(
23122        &self,
23123        buffer: &Entity<Buffer>,
23124        position: text::Anchor,
23125        new_name: String,
23126        cx: &mut App,
23127    ) -> Option<Task<Result<ProjectTransaction>>>;
23128}
23129
23130pub trait CompletionProvider {
23131    fn completions(
23132        &self,
23133        excerpt_id: ExcerptId,
23134        buffer: &Entity<Buffer>,
23135        buffer_position: text::Anchor,
23136        trigger: CompletionContext,
23137        window: &mut Window,
23138        cx: &mut Context<Editor>,
23139    ) -> Task<Result<Vec<CompletionResponse>>>;
23140
23141    fn resolve_completions(
23142        &self,
23143        _buffer: Entity<Buffer>,
23144        _completion_indices: Vec<usize>,
23145        _completions: Rc<RefCell<Box<[Completion]>>>,
23146        _cx: &mut Context<Editor>,
23147    ) -> Task<Result<bool>> {
23148        Task::ready(Ok(false))
23149    }
23150
23151    fn apply_additional_edits_for_completion(
23152        &self,
23153        _buffer: Entity<Buffer>,
23154        _completions: Rc<RefCell<Box<[Completion]>>>,
23155        _completion_index: usize,
23156        _push_to_history: bool,
23157        _cx: &mut Context<Editor>,
23158    ) -> Task<Result<Option<language::Transaction>>> {
23159        Task::ready(Ok(None))
23160    }
23161
23162    fn is_completion_trigger(
23163        &self,
23164        buffer: &Entity<Buffer>,
23165        position: language::Anchor,
23166        text: &str,
23167        trigger_in_words: bool,
23168        menu_is_open: bool,
23169        cx: &mut Context<Editor>,
23170    ) -> bool;
23171
23172    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23173
23174    fn sort_completions(&self) -> bool {
23175        true
23176    }
23177
23178    fn filter_completions(&self) -> bool {
23179        true
23180    }
23181
23182    fn show_snippets(&self) -> bool {
23183        false
23184    }
23185}
23186
23187pub trait CodeActionProvider {
23188    fn id(&self) -> Arc<str>;
23189
23190    fn code_actions(
23191        &self,
23192        buffer: &Entity<Buffer>,
23193        range: Range<text::Anchor>,
23194        window: &mut Window,
23195        cx: &mut App,
23196    ) -> Task<Result<Vec<CodeAction>>>;
23197
23198    fn apply_code_action(
23199        &self,
23200        buffer_handle: Entity<Buffer>,
23201        action: CodeAction,
23202        excerpt_id: ExcerptId,
23203        push_to_history: bool,
23204        window: &mut Window,
23205        cx: &mut App,
23206    ) -> Task<Result<ProjectTransaction>>;
23207}
23208
23209impl CodeActionProvider for Entity<Project> {
23210    fn id(&self) -> Arc<str> {
23211        "project".into()
23212    }
23213
23214    fn code_actions(
23215        &self,
23216        buffer: &Entity<Buffer>,
23217        range: Range<text::Anchor>,
23218        _window: &mut Window,
23219        cx: &mut App,
23220    ) -> Task<Result<Vec<CodeAction>>> {
23221        self.update(cx, |project, cx| {
23222            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23223            let code_actions = project.code_actions(buffer, range, None, cx);
23224            cx.background_spawn(async move {
23225                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23226                Ok(code_lens_actions
23227                    .context("code lens fetch")?
23228                    .into_iter()
23229                    .flatten()
23230                    .chain(
23231                        code_actions
23232                            .context("code action fetch")?
23233                            .into_iter()
23234                            .flatten(),
23235                    )
23236                    .collect())
23237            })
23238        })
23239    }
23240
23241    fn apply_code_action(
23242        &self,
23243        buffer_handle: Entity<Buffer>,
23244        action: CodeAction,
23245        _excerpt_id: ExcerptId,
23246        push_to_history: bool,
23247        _window: &mut Window,
23248        cx: &mut App,
23249    ) -> Task<Result<ProjectTransaction>> {
23250        self.update(cx, |project, cx| {
23251            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23252        })
23253    }
23254}
23255
23256fn snippet_completions(
23257    project: &Project,
23258    buffer: &Entity<Buffer>,
23259    buffer_anchor: text::Anchor,
23260    classifier: CharClassifier,
23261    cx: &mut App,
23262) -> Task<Result<CompletionResponse>> {
23263    let languages = buffer.read(cx).languages_at(buffer_anchor);
23264    let snippet_store = project.snippets().read(cx);
23265
23266    let scopes: Vec<_> = languages
23267        .iter()
23268        .filter_map(|language| {
23269            let language_name = language.lsp_id();
23270            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23271
23272            if snippets.is_empty() {
23273                None
23274            } else {
23275                Some((language.default_scope(), snippets))
23276            }
23277        })
23278        .collect();
23279
23280    if scopes.is_empty() {
23281        return Task::ready(Ok(CompletionResponse {
23282            completions: vec![],
23283            display_options: CompletionDisplayOptions::default(),
23284            is_incomplete: false,
23285        }));
23286    }
23287
23288    let snapshot = buffer.read(cx).text_snapshot();
23289    let executor = cx.background_executor().clone();
23290
23291    cx.background_spawn(async move {
23292        let is_word_char = |c| classifier.is_word(c);
23293
23294        let mut is_incomplete = false;
23295        let mut completions: Vec<Completion> = Vec::new();
23296
23297        const MAX_PREFIX_LEN: usize = 128;
23298        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23299        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23300        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23301
23302        let max_buffer_window: String = snapshot
23303            .text_for_range(window_start..buffer_offset)
23304            .collect();
23305
23306        if max_buffer_window.is_empty() {
23307            return Ok(CompletionResponse {
23308                completions: vec![],
23309                display_options: CompletionDisplayOptions::default(),
23310                is_incomplete: true,
23311            });
23312        }
23313
23314        for (_scope, snippets) in scopes.into_iter() {
23315            // Sort snippets by word count to match longer snippet prefixes first.
23316            let mut sorted_snippet_candidates = snippets
23317                .iter()
23318                .enumerate()
23319                .flat_map(|(snippet_ix, snippet)| {
23320                    snippet
23321                        .prefix
23322                        .iter()
23323                        .enumerate()
23324                        .map(move |(prefix_ix, prefix)| {
23325                            let word_count =
23326                                snippet_candidate_suffixes(prefix, is_word_char).count();
23327                            ((snippet_ix, prefix_ix), prefix, word_count)
23328                        })
23329                })
23330                .collect_vec();
23331            sorted_snippet_candidates
23332                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23333
23334            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23335
23336            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23337                .take(
23338                    sorted_snippet_candidates
23339                        .first()
23340                        .map(|(_, _, word_count)| *word_count)
23341                        .unwrap_or_default(),
23342                )
23343                .collect_vec();
23344
23345            const MAX_RESULTS: usize = 100;
23346            // Each match also remembers how many characters from the buffer it consumed
23347            let mut matches: Vec<(StringMatch, usize)> = vec![];
23348
23349            let mut snippet_list_cutoff_index = 0;
23350            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23351                let word_count = buffer_index + 1;
23352                // Increase `snippet_list_cutoff_index` until we have all of the
23353                // snippets with sufficiently many words.
23354                while sorted_snippet_candidates
23355                    .get(snippet_list_cutoff_index)
23356                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23357                        *snippet_word_count >= word_count
23358                    })
23359                {
23360                    snippet_list_cutoff_index += 1;
23361                }
23362
23363                // Take only the candidates with at least `word_count` many words
23364                let snippet_candidates_at_word_len =
23365                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23366
23367                let candidates = snippet_candidates_at_word_len
23368                    .iter()
23369                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23370                    .enumerate() // index in `sorted_snippet_candidates`
23371                    // First char must match
23372                    .filter(|(_ix, prefix)| {
23373                        itertools::equal(
23374                            prefix
23375                                .chars()
23376                                .next()
23377                                .into_iter()
23378                                .flat_map(|c| c.to_lowercase()),
23379                            buffer_window
23380                                .chars()
23381                                .next()
23382                                .into_iter()
23383                                .flat_map(|c| c.to_lowercase()),
23384                        )
23385                    })
23386                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23387                    .collect::<Vec<StringMatchCandidate>>();
23388
23389                matches.extend(
23390                    fuzzy::match_strings(
23391                        &candidates,
23392                        &buffer_window,
23393                        buffer_window.chars().any(|c| c.is_uppercase()),
23394                        true,
23395                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23396                        &Default::default(),
23397                        executor.clone(),
23398                    )
23399                    .await
23400                    .into_iter()
23401                    .map(|string_match| (string_match, buffer_window.len())),
23402                );
23403
23404                if matches.len() >= MAX_RESULTS {
23405                    break;
23406                }
23407            }
23408
23409            let to_lsp = |point: &text::Anchor| {
23410                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23411                point_to_lsp(end)
23412            };
23413            let lsp_end = to_lsp(&buffer_anchor);
23414
23415            if matches.len() >= MAX_RESULTS {
23416                is_incomplete = true;
23417            }
23418
23419            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23420                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23421                    sorted_snippet_candidates[string_match.candidate_id];
23422                let snippet = &snippets[snippet_index];
23423                let start = buffer_offset - buffer_window_len;
23424                let start = snapshot.anchor_before(start);
23425                let range = start..buffer_anchor;
23426                let lsp_start = to_lsp(&start);
23427                let lsp_range = lsp::Range {
23428                    start: lsp_start,
23429                    end: lsp_end,
23430                };
23431                Completion {
23432                    replace_range: range,
23433                    new_text: snippet.body.clone(),
23434                    source: CompletionSource::Lsp {
23435                        insert_range: None,
23436                        server_id: LanguageServerId(usize::MAX),
23437                        resolved: true,
23438                        lsp_completion: Box::new(lsp::CompletionItem {
23439                            label: snippet.prefix.first().unwrap().clone(),
23440                            kind: Some(CompletionItemKind::SNIPPET),
23441                            label_details: snippet.description.as_ref().map(|description| {
23442                                lsp::CompletionItemLabelDetails {
23443                                    detail: Some(description.clone()),
23444                                    description: None,
23445                                }
23446                            }),
23447                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23448                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23449                                lsp::InsertReplaceEdit {
23450                                    new_text: snippet.body.clone(),
23451                                    insert: lsp_range,
23452                                    replace: lsp_range,
23453                                },
23454                            )),
23455                            filter_text: Some(snippet.body.clone()),
23456                            sort_text: Some(char::MAX.to_string()),
23457                            ..lsp::CompletionItem::default()
23458                        }),
23459                        lsp_defaults: None,
23460                    },
23461                    label: CodeLabel {
23462                        text: matching_prefix.clone(),
23463                        runs: Vec::new(),
23464                        filter_range: 0..matching_prefix.len(),
23465                    },
23466                    icon_path: None,
23467                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23468                        single_line: snippet.name.clone().into(),
23469                        plain_text: snippet
23470                            .description
23471                            .clone()
23472                            .map(|description| description.into()),
23473                    }),
23474                    insert_text_mode: None,
23475                    confirm: None,
23476                    match_start: Some(start),
23477                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23478                }
23479            }));
23480        }
23481
23482        Ok(CompletionResponse {
23483            completions,
23484            display_options: CompletionDisplayOptions::default(),
23485            is_incomplete,
23486        })
23487    })
23488}
23489
23490impl CompletionProvider for Entity<Project> {
23491    fn completions(
23492        &self,
23493        _excerpt_id: ExcerptId,
23494        buffer: &Entity<Buffer>,
23495        buffer_position: text::Anchor,
23496        options: CompletionContext,
23497        _window: &mut Window,
23498        cx: &mut Context<Editor>,
23499    ) -> Task<Result<Vec<CompletionResponse>>> {
23500        self.update(cx, |project, cx| {
23501            let task = project.completions(buffer, buffer_position, options, cx);
23502            cx.background_spawn(task)
23503        })
23504    }
23505
23506    fn resolve_completions(
23507        &self,
23508        buffer: Entity<Buffer>,
23509        completion_indices: Vec<usize>,
23510        completions: Rc<RefCell<Box<[Completion]>>>,
23511        cx: &mut Context<Editor>,
23512    ) -> Task<Result<bool>> {
23513        self.update(cx, |project, cx| {
23514            project.lsp_store().update(cx, |lsp_store, cx| {
23515                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23516            })
23517        })
23518    }
23519
23520    fn apply_additional_edits_for_completion(
23521        &self,
23522        buffer: Entity<Buffer>,
23523        completions: Rc<RefCell<Box<[Completion]>>>,
23524        completion_index: usize,
23525        push_to_history: bool,
23526        cx: &mut Context<Editor>,
23527    ) -> Task<Result<Option<language::Transaction>>> {
23528        self.update(cx, |project, cx| {
23529            project.lsp_store().update(cx, |lsp_store, cx| {
23530                lsp_store.apply_additional_edits_for_completion(
23531                    buffer,
23532                    completions,
23533                    completion_index,
23534                    push_to_history,
23535                    cx,
23536                )
23537            })
23538        })
23539    }
23540
23541    fn is_completion_trigger(
23542        &self,
23543        buffer: &Entity<Buffer>,
23544        position: language::Anchor,
23545        text: &str,
23546        trigger_in_words: bool,
23547        menu_is_open: bool,
23548        cx: &mut Context<Editor>,
23549    ) -> bool {
23550        let mut chars = text.chars();
23551        let char = if let Some(char) = chars.next() {
23552            char
23553        } else {
23554            return false;
23555        };
23556        if chars.next().is_some() {
23557            return false;
23558        }
23559
23560        let buffer = buffer.read(cx);
23561        let snapshot = buffer.snapshot();
23562        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23563            return false;
23564        }
23565        let classifier = snapshot
23566            .char_classifier_at(position)
23567            .scope_context(Some(CharScopeContext::Completion));
23568        if trigger_in_words && classifier.is_word(char) {
23569            return true;
23570        }
23571
23572        buffer.completion_triggers().contains(text)
23573    }
23574
23575    fn show_snippets(&self) -> bool {
23576        true
23577    }
23578}
23579
23580impl SemanticsProvider for Entity<Project> {
23581    fn hover(
23582        &self,
23583        buffer: &Entity<Buffer>,
23584        position: text::Anchor,
23585        cx: &mut App,
23586    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23587        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23588    }
23589
23590    fn document_highlights(
23591        &self,
23592        buffer: &Entity<Buffer>,
23593        position: text::Anchor,
23594        cx: &mut App,
23595    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23596        Some(self.update(cx, |project, cx| {
23597            project.document_highlights(buffer, position, cx)
23598        }))
23599    }
23600
23601    fn definitions(
23602        &self,
23603        buffer: &Entity<Buffer>,
23604        position: text::Anchor,
23605        kind: GotoDefinitionKind,
23606        cx: &mut App,
23607    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23608        Some(self.update(cx, |project, cx| match kind {
23609            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23610            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23611            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23612            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23613        }))
23614    }
23615
23616    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23617        self.update(cx, |project, cx| {
23618            if project
23619                .active_debug_session(cx)
23620                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23621            {
23622                return true;
23623            }
23624
23625            buffer.update(cx, |buffer, cx| {
23626                project.any_language_server_supports_inlay_hints(buffer, cx)
23627            })
23628        })
23629    }
23630
23631    fn inline_values(
23632        &self,
23633        buffer_handle: Entity<Buffer>,
23634        range: Range<text::Anchor>,
23635        cx: &mut App,
23636    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23637        self.update(cx, |project, cx| {
23638            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23639
23640            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23641        })
23642    }
23643
23644    fn applicable_inlay_chunks(
23645        &self,
23646        buffer: &Entity<Buffer>,
23647        ranges: &[Range<text::Anchor>],
23648        cx: &mut App,
23649    ) -> Vec<Range<BufferRow>> {
23650        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23651            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23652        })
23653    }
23654
23655    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23656        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23657            lsp_store.invalidate_inlay_hints(for_buffers)
23658        });
23659    }
23660
23661    fn inlay_hints(
23662        &self,
23663        invalidate: InvalidationStrategy,
23664        buffer: Entity<Buffer>,
23665        ranges: Vec<Range<text::Anchor>>,
23666        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23667        cx: &mut App,
23668    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23669        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23670            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23671        }))
23672    }
23673
23674    fn range_for_rename(
23675        &self,
23676        buffer: &Entity<Buffer>,
23677        position: text::Anchor,
23678        cx: &mut App,
23679    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23680        Some(self.update(cx, |project, cx| {
23681            let buffer = buffer.clone();
23682            let task = project.prepare_rename(buffer.clone(), position, cx);
23683            cx.spawn(async move |_, cx| {
23684                Ok(match task.await? {
23685                    PrepareRenameResponse::Success(range) => Some(range),
23686                    PrepareRenameResponse::InvalidPosition => None,
23687                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23688                        // Fallback on using TreeSitter info to determine identifier range
23689                        buffer.read_with(cx, |buffer, _| {
23690                            let snapshot = buffer.snapshot();
23691                            let (range, kind) = snapshot.surrounding_word(position, None);
23692                            if kind != Some(CharKind::Word) {
23693                                return None;
23694                            }
23695                            Some(
23696                                snapshot.anchor_before(range.start)
23697                                    ..snapshot.anchor_after(range.end),
23698                            )
23699                        })?
23700                    }
23701                })
23702            })
23703        }))
23704    }
23705
23706    fn perform_rename(
23707        &self,
23708        buffer: &Entity<Buffer>,
23709        position: text::Anchor,
23710        new_name: String,
23711        cx: &mut App,
23712    ) -> Option<Task<Result<ProjectTransaction>>> {
23713        Some(self.update(cx, |project, cx| {
23714            project.perform_rename(buffer.clone(), position, new_name, cx)
23715        }))
23716    }
23717}
23718
23719fn consume_contiguous_rows(
23720    contiguous_row_selections: &mut Vec<Selection<Point>>,
23721    selection: &Selection<Point>,
23722    display_map: &DisplaySnapshot,
23723    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23724) -> (MultiBufferRow, MultiBufferRow) {
23725    contiguous_row_selections.push(selection.clone());
23726    let start_row = starting_row(selection, display_map);
23727    let mut end_row = ending_row(selection, display_map);
23728
23729    while let Some(next_selection) = selections.peek() {
23730        if next_selection.start.row <= end_row.0 {
23731            end_row = ending_row(next_selection, display_map);
23732            contiguous_row_selections.push(selections.next().unwrap().clone());
23733        } else {
23734            break;
23735        }
23736    }
23737    (start_row, end_row)
23738}
23739
23740fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23741    if selection.start.column > 0 {
23742        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23743    } else {
23744        MultiBufferRow(selection.start.row)
23745    }
23746}
23747
23748fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23749    if next_selection.end.column > 0 || next_selection.is_empty() {
23750        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23751    } else {
23752        MultiBufferRow(next_selection.end.row)
23753    }
23754}
23755
23756impl EditorSnapshot {
23757    pub fn remote_selections_in_range<'a>(
23758        &'a self,
23759        range: &'a Range<Anchor>,
23760        collaboration_hub: &dyn CollaborationHub,
23761        cx: &'a App,
23762    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23763        let participant_names = collaboration_hub.user_names(cx);
23764        let participant_indices = collaboration_hub.user_participant_indices(cx);
23765        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23766        let collaborators_by_replica_id = collaborators_by_peer_id
23767            .values()
23768            .map(|collaborator| (collaborator.replica_id, collaborator))
23769            .collect::<HashMap<_, _>>();
23770        self.buffer_snapshot()
23771            .selections_in_range(range, false)
23772            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23773                if replica_id == ReplicaId::AGENT {
23774                    Some(RemoteSelection {
23775                        replica_id,
23776                        selection,
23777                        cursor_shape,
23778                        line_mode,
23779                        collaborator_id: CollaboratorId::Agent,
23780                        user_name: Some("Agent".into()),
23781                        color: cx.theme().players().agent(),
23782                    })
23783                } else {
23784                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23785                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23786                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23787                    Some(RemoteSelection {
23788                        replica_id,
23789                        selection,
23790                        cursor_shape,
23791                        line_mode,
23792                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23793                        user_name,
23794                        color: if let Some(index) = participant_index {
23795                            cx.theme().players().color_for_participant(index.0)
23796                        } else {
23797                            cx.theme().players().absent()
23798                        },
23799                    })
23800                }
23801            })
23802    }
23803
23804    pub fn hunks_for_ranges(
23805        &self,
23806        ranges: impl IntoIterator<Item = Range<Point>>,
23807    ) -> Vec<MultiBufferDiffHunk> {
23808        let mut hunks = Vec::new();
23809        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23810            HashMap::default();
23811        for query_range in ranges {
23812            let query_rows =
23813                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23814            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23815                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23816            ) {
23817                // Include deleted hunks that are adjacent to the query range, because
23818                // otherwise they would be missed.
23819                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23820                if hunk.status().is_deleted() {
23821                    intersects_range |= hunk.row_range.start == query_rows.end;
23822                    intersects_range |= hunk.row_range.end == query_rows.start;
23823                }
23824                if intersects_range {
23825                    if !processed_buffer_rows
23826                        .entry(hunk.buffer_id)
23827                        .or_default()
23828                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23829                    {
23830                        continue;
23831                    }
23832                    hunks.push(hunk);
23833                }
23834            }
23835        }
23836
23837        hunks
23838    }
23839
23840    fn display_diff_hunks_for_rows<'a>(
23841        &'a self,
23842        display_rows: Range<DisplayRow>,
23843        folded_buffers: &'a HashSet<BufferId>,
23844    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23845        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23846        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23847
23848        self.buffer_snapshot()
23849            .diff_hunks_in_range(buffer_start..buffer_end)
23850            .filter_map(|hunk| {
23851                if folded_buffers.contains(&hunk.buffer_id) {
23852                    return None;
23853                }
23854
23855                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23856                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23857
23858                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23859                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23860
23861                let display_hunk = if hunk_display_start.column() != 0 {
23862                    DisplayDiffHunk::Folded {
23863                        display_row: hunk_display_start.row(),
23864                    }
23865                } else {
23866                    let mut end_row = hunk_display_end.row();
23867                    if hunk_display_end.column() > 0 {
23868                        end_row.0 += 1;
23869                    }
23870                    let is_created_file = hunk.is_created_file();
23871                    DisplayDiffHunk::Unfolded {
23872                        status: hunk.status(),
23873                        diff_base_byte_range: hunk.diff_base_byte_range,
23874                        display_row_range: hunk_display_start.row()..end_row,
23875                        multi_buffer_range: Anchor::range_in_buffer(
23876                            hunk.excerpt_id,
23877                            hunk.buffer_id,
23878                            hunk.buffer_range,
23879                        ),
23880                        is_created_file,
23881                    }
23882                };
23883
23884                Some(display_hunk)
23885            })
23886    }
23887
23888    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23889        self.display_snapshot
23890            .buffer_snapshot()
23891            .language_at(position)
23892    }
23893
23894    pub fn is_focused(&self) -> bool {
23895        self.is_focused
23896    }
23897
23898    pub fn placeholder_text(&self) -> Option<String> {
23899        self.placeholder_display_snapshot
23900            .as_ref()
23901            .map(|display_map| display_map.text())
23902    }
23903
23904    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23905        self.scroll_anchor.scroll_position(&self.display_snapshot)
23906    }
23907
23908    fn gutter_dimensions(
23909        &self,
23910        font_id: FontId,
23911        font_size: Pixels,
23912        max_line_number_width: Pixels,
23913        cx: &App,
23914    ) -> Option<GutterDimensions> {
23915        if !self.show_gutter {
23916            return None;
23917        }
23918
23919        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23920        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23921
23922        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23923            matches!(
23924                ProjectSettings::get_global(cx).git.git_gutter,
23925                GitGutterSetting::TrackedFiles
23926            )
23927        });
23928        let gutter_settings = EditorSettings::get_global(cx).gutter;
23929        let show_line_numbers = self
23930            .show_line_numbers
23931            .unwrap_or(gutter_settings.line_numbers);
23932        let line_gutter_width = if show_line_numbers {
23933            // Avoid flicker-like gutter resizes when the line number gains another digit by
23934            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23935            let min_width_for_number_on_gutter =
23936                ch_advance * gutter_settings.min_line_number_digits as f32;
23937            max_line_number_width.max(min_width_for_number_on_gutter)
23938        } else {
23939            0.0.into()
23940        };
23941
23942        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23943        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23944
23945        let git_blame_entries_width =
23946            self.git_blame_gutter_max_author_length
23947                .map(|max_author_length| {
23948                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23949                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23950
23951                    /// The number of characters to dedicate to gaps and margins.
23952                    const SPACING_WIDTH: usize = 4;
23953
23954                    let max_char_count = max_author_length.min(renderer.max_author_length())
23955                        + ::git::SHORT_SHA_LENGTH
23956                        + MAX_RELATIVE_TIMESTAMP.len()
23957                        + SPACING_WIDTH;
23958
23959                    ch_advance * max_char_count
23960                });
23961
23962        let is_singleton = self.buffer_snapshot().is_singleton();
23963
23964        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23965        left_padding += if !is_singleton {
23966            ch_width * 4.0
23967        } else if show_runnables || show_breakpoints {
23968            ch_width * 3.0
23969        } else if show_git_gutter && show_line_numbers {
23970            ch_width * 2.0
23971        } else if show_git_gutter || show_line_numbers {
23972            ch_width
23973        } else {
23974            px(0.)
23975        };
23976
23977        let shows_folds = is_singleton && gutter_settings.folds;
23978
23979        let right_padding = if shows_folds && show_line_numbers {
23980            ch_width * 4.0
23981        } else if shows_folds || (!is_singleton && show_line_numbers) {
23982            ch_width * 3.0
23983        } else if show_line_numbers {
23984            ch_width
23985        } else {
23986            px(0.)
23987        };
23988
23989        Some(GutterDimensions {
23990            left_padding,
23991            right_padding,
23992            width: line_gutter_width + left_padding + right_padding,
23993            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23994            git_blame_entries_width,
23995        })
23996    }
23997
23998    pub fn render_crease_toggle(
23999        &self,
24000        buffer_row: MultiBufferRow,
24001        row_contains_cursor: bool,
24002        editor: Entity<Editor>,
24003        window: &mut Window,
24004        cx: &mut App,
24005    ) -> Option<AnyElement> {
24006        let folded = self.is_line_folded(buffer_row);
24007        let mut is_foldable = false;
24008
24009        if let Some(crease) = self
24010            .crease_snapshot
24011            .query_row(buffer_row, self.buffer_snapshot())
24012        {
24013            is_foldable = true;
24014            match crease {
24015                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24016                    if let Some(render_toggle) = render_toggle {
24017                        let toggle_callback =
24018                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24019                                if folded {
24020                                    editor.update(cx, |editor, cx| {
24021                                        editor.fold_at(buffer_row, window, cx)
24022                                    });
24023                                } else {
24024                                    editor.update(cx, |editor, cx| {
24025                                        editor.unfold_at(buffer_row, window, cx)
24026                                    });
24027                                }
24028                            });
24029                        return Some((render_toggle)(
24030                            buffer_row,
24031                            folded,
24032                            toggle_callback,
24033                            window,
24034                            cx,
24035                        ));
24036                    }
24037                }
24038            }
24039        }
24040
24041        is_foldable |= self.starts_indent(buffer_row);
24042
24043        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24044            Some(
24045                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24046                    .toggle_state(folded)
24047                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24048                        if folded {
24049                            this.unfold_at(buffer_row, window, cx);
24050                        } else {
24051                            this.fold_at(buffer_row, window, cx);
24052                        }
24053                    }))
24054                    .into_any_element(),
24055            )
24056        } else {
24057            None
24058        }
24059    }
24060
24061    pub fn render_crease_trailer(
24062        &self,
24063        buffer_row: MultiBufferRow,
24064        window: &mut Window,
24065        cx: &mut App,
24066    ) -> Option<AnyElement> {
24067        let folded = self.is_line_folded(buffer_row);
24068        if let Crease::Inline { render_trailer, .. } = self
24069            .crease_snapshot
24070            .query_row(buffer_row, self.buffer_snapshot())?
24071        {
24072            let render_trailer = render_trailer.as_ref()?;
24073            Some(render_trailer(buffer_row, folded, window, cx))
24074        } else {
24075            None
24076        }
24077    }
24078}
24079
24080impl Deref for EditorSnapshot {
24081    type Target = DisplaySnapshot;
24082
24083    fn deref(&self) -> &Self::Target {
24084        &self.display_snapshot
24085    }
24086}
24087
24088#[derive(Clone, Debug, PartialEq, Eq)]
24089pub enum EditorEvent {
24090    InputIgnored {
24091        text: Arc<str>,
24092    },
24093    InputHandled {
24094        utf16_range_to_replace: Option<Range<isize>>,
24095        text: Arc<str>,
24096    },
24097    ExcerptsAdded {
24098        buffer: Entity<Buffer>,
24099        predecessor: ExcerptId,
24100        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24101    },
24102    ExcerptsRemoved {
24103        ids: Vec<ExcerptId>,
24104        removed_buffer_ids: Vec<BufferId>,
24105    },
24106    BufferFoldToggled {
24107        ids: Vec<ExcerptId>,
24108        folded: bool,
24109    },
24110    ExcerptsEdited {
24111        ids: Vec<ExcerptId>,
24112    },
24113    ExcerptsExpanded {
24114        ids: Vec<ExcerptId>,
24115    },
24116    BufferEdited,
24117    Edited {
24118        transaction_id: clock::Lamport,
24119    },
24120    Reparsed(BufferId),
24121    Focused,
24122    FocusedIn,
24123    Blurred,
24124    DirtyChanged,
24125    Saved,
24126    TitleChanged,
24127    SelectionsChanged {
24128        local: bool,
24129    },
24130    ScrollPositionChanged {
24131        local: bool,
24132        autoscroll: bool,
24133    },
24134    TransactionUndone {
24135        transaction_id: clock::Lamport,
24136    },
24137    TransactionBegun {
24138        transaction_id: clock::Lamport,
24139    },
24140    CursorShapeChanged,
24141    BreadcrumbsChanged,
24142    PushedToNavHistory {
24143        anchor: Anchor,
24144        is_deactivate: bool,
24145    },
24146}
24147
24148impl EventEmitter<EditorEvent> for Editor {}
24149
24150impl Focusable for Editor {
24151    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24152        self.focus_handle.clone()
24153    }
24154}
24155
24156impl Render for Editor {
24157    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24158        let settings = ThemeSettings::get_global(cx);
24159
24160        let mut text_style = match self.mode {
24161            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24162                color: cx.theme().colors().editor_foreground,
24163                font_family: settings.ui_font.family.clone(),
24164                font_features: settings.ui_font.features.clone(),
24165                font_fallbacks: settings.ui_font.fallbacks.clone(),
24166                font_size: rems(0.875).into(),
24167                font_weight: settings.ui_font.weight,
24168                line_height: relative(settings.buffer_line_height.value()),
24169                ..Default::default()
24170            },
24171            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24172                color: cx.theme().colors().editor_foreground,
24173                font_family: settings.buffer_font.family.clone(),
24174                font_features: settings.buffer_font.features.clone(),
24175                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24176                font_size: settings.buffer_font_size(cx).into(),
24177                font_weight: settings.buffer_font.weight,
24178                line_height: relative(settings.buffer_line_height.value()),
24179                ..Default::default()
24180            },
24181        };
24182        if let Some(text_style_refinement) = &self.text_style_refinement {
24183            text_style.refine(text_style_refinement)
24184        }
24185
24186        let background = match self.mode {
24187            EditorMode::SingleLine => cx.theme().system().transparent,
24188            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24189            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24190            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24191        };
24192
24193        EditorElement::new(
24194            &cx.entity(),
24195            EditorStyle {
24196                background,
24197                border: cx.theme().colors().border,
24198                local_player: cx.theme().players().local(),
24199                text: text_style,
24200                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24201                syntax: cx.theme().syntax().clone(),
24202                status: cx.theme().status().clone(),
24203                inlay_hints_style: make_inlay_hints_style(cx),
24204                edit_prediction_styles: make_suggestion_styles(cx),
24205                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24206                show_underlines: self.diagnostics_enabled(),
24207            },
24208        )
24209    }
24210}
24211
24212impl EntityInputHandler for Editor {
24213    fn text_for_range(
24214        &mut self,
24215        range_utf16: Range<usize>,
24216        adjusted_range: &mut Option<Range<usize>>,
24217        _: &mut Window,
24218        cx: &mut Context<Self>,
24219    ) -> Option<String> {
24220        let snapshot = self.buffer.read(cx).read(cx);
24221        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24222        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24223        if (start.0..end.0) != range_utf16 {
24224            adjusted_range.replace(start.0..end.0);
24225        }
24226        Some(snapshot.text_for_range(start..end).collect())
24227    }
24228
24229    fn selected_text_range(
24230        &mut self,
24231        ignore_disabled_input: bool,
24232        _: &mut Window,
24233        cx: &mut Context<Self>,
24234    ) -> Option<UTF16Selection> {
24235        // Prevent the IME menu from appearing when holding down an alphabetic key
24236        // while input is disabled.
24237        if !ignore_disabled_input && !self.input_enabled {
24238            return None;
24239        }
24240
24241        let selection = self
24242            .selections
24243            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24244        let range = selection.range();
24245
24246        Some(UTF16Selection {
24247            range: range.start.0..range.end.0,
24248            reversed: selection.reversed,
24249        })
24250    }
24251
24252    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24253        let snapshot = self.buffer.read(cx).read(cx);
24254        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24255        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24256    }
24257
24258    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24259        self.clear_highlights::<InputComposition>(cx);
24260        self.ime_transaction.take();
24261    }
24262
24263    fn replace_text_in_range(
24264        &mut self,
24265        range_utf16: Option<Range<usize>>,
24266        text: &str,
24267        window: &mut Window,
24268        cx: &mut Context<Self>,
24269    ) {
24270        if !self.input_enabled {
24271            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24272            return;
24273        }
24274
24275        self.transact(window, cx, |this, window, cx| {
24276            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24277                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24278                Some(this.selection_replacement_ranges(range_utf16, cx))
24279            } else {
24280                this.marked_text_ranges(cx)
24281            };
24282
24283            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24284                let newest_selection_id = this.selections.newest_anchor().id;
24285                this.selections
24286                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24287                    .iter()
24288                    .zip(ranges_to_replace.iter())
24289                    .find_map(|(selection, range)| {
24290                        if selection.id == newest_selection_id {
24291                            Some(
24292                                (range.start.0 as isize - selection.head().0 as isize)
24293                                    ..(range.end.0 as isize - selection.head().0 as isize),
24294                            )
24295                        } else {
24296                            None
24297                        }
24298                    })
24299            });
24300
24301            cx.emit(EditorEvent::InputHandled {
24302                utf16_range_to_replace: range_to_replace,
24303                text: text.into(),
24304            });
24305
24306            if let Some(new_selected_ranges) = new_selected_ranges {
24307                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24308                    selections.select_ranges(new_selected_ranges)
24309                });
24310                this.backspace(&Default::default(), window, cx);
24311            }
24312
24313            this.handle_input(text, window, cx);
24314        });
24315
24316        if let Some(transaction) = self.ime_transaction {
24317            self.buffer.update(cx, |buffer, cx| {
24318                buffer.group_until_transaction(transaction, cx);
24319            });
24320        }
24321
24322        self.unmark_text(window, cx);
24323    }
24324
24325    fn replace_and_mark_text_in_range(
24326        &mut self,
24327        range_utf16: Option<Range<usize>>,
24328        text: &str,
24329        new_selected_range_utf16: Option<Range<usize>>,
24330        window: &mut Window,
24331        cx: &mut Context<Self>,
24332    ) {
24333        if !self.input_enabled {
24334            return;
24335        }
24336
24337        let transaction = self.transact(window, cx, |this, window, cx| {
24338            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24339                let snapshot = this.buffer.read(cx).read(cx);
24340                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24341                    for marked_range in &mut marked_ranges {
24342                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24343                        marked_range.start.0 += relative_range_utf16.start;
24344                        marked_range.start =
24345                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24346                        marked_range.end =
24347                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24348                    }
24349                }
24350                Some(marked_ranges)
24351            } else if let Some(range_utf16) = range_utf16 {
24352                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24353                Some(this.selection_replacement_ranges(range_utf16, cx))
24354            } else {
24355                None
24356            };
24357
24358            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24359                let newest_selection_id = this.selections.newest_anchor().id;
24360                this.selections
24361                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24362                    .iter()
24363                    .zip(ranges_to_replace.iter())
24364                    .find_map(|(selection, range)| {
24365                        if selection.id == newest_selection_id {
24366                            Some(
24367                                (range.start.0 as isize - selection.head().0 as isize)
24368                                    ..(range.end.0 as isize - selection.head().0 as isize),
24369                            )
24370                        } else {
24371                            None
24372                        }
24373                    })
24374            });
24375
24376            cx.emit(EditorEvent::InputHandled {
24377                utf16_range_to_replace: range_to_replace,
24378                text: text.into(),
24379            });
24380
24381            if let Some(ranges) = ranges_to_replace {
24382                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24383                    s.select_ranges(ranges)
24384                });
24385            }
24386
24387            let marked_ranges = {
24388                let snapshot = this.buffer.read(cx).read(cx);
24389                this.selections
24390                    .disjoint_anchors_arc()
24391                    .iter()
24392                    .map(|selection| {
24393                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24394                    })
24395                    .collect::<Vec<_>>()
24396            };
24397
24398            if text.is_empty() {
24399                this.unmark_text(window, cx);
24400            } else {
24401                this.highlight_text::<InputComposition>(
24402                    marked_ranges.clone(),
24403                    HighlightStyle {
24404                        underline: Some(UnderlineStyle {
24405                            thickness: px(1.),
24406                            color: None,
24407                            wavy: false,
24408                        }),
24409                        ..Default::default()
24410                    },
24411                    cx,
24412                );
24413            }
24414
24415            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24416            let use_autoclose = this.use_autoclose;
24417            let use_auto_surround = this.use_auto_surround;
24418            this.set_use_autoclose(false);
24419            this.set_use_auto_surround(false);
24420            this.handle_input(text, window, cx);
24421            this.set_use_autoclose(use_autoclose);
24422            this.set_use_auto_surround(use_auto_surround);
24423
24424            if let Some(new_selected_range) = new_selected_range_utf16 {
24425                let snapshot = this.buffer.read(cx).read(cx);
24426                let new_selected_ranges = marked_ranges
24427                    .into_iter()
24428                    .map(|marked_range| {
24429                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24430                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24431                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24432                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24433                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24434                    })
24435                    .collect::<Vec<_>>();
24436
24437                drop(snapshot);
24438                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24439                    selections.select_ranges(new_selected_ranges)
24440                });
24441            }
24442        });
24443
24444        self.ime_transaction = self.ime_transaction.or(transaction);
24445        if let Some(transaction) = self.ime_transaction {
24446            self.buffer.update(cx, |buffer, cx| {
24447                buffer.group_until_transaction(transaction, cx);
24448            });
24449        }
24450
24451        if self.text_highlights::<InputComposition>(cx).is_none() {
24452            self.ime_transaction.take();
24453        }
24454    }
24455
24456    fn bounds_for_range(
24457        &mut self,
24458        range_utf16: Range<usize>,
24459        element_bounds: gpui::Bounds<Pixels>,
24460        window: &mut Window,
24461        cx: &mut Context<Self>,
24462    ) -> Option<gpui::Bounds<Pixels>> {
24463        let text_layout_details = self.text_layout_details(window);
24464        let CharacterDimensions {
24465            em_width,
24466            em_advance,
24467            line_height,
24468        } = self.character_dimensions(window);
24469
24470        let snapshot = self.snapshot(window, cx);
24471        let scroll_position = snapshot.scroll_position();
24472        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24473
24474        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24475        let x = Pixels::from(
24476            ScrollOffset::from(
24477                snapshot.x_for_display_point(start, &text_layout_details)
24478                    + self.gutter_dimensions.full_width(),
24479            ) - scroll_left,
24480        );
24481        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24482
24483        Some(Bounds {
24484            origin: element_bounds.origin + point(x, y),
24485            size: size(em_width, line_height),
24486        })
24487    }
24488
24489    fn character_index_for_point(
24490        &mut self,
24491        point: gpui::Point<Pixels>,
24492        _window: &mut Window,
24493        _cx: &mut Context<Self>,
24494    ) -> Option<usize> {
24495        let position_map = self.last_position_map.as_ref()?;
24496        if !position_map.text_hitbox.contains(&point) {
24497            return None;
24498        }
24499        let display_point = position_map.point_for_position(point).previous_valid;
24500        let anchor = position_map
24501            .snapshot
24502            .display_point_to_anchor(display_point, Bias::Left);
24503        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24504        Some(utf16_offset.0)
24505    }
24506
24507    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24508        self.input_enabled
24509    }
24510}
24511
24512trait SelectionExt {
24513    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24514    fn spanned_rows(
24515        &self,
24516        include_end_if_at_line_start: bool,
24517        map: &DisplaySnapshot,
24518    ) -> Range<MultiBufferRow>;
24519}
24520
24521impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24522    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24523        let start = self
24524            .start
24525            .to_point(map.buffer_snapshot())
24526            .to_display_point(map);
24527        let end = self
24528            .end
24529            .to_point(map.buffer_snapshot())
24530            .to_display_point(map);
24531        if self.reversed {
24532            end..start
24533        } else {
24534            start..end
24535        }
24536    }
24537
24538    fn spanned_rows(
24539        &self,
24540        include_end_if_at_line_start: bool,
24541        map: &DisplaySnapshot,
24542    ) -> Range<MultiBufferRow> {
24543        let start = self.start.to_point(map.buffer_snapshot());
24544        let mut end = self.end.to_point(map.buffer_snapshot());
24545        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24546            end.row -= 1;
24547        }
24548
24549        let buffer_start = map.prev_line_boundary(start).0;
24550        let buffer_end = map.next_line_boundary(end).0;
24551        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24552    }
24553}
24554
24555impl<T: InvalidationRegion> InvalidationStack<T> {
24556    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24557    where
24558        S: Clone + ToOffset,
24559    {
24560        while let Some(region) = self.last() {
24561            let all_selections_inside_invalidation_ranges =
24562                if selections.len() == region.ranges().len() {
24563                    selections
24564                        .iter()
24565                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24566                        .all(|(selection, invalidation_range)| {
24567                            let head = selection.head().to_offset(buffer);
24568                            invalidation_range.start <= head && invalidation_range.end >= head
24569                        })
24570                } else {
24571                    false
24572                };
24573
24574            if all_selections_inside_invalidation_ranges {
24575                break;
24576            } else {
24577                self.pop();
24578            }
24579        }
24580    }
24581}
24582
24583impl<T> Default for InvalidationStack<T> {
24584    fn default() -> Self {
24585        Self(Default::default())
24586    }
24587}
24588
24589impl<T> Deref for InvalidationStack<T> {
24590    type Target = Vec<T>;
24591
24592    fn deref(&self) -> &Self::Target {
24593        &self.0
24594    }
24595}
24596
24597impl<T> DerefMut for InvalidationStack<T> {
24598    fn deref_mut(&mut self) -> &mut Self::Target {
24599        &mut self.0
24600    }
24601}
24602
24603impl InvalidationRegion for SnippetState {
24604    fn ranges(&self) -> &[Range<Anchor>] {
24605        &self.ranges[self.active_index]
24606    }
24607}
24608
24609fn edit_prediction_edit_text(
24610    current_snapshot: &BufferSnapshot,
24611    edits: &[(Range<Anchor>, impl AsRef<str>)],
24612    edit_preview: &EditPreview,
24613    include_deletions: bool,
24614    cx: &App,
24615) -> HighlightedText {
24616    let edits = edits
24617        .iter()
24618        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24619        .collect::<Vec<_>>();
24620
24621    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24622}
24623
24624fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24625    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24626    // Just show the raw edit text with basic styling
24627    let mut text = String::new();
24628    let mut highlights = Vec::new();
24629
24630    let insertion_highlight_style = HighlightStyle {
24631        color: Some(cx.theme().colors().text),
24632        ..Default::default()
24633    };
24634
24635    for (_, edit_text) in edits {
24636        let start_offset = text.len();
24637        text.push_str(edit_text);
24638        let end_offset = text.len();
24639
24640        if start_offset < end_offset {
24641            highlights.push((start_offset..end_offset, insertion_highlight_style));
24642        }
24643    }
24644
24645    HighlightedText {
24646        text: text.into(),
24647        highlights,
24648    }
24649}
24650
24651pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24652    match severity {
24653        lsp::DiagnosticSeverity::ERROR => colors.error,
24654        lsp::DiagnosticSeverity::WARNING => colors.warning,
24655        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24656        lsp::DiagnosticSeverity::HINT => colors.info,
24657        _ => colors.ignored,
24658    }
24659}
24660
24661pub fn styled_runs_for_code_label<'a>(
24662    label: &'a CodeLabel,
24663    syntax_theme: &'a theme::SyntaxTheme,
24664) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24665    let fade_out = HighlightStyle {
24666        fade_out: Some(0.35),
24667        ..Default::default()
24668    };
24669
24670    let mut prev_end = label.filter_range.end;
24671    label
24672        .runs
24673        .iter()
24674        .enumerate()
24675        .flat_map(move |(ix, (range, highlight_id))| {
24676            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24677                style
24678            } else {
24679                return Default::default();
24680            };
24681            let muted_style = style.highlight(fade_out);
24682
24683            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24684            if range.start >= label.filter_range.end {
24685                if range.start > prev_end {
24686                    runs.push((prev_end..range.start, fade_out));
24687                }
24688                runs.push((range.clone(), muted_style));
24689            } else if range.end <= label.filter_range.end {
24690                runs.push((range.clone(), style));
24691            } else {
24692                runs.push((range.start..label.filter_range.end, style));
24693                runs.push((label.filter_range.end..range.end, muted_style));
24694            }
24695            prev_end = cmp::max(prev_end, range.end);
24696
24697            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24698                runs.push((prev_end..label.text.len(), fade_out));
24699            }
24700
24701            runs
24702        })
24703}
24704
24705pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24706    let mut prev_index = 0;
24707    let mut prev_codepoint: Option<char> = None;
24708    text.char_indices()
24709        .chain([(text.len(), '\0')])
24710        .filter_map(move |(index, codepoint)| {
24711            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24712            let is_boundary = index == text.len()
24713                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24714                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24715            if is_boundary {
24716                let chunk = &text[prev_index..index];
24717                prev_index = index;
24718                Some(chunk)
24719            } else {
24720                None
24721            }
24722        })
24723}
24724
24725/// Given a string of text immediately before the cursor, iterates over possible
24726/// strings a snippet could match to. More precisely: returns an iterator over
24727/// suffixes of `text` created by splitting at word boundaries (before & after
24728/// every non-word character).
24729///
24730/// Shorter suffixes are returned first.
24731pub(crate) fn snippet_candidate_suffixes(
24732    text: &str,
24733    is_word_char: impl Fn(char) -> bool,
24734) -> impl std::iter::Iterator<Item = &str> {
24735    let mut prev_index = text.len();
24736    let mut prev_codepoint = None;
24737    text.char_indices()
24738        .rev()
24739        .chain([(0, '\0')])
24740        .filter_map(move |(index, codepoint)| {
24741            let prev_index = std::mem::replace(&mut prev_index, index);
24742            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24743            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24744                None
24745            } else {
24746                let chunk = &text[prev_index..]; // go to end of string
24747                Some(chunk)
24748            }
24749        })
24750}
24751
24752pub trait RangeToAnchorExt: Sized {
24753    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24754
24755    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24756        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24757        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24758    }
24759}
24760
24761impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24762    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24763        let start_offset = self.start.to_offset(snapshot);
24764        let end_offset = self.end.to_offset(snapshot);
24765        if start_offset == end_offset {
24766            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24767        } else {
24768            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24769        }
24770    }
24771}
24772
24773pub trait RowExt {
24774    fn as_f64(&self) -> f64;
24775
24776    fn next_row(&self) -> Self;
24777
24778    fn previous_row(&self) -> Self;
24779
24780    fn minus(&self, other: Self) -> u32;
24781}
24782
24783impl RowExt for DisplayRow {
24784    fn as_f64(&self) -> f64 {
24785        self.0 as _
24786    }
24787
24788    fn next_row(&self) -> Self {
24789        Self(self.0 + 1)
24790    }
24791
24792    fn previous_row(&self) -> Self {
24793        Self(self.0.saturating_sub(1))
24794    }
24795
24796    fn minus(&self, other: Self) -> u32 {
24797        self.0 - other.0
24798    }
24799}
24800
24801impl RowExt for MultiBufferRow {
24802    fn as_f64(&self) -> f64 {
24803        self.0 as _
24804    }
24805
24806    fn next_row(&self) -> Self {
24807        Self(self.0 + 1)
24808    }
24809
24810    fn previous_row(&self) -> Self {
24811        Self(self.0.saturating_sub(1))
24812    }
24813
24814    fn minus(&self, other: Self) -> u32 {
24815        self.0 - other.0
24816    }
24817}
24818
24819trait RowRangeExt {
24820    type Row;
24821
24822    fn len(&self) -> usize;
24823
24824    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24825}
24826
24827impl RowRangeExt for Range<MultiBufferRow> {
24828    type Row = MultiBufferRow;
24829
24830    fn len(&self) -> usize {
24831        (self.end.0 - self.start.0) as usize
24832    }
24833
24834    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24835        (self.start.0..self.end.0).map(MultiBufferRow)
24836    }
24837}
24838
24839impl RowRangeExt for Range<DisplayRow> {
24840    type Row = DisplayRow;
24841
24842    fn len(&self) -> usize {
24843        (self.end.0 - self.start.0) as usize
24844    }
24845
24846    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24847        (self.start.0..self.end.0).map(DisplayRow)
24848    }
24849}
24850
24851/// If select range has more than one line, we
24852/// just point the cursor to range.start.
24853fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24854    if range.start.row == range.end.row {
24855        range
24856    } else {
24857        range.start..range.start
24858    }
24859}
24860pub struct KillRing(ClipboardItem);
24861impl Global for KillRing {}
24862
24863const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24864
24865enum BreakpointPromptEditAction {
24866    Log,
24867    Condition,
24868    HitCondition,
24869}
24870
24871struct BreakpointPromptEditor {
24872    pub(crate) prompt: Entity<Editor>,
24873    editor: WeakEntity<Editor>,
24874    breakpoint_anchor: Anchor,
24875    breakpoint: Breakpoint,
24876    edit_action: BreakpointPromptEditAction,
24877    block_ids: HashSet<CustomBlockId>,
24878    editor_margins: Arc<Mutex<EditorMargins>>,
24879    _subscriptions: Vec<Subscription>,
24880}
24881
24882impl BreakpointPromptEditor {
24883    const MAX_LINES: u8 = 4;
24884
24885    fn new(
24886        editor: WeakEntity<Editor>,
24887        breakpoint_anchor: Anchor,
24888        breakpoint: Breakpoint,
24889        edit_action: BreakpointPromptEditAction,
24890        window: &mut Window,
24891        cx: &mut Context<Self>,
24892    ) -> Self {
24893        let base_text = match edit_action {
24894            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24895            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24896            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24897        }
24898        .map(|msg| msg.to_string())
24899        .unwrap_or_default();
24900
24901        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24902        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24903
24904        let prompt = cx.new(|cx| {
24905            let mut prompt = Editor::new(
24906                EditorMode::AutoHeight {
24907                    min_lines: 1,
24908                    max_lines: Some(Self::MAX_LINES as usize),
24909                },
24910                buffer,
24911                None,
24912                window,
24913                cx,
24914            );
24915            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24916            prompt.set_show_cursor_when_unfocused(false, cx);
24917            prompt.set_placeholder_text(
24918                match edit_action {
24919                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24920                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24921                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24922                },
24923                window,
24924                cx,
24925            );
24926
24927            prompt
24928        });
24929
24930        Self {
24931            prompt,
24932            editor,
24933            breakpoint_anchor,
24934            breakpoint,
24935            edit_action,
24936            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24937            block_ids: Default::default(),
24938            _subscriptions: vec![],
24939        }
24940    }
24941
24942    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24943        self.block_ids.extend(block_ids)
24944    }
24945
24946    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24947        if let Some(editor) = self.editor.upgrade() {
24948            let message = self
24949                .prompt
24950                .read(cx)
24951                .buffer
24952                .read(cx)
24953                .as_singleton()
24954                .expect("A multi buffer in breakpoint prompt isn't possible")
24955                .read(cx)
24956                .as_rope()
24957                .to_string();
24958
24959            editor.update(cx, |editor, cx| {
24960                editor.edit_breakpoint_at_anchor(
24961                    self.breakpoint_anchor,
24962                    self.breakpoint.clone(),
24963                    match self.edit_action {
24964                        BreakpointPromptEditAction::Log => {
24965                            BreakpointEditAction::EditLogMessage(message.into())
24966                        }
24967                        BreakpointPromptEditAction::Condition => {
24968                            BreakpointEditAction::EditCondition(message.into())
24969                        }
24970                        BreakpointPromptEditAction::HitCondition => {
24971                            BreakpointEditAction::EditHitCondition(message.into())
24972                        }
24973                    },
24974                    cx,
24975                );
24976
24977                editor.remove_blocks(self.block_ids.clone(), None, cx);
24978                cx.focus_self(window);
24979            });
24980        }
24981    }
24982
24983    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24984        self.editor
24985            .update(cx, |editor, cx| {
24986                editor.remove_blocks(self.block_ids.clone(), None, cx);
24987                window.focus(&editor.focus_handle);
24988            })
24989            .log_err();
24990    }
24991
24992    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24993        let settings = ThemeSettings::get_global(cx);
24994        let text_style = TextStyle {
24995            color: if self.prompt.read(cx).read_only(cx) {
24996                cx.theme().colors().text_disabled
24997            } else {
24998                cx.theme().colors().text
24999            },
25000            font_family: settings.buffer_font.family.clone(),
25001            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25002            font_size: settings.buffer_font_size(cx).into(),
25003            font_weight: settings.buffer_font.weight,
25004            line_height: relative(settings.buffer_line_height.value()),
25005            ..Default::default()
25006        };
25007        EditorElement::new(
25008            &self.prompt,
25009            EditorStyle {
25010                background: cx.theme().colors().editor_background,
25011                local_player: cx.theme().players().local(),
25012                text: text_style,
25013                ..Default::default()
25014            },
25015        )
25016    }
25017}
25018
25019impl Render for BreakpointPromptEditor {
25020    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25021        let editor_margins = *self.editor_margins.lock();
25022        let gutter_dimensions = editor_margins.gutter;
25023        h_flex()
25024            .key_context("Editor")
25025            .bg(cx.theme().colors().editor_background)
25026            .border_y_1()
25027            .border_color(cx.theme().status().info_border)
25028            .size_full()
25029            .py(window.line_height() / 2.5)
25030            .on_action(cx.listener(Self::confirm))
25031            .on_action(cx.listener(Self::cancel))
25032            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25033            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25034    }
25035}
25036
25037impl Focusable for BreakpointPromptEditor {
25038    fn focus_handle(&self, cx: &App) -> FocusHandle {
25039        self.prompt.focus_handle(cx)
25040    }
25041}
25042
25043fn all_edits_insertions_or_deletions(
25044    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25045    snapshot: &MultiBufferSnapshot,
25046) -> bool {
25047    let mut all_insertions = true;
25048    let mut all_deletions = true;
25049
25050    for (range, new_text) in edits.iter() {
25051        let range_is_empty = range.to_offset(snapshot).is_empty();
25052        let text_is_empty = new_text.is_empty();
25053
25054        if range_is_empty != text_is_empty {
25055            if range_is_empty {
25056                all_deletions = false;
25057            } else {
25058                all_insertions = false;
25059            }
25060        } else {
25061            return false;
25062        }
25063
25064        if !all_insertions && !all_deletions {
25065            return false;
25066        }
25067    }
25068    all_insertions || all_deletions
25069}
25070
25071struct MissingEditPredictionKeybindingTooltip;
25072
25073impl Render for MissingEditPredictionKeybindingTooltip {
25074    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25075        ui::tooltip_container(cx, |container, cx| {
25076            container
25077                .flex_shrink_0()
25078                .max_w_80()
25079                .min_h(rems_from_px(124.))
25080                .justify_between()
25081                .child(
25082                    v_flex()
25083                        .flex_1()
25084                        .text_ui_sm(cx)
25085                        .child(Label::new("Conflict with Accept Keybinding"))
25086                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25087                )
25088                .child(
25089                    h_flex()
25090                        .pb_1()
25091                        .gap_1()
25092                        .items_end()
25093                        .w_full()
25094                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25095                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25096                        }))
25097                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25098                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25099                        })),
25100                )
25101        })
25102    }
25103}
25104
25105#[derive(Debug, Clone, Copy, PartialEq)]
25106pub struct LineHighlight {
25107    pub background: Background,
25108    pub border: Option<gpui::Hsla>,
25109    pub include_gutter: bool,
25110    pub type_id: Option<TypeId>,
25111}
25112
25113struct LineManipulationResult {
25114    pub new_text: String,
25115    pub line_count_before: usize,
25116    pub line_count_after: usize,
25117}
25118
25119fn render_diff_hunk_controls(
25120    row: u32,
25121    status: &DiffHunkStatus,
25122    hunk_range: Range<Anchor>,
25123    is_created_file: bool,
25124    line_height: Pixels,
25125    editor: &Entity<Editor>,
25126    _window: &mut Window,
25127    cx: &mut App,
25128) -> AnyElement {
25129    h_flex()
25130        .h(line_height)
25131        .mr_1()
25132        .gap_1()
25133        .px_0p5()
25134        .pb_1()
25135        .border_x_1()
25136        .border_b_1()
25137        .border_color(cx.theme().colors().border_variant)
25138        .rounded_b_lg()
25139        .bg(cx.theme().colors().editor_background)
25140        .gap_1()
25141        .block_mouse_except_scroll()
25142        .shadow_md()
25143        .child(if status.has_secondary_hunk() {
25144            Button::new(("stage", row as u64), "Stage")
25145                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25146                .tooltip({
25147                    let focus_handle = editor.focus_handle(cx);
25148                    move |_window, cx| {
25149                        Tooltip::for_action_in(
25150                            "Stage Hunk",
25151                            &::git::ToggleStaged,
25152                            &focus_handle,
25153                            cx,
25154                        )
25155                    }
25156                })
25157                .on_click({
25158                    let editor = editor.clone();
25159                    move |_event, _window, cx| {
25160                        editor.update(cx, |editor, cx| {
25161                            editor.stage_or_unstage_diff_hunks(
25162                                true,
25163                                vec![hunk_range.start..hunk_range.start],
25164                                cx,
25165                            );
25166                        });
25167                    }
25168                })
25169        } else {
25170            Button::new(("unstage", row as u64), "Unstage")
25171                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25172                .tooltip({
25173                    let focus_handle = editor.focus_handle(cx);
25174                    move |_window, cx| {
25175                        Tooltip::for_action_in(
25176                            "Unstage Hunk",
25177                            &::git::ToggleStaged,
25178                            &focus_handle,
25179                            cx,
25180                        )
25181                    }
25182                })
25183                .on_click({
25184                    let editor = editor.clone();
25185                    move |_event, _window, cx| {
25186                        editor.update(cx, |editor, cx| {
25187                            editor.stage_or_unstage_diff_hunks(
25188                                false,
25189                                vec![hunk_range.start..hunk_range.start],
25190                                cx,
25191                            );
25192                        });
25193                    }
25194                })
25195        })
25196        .child(
25197            Button::new(("restore", row as u64), "Restore")
25198                .tooltip({
25199                    let focus_handle = editor.focus_handle(cx);
25200                    move |_window, cx| {
25201                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25202                    }
25203                })
25204                .on_click({
25205                    let editor = editor.clone();
25206                    move |_event, window, cx| {
25207                        editor.update(cx, |editor, cx| {
25208                            let snapshot = editor.snapshot(window, cx);
25209                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25210                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25211                        });
25212                    }
25213                })
25214                .disabled(is_created_file),
25215        )
25216        .when(
25217            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25218            |el| {
25219                el.child(
25220                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25221                        .shape(IconButtonShape::Square)
25222                        .icon_size(IconSize::Small)
25223                        // .disabled(!has_multiple_hunks)
25224                        .tooltip({
25225                            let focus_handle = editor.focus_handle(cx);
25226                            move |_window, cx| {
25227                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25228                            }
25229                        })
25230                        .on_click({
25231                            let editor = editor.clone();
25232                            move |_event, window, cx| {
25233                                editor.update(cx, |editor, cx| {
25234                                    let snapshot = editor.snapshot(window, cx);
25235                                    let position =
25236                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25237                                    editor.go_to_hunk_before_or_after_position(
25238                                        &snapshot,
25239                                        position,
25240                                        Direction::Next,
25241                                        window,
25242                                        cx,
25243                                    );
25244                                    editor.expand_selected_diff_hunks(cx);
25245                                });
25246                            }
25247                        }),
25248                )
25249                .child(
25250                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25251                        .shape(IconButtonShape::Square)
25252                        .icon_size(IconSize::Small)
25253                        // .disabled(!has_multiple_hunks)
25254                        .tooltip({
25255                            let focus_handle = editor.focus_handle(cx);
25256                            move |_window, cx| {
25257                                Tooltip::for_action_in(
25258                                    "Previous Hunk",
25259                                    &GoToPreviousHunk,
25260                                    &focus_handle,
25261                                    cx,
25262                                )
25263                            }
25264                        })
25265                        .on_click({
25266                            let editor = editor.clone();
25267                            move |_event, window, cx| {
25268                                editor.update(cx, |editor, cx| {
25269                                    let snapshot = editor.snapshot(window, cx);
25270                                    let point =
25271                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25272                                    editor.go_to_hunk_before_or_after_position(
25273                                        &snapshot,
25274                                        point,
25275                                        Direction::Prev,
25276                                        window,
25277                                        cx,
25278                                    );
25279                                    editor.expand_selected_diff_hunks(cx);
25280                                });
25281                            }
25282                        }),
25283                )
25284            },
25285        )
25286        .into_any_element()
25287}
25288
25289pub fn multibuffer_context_lines(cx: &App) -> u32 {
25290    EditorSettings::try_get(cx)
25291        .map(|settings| settings.excerpt_context_lines)
25292        .unwrap_or(2)
25293        .min(32)
25294}