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    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    next_inlay_id: usize,
 1127    next_color_inlay_id: usize,
 1128    _subscriptions: Vec<Subscription>,
 1129    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1130    gutter_dimensions: GutterDimensions,
 1131    style: Option<EditorStyle>,
 1132    text_style_refinement: Option<TextStyleRefinement>,
 1133    next_editor_action_id: EditorActionId,
 1134    editor_actions: Rc<
 1135        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1136    >,
 1137    use_autoclose: bool,
 1138    use_auto_surround: bool,
 1139    auto_replace_emoji_shortcode: bool,
 1140    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1141    show_git_blame_gutter: bool,
 1142    show_git_blame_inline: bool,
 1143    show_git_blame_inline_delay_task: Option<Task<()>>,
 1144    git_blame_inline_enabled: bool,
 1145    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1146    buffer_serialization: Option<BufferSerialization>,
 1147    show_selection_menu: Option<bool>,
 1148    blame: Option<Entity<GitBlame>>,
 1149    blame_subscription: Option<Subscription>,
 1150    custom_context_menu: Option<
 1151        Box<
 1152            dyn 'static
 1153                + Fn(
 1154                    &mut Self,
 1155                    DisplayPoint,
 1156                    &mut Window,
 1157                    &mut Context<Self>,
 1158                ) -> Option<Entity<ui::ContextMenu>>,
 1159        >,
 1160    >,
 1161    last_bounds: Option<Bounds<Pixels>>,
 1162    last_position_map: Option<Rc<PositionMap>>,
 1163    expect_bounds_change: Option<Bounds<Pixels>>,
 1164    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1165    tasks_update_task: Option<Task<()>>,
 1166    breakpoint_store: Option<Entity<BreakpointStore>>,
 1167    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1168    hovered_diff_hunk_row: Option<DisplayRow>,
 1169    pull_diagnostics_task: Task<()>,
 1170    in_project_search: bool,
 1171    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1172    breadcrumb_header: Option<String>,
 1173    focused_block: Option<FocusedBlock>,
 1174    next_scroll_position: NextScrollCursorCenterTopBottom,
 1175    addons: HashMap<TypeId, Box<dyn Addon>>,
 1176    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1177    load_diff_task: Option<Shared<Task<()>>>,
 1178    /// Whether we are temporarily displaying a diff other than git's
 1179    temporary_diff_override: bool,
 1180    selection_mark_mode: bool,
 1181    toggle_fold_multiple_buffers: Task<()>,
 1182    _scroll_cursor_center_top_bottom_task: Task<()>,
 1183    serialize_selections: Task<()>,
 1184    serialize_folds: Task<()>,
 1185    mouse_cursor_hidden: bool,
 1186    minimap: Option<Entity<Self>>,
 1187    hide_mouse_mode: HideMouseMode,
 1188    pub change_list: ChangeList,
 1189    inline_value_cache: InlineValueCache,
 1190
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    post_scroll_update: Task<()>,
 1194    refresh_colors_task: Task<()>,
 1195    inlay_hints: Option<LspInlayHintData>,
 1196    folding_newlines: Task<()>,
 1197    select_next_is_case_sensitive: Option<bool>,
 1198    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1199}
 1200
 1201fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1202    if debounce_ms > 0 {
 1203        Some(Duration::from_millis(debounce_ms))
 1204    } else {
 1205        None
 1206    }
 1207}
 1208
 1209#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1210enum NextScrollCursorCenterTopBottom {
 1211    #[default]
 1212    Center,
 1213    Top,
 1214    Bottom,
 1215}
 1216
 1217impl NextScrollCursorCenterTopBottom {
 1218    fn next(&self) -> Self {
 1219        match self {
 1220            Self::Center => Self::Top,
 1221            Self::Top => Self::Bottom,
 1222            Self::Bottom => Self::Center,
 1223        }
 1224    }
 1225}
 1226
 1227#[derive(Clone)]
 1228pub struct EditorSnapshot {
 1229    pub mode: EditorMode,
 1230    show_gutter: bool,
 1231    show_line_numbers: Option<bool>,
 1232    show_git_diff_gutter: Option<bool>,
 1233    show_code_actions: Option<bool>,
 1234    show_runnables: Option<bool>,
 1235    show_breakpoints: Option<bool>,
 1236    git_blame_gutter_max_author_length: Option<usize>,
 1237    pub display_snapshot: DisplaySnapshot,
 1238    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1239    is_focused: bool,
 1240    scroll_anchor: ScrollAnchor,
 1241    ongoing_scroll: OngoingScroll,
 1242    current_line_highlight: CurrentLineHighlight,
 1243    gutter_hovered: bool,
 1244}
 1245
 1246#[derive(Default, Debug, Clone, Copy)]
 1247pub struct GutterDimensions {
 1248    pub left_padding: Pixels,
 1249    pub right_padding: Pixels,
 1250    pub width: Pixels,
 1251    pub margin: Pixels,
 1252    pub git_blame_entries_width: Option<Pixels>,
 1253}
 1254
 1255impl GutterDimensions {
 1256    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1257        Self {
 1258            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1259            ..Default::default()
 1260        }
 1261    }
 1262
 1263    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1264        -cx.text_system().descent(font_id, font_size)
 1265    }
 1266    /// The full width of the space taken up by the gutter.
 1267    pub fn full_width(&self) -> Pixels {
 1268        self.margin + self.width
 1269    }
 1270
 1271    /// The width of the space reserved for the fold indicators,
 1272    /// use alongside 'justify_end' and `gutter_width` to
 1273    /// right align content with the line numbers
 1274    pub fn fold_area_width(&self) -> Pixels {
 1275        self.margin + self.right_padding
 1276    }
 1277}
 1278
 1279struct CharacterDimensions {
 1280    em_width: Pixels,
 1281    em_advance: Pixels,
 1282    line_height: Pixels,
 1283}
 1284
 1285#[derive(Debug)]
 1286pub struct RemoteSelection {
 1287    pub replica_id: ReplicaId,
 1288    pub selection: Selection<Anchor>,
 1289    pub cursor_shape: CursorShape,
 1290    pub collaborator_id: CollaboratorId,
 1291    pub line_mode: bool,
 1292    pub user_name: Option<SharedString>,
 1293    pub color: PlayerColor,
 1294}
 1295
 1296#[derive(Clone, Debug)]
 1297struct SelectionHistoryEntry {
 1298    selections: Arc<[Selection<Anchor>]>,
 1299    select_next_state: Option<SelectNextState>,
 1300    select_prev_state: Option<SelectNextState>,
 1301    add_selections_state: Option<AddSelectionsState>,
 1302}
 1303
 1304#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1305enum SelectionHistoryMode {
 1306    #[default]
 1307    Normal,
 1308    Undoing,
 1309    Redoing,
 1310    Skipping,
 1311}
 1312
 1313#[derive(Clone, PartialEq, Eq, Hash)]
 1314struct HoveredCursor {
 1315    replica_id: ReplicaId,
 1316    selection_id: usize,
 1317}
 1318
 1319#[derive(Debug)]
 1320/// SelectionEffects controls the side-effects of updating the selection.
 1321///
 1322/// The default behaviour does "what you mostly want":
 1323/// - it pushes to the nav history if the cursor moved by >10 lines
 1324/// - it re-triggers completion requests
 1325/// - it scrolls to fit
 1326///
 1327/// You might want to modify these behaviours. For example when doing a "jump"
 1328/// like go to definition, we always want to add to nav history; but when scrolling
 1329/// in vim mode we never do.
 1330///
 1331/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1332/// move.
 1333#[derive(Clone)]
 1334pub struct SelectionEffects {
 1335    nav_history: Option<bool>,
 1336    completions: bool,
 1337    scroll: Option<Autoscroll>,
 1338}
 1339
 1340impl Default for SelectionEffects {
 1341    fn default() -> Self {
 1342        Self {
 1343            nav_history: None,
 1344            completions: true,
 1345            scroll: Some(Autoscroll::fit()),
 1346        }
 1347    }
 1348}
 1349impl SelectionEffects {
 1350    pub fn scroll(scroll: Autoscroll) -> Self {
 1351        Self {
 1352            scroll: Some(scroll),
 1353            ..Default::default()
 1354        }
 1355    }
 1356
 1357    pub fn no_scroll() -> Self {
 1358        Self {
 1359            scroll: None,
 1360            ..Default::default()
 1361        }
 1362    }
 1363
 1364    pub fn completions(self, completions: bool) -> Self {
 1365        Self {
 1366            completions,
 1367            ..self
 1368        }
 1369    }
 1370
 1371    pub fn nav_history(self, nav_history: bool) -> Self {
 1372        Self {
 1373            nav_history: Some(nav_history),
 1374            ..self
 1375        }
 1376    }
 1377}
 1378
 1379struct DeferredSelectionEffectsState {
 1380    changed: bool,
 1381    effects: SelectionEffects,
 1382    old_cursor_position: Anchor,
 1383    history_entry: SelectionHistoryEntry,
 1384}
 1385
 1386#[derive(Default)]
 1387struct SelectionHistory {
 1388    #[allow(clippy::type_complexity)]
 1389    selections_by_transaction:
 1390        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1391    mode: SelectionHistoryMode,
 1392    undo_stack: VecDeque<SelectionHistoryEntry>,
 1393    redo_stack: VecDeque<SelectionHistoryEntry>,
 1394}
 1395
 1396impl SelectionHistory {
 1397    #[track_caller]
 1398    fn insert_transaction(
 1399        &mut self,
 1400        transaction_id: TransactionId,
 1401        selections: Arc<[Selection<Anchor>]>,
 1402    ) {
 1403        if selections.is_empty() {
 1404            log::error!(
 1405                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1406                std::panic::Location::caller()
 1407            );
 1408            return;
 1409        }
 1410        self.selections_by_transaction
 1411            .insert(transaction_id, (selections, None));
 1412    }
 1413
 1414    #[allow(clippy::type_complexity)]
 1415    fn transaction(
 1416        &self,
 1417        transaction_id: TransactionId,
 1418    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1419        self.selections_by_transaction.get(&transaction_id)
 1420    }
 1421
 1422    #[allow(clippy::type_complexity)]
 1423    fn transaction_mut(
 1424        &mut self,
 1425        transaction_id: TransactionId,
 1426    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1427        self.selections_by_transaction.get_mut(&transaction_id)
 1428    }
 1429
 1430    fn push(&mut self, entry: SelectionHistoryEntry) {
 1431        if !entry.selections.is_empty() {
 1432            match self.mode {
 1433                SelectionHistoryMode::Normal => {
 1434                    self.push_undo(entry);
 1435                    self.redo_stack.clear();
 1436                }
 1437                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1438                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1439                SelectionHistoryMode::Skipping => {}
 1440            }
 1441        }
 1442    }
 1443
 1444    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1445        if self
 1446            .undo_stack
 1447            .back()
 1448            .is_none_or(|e| e.selections != entry.selections)
 1449        {
 1450            self.undo_stack.push_back(entry);
 1451            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1452                self.undo_stack.pop_front();
 1453            }
 1454        }
 1455    }
 1456
 1457    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1458        if self
 1459            .redo_stack
 1460            .back()
 1461            .is_none_or(|e| e.selections != entry.selections)
 1462        {
 1463            self.redo_stack.push_back(entry);
 1464            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1465                self.redo_stack.pop_front();
 1466            }
 1467        }
 1468    }
 1469}
 1470
 1471#[derive(Clone, Copy)]
 1472pub struct RowHighlightOptions {
 1473    pub autoscroll: bool,
 1474    pub include_gutter: bool,
 1475}
 1476
 1477impl Default for RowHighlightOptions {
 1478    fn default() -> Self {
 1479        Self {
 1480            autoscroll: Default::default(),
 1481            include_gutter: true,
 1482        }
 1483    }
 1484}
 1485
 1486struct RowHighlight {
 1487    index: usize,
 1488    range: Range<Anchor>,
 1489    color: Hsla,
 1490    options: RowHighlightOptions,
 1491    type_id: TypeId,
 1492}
 1493
 1494#[derive(Clone, Debug)]
 1495struct AddSelectionsState {
 1496    groups: Vec<AddSelectionsGroup>,
 1497}
 1498
 1499#[derive(Clone, Debug)]
 1500struct AddSelectionsGroup {
 1501    above: bool,
 1502    stack: Vec<usize>,
 1503}
 1504
 1505#[derive(Clone)]
 1506struct SelectNextState {
 1507    query: AhoCorasick,
 1508    wordwise: bool,
 1509    done: bool,
 1510}
 1511
 1512impl std::fmt::Debug for SelectNextState {
 1513    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1514        f.debug_struct(std::any::type_name::<Self>())
 1515            .field("wordwise", &self.wordwise)
 1516            .field("done", &self.done)
 1517            .finish()
 1518    }
 1519}
 1520
 1521#[derive(Debug)]
 1522struct AutocloseRegion {
 1523    selection_id: usize,
 1524    range: Range<Anchor>,
 1525    pair: BracketPair,
 1526}
 1527
 1528#[derive(Debug)]
 1529struct SnippetState {
 1530    ranges: Vec<Vec<Range<Anchor>>>,
 1531    active_index: usize,
 1532    choices: Vec<Option<Vec<String>>>,
 1533}
 1534
 1535#[doc(hidden)]
 1536pub struct RenameState {
 1537    pub range: Range<Anchor>,
 1538    pub old_name: Arc<str>,
 1539    pub editor: Entity<Editor>,
 1540    block_id: CustomBlockId,
 1541}
 1542
 1543struct InvalidationStack<T>(Vec<T>);
 1544
 1545struct RegisteredEditPredictionProvider {
 1546    provider: Arc<dyn EditPredictionProviderHandle>,
 1547    _subscription: Subscription,
 1548}
 1549
 1550#[derive(Debug, PartialEq, Eq)]
 1551pub struct ActiveDiagnosticGroup {
 1552    pub active_range: Range<Anchor>,
 1553    pub active_message: String,
 1554    pub group_id: usize,
 1555    pub blocks: HashSet<CustomBlockId>,
 1556}
 1557
 1558#[derive(Debug, PartialEq, Eq)]
 1559
 1560pub(crate) enum ActiveDiagnostic {
 1561    None,
 1562    All,
 1563    Group(ActiveDiagnosticGroup),
 1564}
 1565
 1566#[derive(Serialize, Deserialize, Clone, Debug)]
 1567pub struct ClipboardSelection {
 1568    /// The number of bytes in this selection.
 1569    pub len: usize,
 1570    /// Whether this was a full-line selection.
 1571    pub is_entire_line: bool,
 1572    /// The indentation of the first line when this content was originally copied.
 1573    pub first_line_indent: u32,
 1574}
 1575
 1576// selections, scroll behavior, was newest selection reversed
 1577type SelectSyntaxNodeHistoryState = (
 1578    Box<[Selection<usize>]>,
 1579    SelectSyntaxNodeScrollBehavior,
 1580    bool,
 1581);
 1582
 1583#[derive(Default)]
 1584struct SelectSyntaxNodeHistory {
 1585    stack: Vec<SelectSyntaxNodeHistoryState>,
 1586    // disable temporarily to allow changing selections without losing the stack
 1587    pub disable_clearing: bool,
 1588}
 1589
 1590impl SelectSyntaxNodeHistory {
 1591    pub fn try_clear(&mut self) {
 1592        if !self.disable_clearing {
 1593            self.stack.clear();
 1594        }
 1595    }
 1596
 1597    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1598        self.stack.push(selection);
 1599    }
 1600
 1601    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1602        self.stack.pop()
 1603    }
 1604}
 1605
 1606enum SelectSyntaxNodeScrollBehavior {
 1607    CursorTop,
 1608    FitSelection,
 1609    CursorBottom,
 1610}
 1611
 1612#[derive(Debug)]
 1613pub(crate) struct NavigationData {
 1614    cursor_anchor: Anchor,
 1615    cursor_position: Point,
 1616    scroll_anchor: ScrollAnchor,
 1617    scroll_top_row: u32,
 1618}
 1619
 1620#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1621pub enum GotoDefinitionKind {
 1622    Symbol,
 1623    Declaration,
 1624    Type,
 1625    Implementation,
 1626}
 1627
 1628pub enum FormatTarget {
 1629    Buffers(HashSet<Entity<Buffer>>),
 1630    Ranges(Vec<Range<MultiBufferPoint>>),
 1631}
 1632
 1633pub(crate) struct FocusedBlock {
 1634    id: BlockId,
 1635    focus_handle: WeakFocusHandle,
 1636}
 1637
 1638#[derive(Clone)]
 1639enum JumpData {
 1640    MultiBufferRow {
 1641        row: MultiBufferRow,
 1642        line_offset_from_top: u32,
 1643    },
 1644    MultiBufferPoint {
 1645        excerpt_id: ExcerptId,
 1646        position: Point,
 1647        anchor: text::Anchor,
 1648        line_offset_from_top: u32,
 1649    },
 1650}
 1651
 1652pub enum MultibufferSelectionMode {
 1653    First,
 1654    All,
 1655}
 1656
 1657#[derive(Clone, Copy, Debug, Default)]
 1658pub struct RewrapOptions {
 1659    pub override_language_settings: bool,
 1660    pub preserve_existing_whitespace: bool,
 1661}
 1662
 1663impl Editor {
 1664    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1665        let buffer = cx.new(|cx| Buffer::local("", cx));
 1666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1667        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1668    }
 1669
 1670    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::full(), buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn auto_height(
 1677        min_lines: usize,
 1678        max_lines: usize,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(
 1685            EditorMode::AutoHeight {
 1686                min_lines,
 1687                max_lines: Some(max_lines),
 1688            },
 1689            buffer,
 1690            None,
 1691            window,
 1692            cx,
 1693        )
 1694    }
 1695
 1696    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1697    /// The editor grows as tall as needed to fit its content.
 1698    pub fn auto_height_unbounded(
 1699        min_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: None,
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    pub fn for_buffer(
 1718        buffer: Entity<Buffer>,
 1719        project: Option<Entity<Project>>,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(EditorMode::full(), buffer, project, window, cx)
 1725    }
 1726
 1727    pub fn for_multibuffer(
 1728        buffer: Entity<MultiBuffer>,
 1729        project: Option<Entity<Project>>,
 1730        window: &mut Window,
 1731        cx: &mut Context<Self>,
 1732    ) -> Self {
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let mut clone = Self::new(
 1738            self.mode.clone(),
 1739            self.buffer.clone(),
 1740            self.project.clone(),
 1741            window,
 1742            cx,
 1743        );
 1744        self.display_map.update(cx, |display_map, cx| {
 1745            let snapshot = display_map.snapshot(cx);
 1746            clone.display_map.update(cx, |display_map, cx| {
 1747                display_map.set_state(&snapshot, cx);
 1748            });
 1749        });
 1750        clone.folds_did_change(cx);
 1751        clone.selections.clone_state(&self.selections);
 1752        clone.scroll_manager.clone_state(&self.scroll_manager);
 1753        clone.searchable = self.searchable;
 1754        clone.read_only = self.read_only;
 1755        clone
 1756    }
 1757
 1758    pub fn new(
 1759        mode: EditorMode,
 1760        buffer: Entity<MultiBuffer>,
 1761        project: Option<Entity<Project>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        Editor::new_internal(mode, buffer, project, None, window, cx)
 1766    }
 1767
 1768    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1769        let multi_buffer = self.buffer().read(cx);
 1770        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1771        let multi_buffer_visible_start = self
 1772            .scroll_manager
 1773            .anchor()
 1774            .anchor
 1775            .to_point(&multi_buffer_snapshot);
 1776        let max_row = multi_buffer_snapshot.max_point().row;
 1777
 1778        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1779        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1780
 1781        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1782            let outline_items = buffer
 1783                .outline_items_containing(
 1784                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1785                    true,
 1786                    self.style().map(|style| style.syntax.as_ref()),
 1787                )
 1788                .into_iter()
 1789                .map(|outline_item| OutlineItem {
 1790                    depth: outline_item.depth,
 1791                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1792                    source_range_for_text: Anchor::range_in_buffer(
 1793                        *excerpt_id,
 1794                        buffer_id,
 1795                        outline_item.source_range_for_text,
 1796                    ),
 1797                    text: outline_item.text,
 1798                    highlight_ranges: outline_item.highlight_ranges,
 1799                    name_ranges: outline_item.name_ranges,
 1800                    body_range: outline_item
 1801                        .body_range
 1802                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1803                    annotation_range: outline_item
 1804                        .annotation_range
 1805                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1806                });
 1807            return Some(outline_items.collect());
 1808        }
 1809
 1810        None
 1811    }
 1812
 1813    fn new_internal(
 1814        mode: EditorMode,
 1815        multi_buffer: Entity<MultiBuffer>,
 1816        project: Option<Entity<Project>>,
 1817        display_map: Option<Entity<DisplayMap>>,
 1818        window: &mut Window,
 1819        cx: &mut Context<Self>,
 1820    ) -> Self {
 1821        debug_assert!(
 1822            display_map.is_none() || mode.is_minimap(),
 1823            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1824        );
 1825
 1826        let full_mode = mode.is_full();
 1827        let is_minimap = mode.is_minimap();
 1828        let diagnostics_max_severity = if full_mode {
 1829            EditorSettings::get_global(cx)
 1830                .diagnostics_max_severity
 1831                .unwrap_or(DiagnosticSeverity::Hint)
 1832        } else {
 1833            DiagnosticSeverity::Off
 1834        };
 1835        let style = window.text_style();
 1836        let font_size = style.font_size.to_pixels(window.rem_size());
 1837        let editor = cx.entity().downgrade();
 1838        let fold_placeholder = FoldPlaceholder {
 1839            constrain_width: false,
 1840            render: Arc::new(move |fold_id, fold_range, cx| {
 1841                let editor = editor.clone();
 1842                div()
 1843                    .id(fold_id)
 1844                    .bg(cx.theme().colors().ghost_element_background)
 1845                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1846                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1847                    .rounded_xs()
 1848                    .size_full()
 1849                    .cursor_pointer()
 1850                    .child("")
 1851                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1852                    .on_click(move |_, _window, cx| {
 1853                        editor
 1854                            .update(cx, |editor, cx| {
 1855                                editor.unfold_ranges(
 1856                                    &[fold_range.start..fold_range.end],
 1857                                    true,
 1858                                    false,
 1859                                    cx,
 1860                                );
 1861                                cx.stop_propagation();
 1862                            })
 1863                            .ok();
 1864                    })
 1865                    .into_any()
 1866            }),
 1867            merge_adjacent: true,
 1868            ..FoldPlaceholder::default()
 1869        };
 1870        let display_map = display_map.unwrap_or_else(|| {
 1871            cx.new(|cx| {
 1872                DisplayMap::new(
 1873                    multi_buffer.clone(),
 1874                    style.font(),
 1875                    font_size,
 1876                    None,
 1877                    FILE_HEADER_HEIGHT,
 1878                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1879                    fold_placeholder,
 1880                    diagnostics_max_severity,
 1881                    cx,
 1882                )
 1883            })
 1884        });
 1885
 1886        let selections = SelectionsCollection::new();
 1887
 1888        let blink_manager = cx.new(|cx| {
 1889            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1890            if is_minimap {
 1891                blink_manager.disable(cx);
 1892            }
 1893            blink_manager
 1894        });
 1895
 1896        let soft_wrap_mode_override =
 1897            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1898
 1899        let mut project_subscriptions = Vec::new();
 1900        if full_mode && let Some(project) = project.as_ref() {
 1901            project_subscriptions.push(cx.subscribe_in(
 1902                project,
 1903                window,
 1904                |editor, _, event, window, cx| match event {
 1905                    project::Event::RefreshCodeLens => {
 1906                        // we always query lens with actions, without storing them, always refreshing them
 1907                    }
 1908                    project::Event::RefreshInlayHints {
 1909                        server_id,
 1910                        request_id,
 1911                    } => {
 1912                        editor.refresh_inlay_hints(
 1913                            InlayHintRefreshReason::RefreshRequested {
 1914                                server_id: *server_id,
 1915                                request_id: *request_id,
 1916                            },
 1917                            cx,
 1918                        );
 1919                    }
 1920                    project::Event::LanguageServerRemoved(..) => {
 1921                        if editor.tasks_update_task.is_none() {
 1922                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1923                        }
 1924                        editor.registered_buffers.clear();
 1925                        editor.register_visible_buffers(cx);
 1926                    }
 1927                    project::Event::LanguageServerAdded(..) => {
 1928                        if editor.tasks_update_task.is_none() {
 1929                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1930                        }
 1931                    }
 1932                    project::Event::SnippetEdit(id, snippet_edits) => {
 1933                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1934                            let focus_handle = editor.focus_handle(cx);
 1935                            if focus_handle.is_focused(window) {
 1936                                let snapshot = buffer.read(cx).snapshot();
 1937                                for (range, snippet) in snippet_edits {
 1938                                    let editor_range =
 1939                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1940                                    editor
 1941                                        .insert_snippet(
 1942                                            &[editor_range],
 1943                                            snippet.clone(),
 1944                                            window,
 1945                                            cx,
 1946                                        )
 1947                                        .ok();
 1948                                }
 1949                            }
 1950                        }
 1951                    }
 1952                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1953                        let buffer_id = *buffer_id;
 1954                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1955                            editor.register_buffer(buffer_id, cx);
 1956                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1957                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1958                            refresh_linked_ranges(editor, window, cx);
 1959                            editor.refresh_code_actions(window, cx);
 1960                            editor.refresh_document_highlights(cx);
 1961                        }
 1962                    }
 1963
 1964                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1965                        let Some(workspace) = editor.workspace() else {
 1966                            return;
 1967                        };
 1968                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1969                        else {
 1970                            return;
 1971                        };
 1972
 1973                        if active_editor.entity_id() == cx.entity_id() {
 1974                            let entity_id = cx.entity_id();
 1975                            workspace.update(cx, |this, cx| {
 1976                                this.panes_mut()
 1977                                    .iter_mut()
 1978                                    .filter(|pane| pane.entity_id() != entity_id)
 1979                                    .for_each(|p| {
 1980                                        p.update(cx, |pane, _| {
 1981                                            pane.nav_history_mut().rename_item(
 1982                                                entity_id,
 1983                                                project_path.clone(),
 1984                                                abs_path.clone().into(),
 1985                                            );
 1986                                        })
 1987                                    });
 1988                            });
 1989                            let edited_buffers_already_open = {
 1990                                let other_editors: Vec<Entity<Editor>> = workspace
 1991                                    .read(cx)
 1992                                    .panes()
 1993                                    .iter()
 1994                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1995                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1996                                    .collect();
 1997
 1998                                transaction.0.keys().all(|buffer| {
 1999                                    other_editors.iter().any(|editor| {
 2000                                        let multi_buffer = editor.read(cx).buffer();
 2001                                        multi_buffer.read(cx).is_singleton()
 2002                                            && multi_buffer.read(cx).as_singleton().map_or(
 2003                                                false,
 2004                                                |singleton| {
 2005                                                    singleton.entity_id() == buffer.entity_id()
 2006                                                },
 2007                                            )
 2008                                    })
 2009                                })
 2010                            };
 2011                            if !edited_buffers_already_open {
 2012                                let workspace = workspace.downgrade();
 2013                                let transaction = transaction.clone();
 2014                                cx.defer_in(window, move |_, window, cx| {
 2015                                    cx.spawn_in(window, async move |editor, cx| {
 2016                                        Self::open_project_transaction(
 2017                                            &editor,
 2018                                            workspace,
 2019                                            transaction,
 2020                                            "Rename".to_string(),
 2021                                            cx,
 2022                                        )
 2023                                        .await
 2024                                        .ok()
 2025                                    })
 2026                                    .detach();
 2027                                });
 2028                            }
 2029                        }
 2030                    }
 2031
 2032                    _ => {}
 2033                },
 2034            ));
 2035            if let Some(task_inventory) = project
 2036                .read(cx)
 2037                .task_store()
 2038                .read(cx)
 2039                .task_inventory()
 2040                .cloned()
 2041            {
 2042                project_subscriptions.push(cx.observe_in(
 2043                    &task_inventory,
 2044                    window,
 2045                    |editor, _, window, cx| {
 2046                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2047                    },
 2048                ));
 2049            };
 2050
 2051            project_subscriptions.push(cx.subscribe_in(
 2052                &project.read(cx).breakpoint_store(),
 2053                window,
 2054                |editor, _, event, window, cx| match event {
 2055                    BreakpointStoreEvent::ClearDebugLines => {
 2056                        editor.clear_row_highlights::<ActiveDebugLine>();
 2057                        editor.refresh_inline_values(cx);
 2058                    }
 2059                    BreakpointStoreEvent::SetDebugLine => {
 2060                        if editor.go_to_active_debug_line(window, cx) {
 2061                            cx.stop_propagation();
 2062                        }
 2063
 2064                        editor.refresh_inline_values(cx);
 2065                    }
 2066                    _ => {}
 2067                },
 2068            ));
 2069            let git_store = project.read(cx).git_store().clone();
 2070            let project = project.clone();
 2071            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2072                if let GitStoreEvent::RepositoryAdded = event {
 2073                    this.load_diff_task = Some(
 2074                        update_uncommitted_diff_for_buffer(
 2075                            cx.entity(),
 2076                            &project,
 2077                            this.buffer.read(cx).all_buffers(),
 2078                            this.buffer.clone(),
 2079                            cx,
 2080                        )
 2081                        .shared(),
 2082                    );
 2083                }
 2084            }));
 2085        }
 2086
 2087        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2088
 2089        let inlay_hint_settings =
 2090            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2091        let focus_handle = cx.focus_handle();
 2092        if !is_minimap {
 2093            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2094                .detach();
 2095            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2096                .detach();
 2097            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2098                .detach();
 2099            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2100                .detach();
 2101            cx.observe_pending_input(window, Self::observe_pending_input)
 2102                .detach();
 2103        }
 2104
 2105        let show_indent_guides =
 2106            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2107                Some(false)
 2108            } else {
 2109                None
 2110            };
 2111
 2112        let breakpoint_store = match (&mode, project.as_ref()) {
 2113            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2114            _ => None,
 2115        };
 2116
 2117        let mut code_action_providers = Vec::new();
 2118        let mut load_uncommitted_diff = None;
 2119        if let Some(project) = project.clone() {
 2120            load_uncommitted_diff = Some(
 2121                update_uncommitted_diff_for_buffer(
 2122                    cx.entity(),
 2123                    &project,
 2124                    multi_buffer.read(cx).all_buffers(),
 2125                    multi_buffer.clone(),
 2126                    cx,
 2127                )
 2128                .shared(),
 2129            );
 2130            code_action_providers.push(Rc::new(project) as Rc<_>);
 2131        }
 2132
 2133        let mut editor = Self {
 2134            focus_handle,
 2135            show_cursor_when_unfocused: false,
 2136            last_focused_descendant: None,
 2137            buffer: multi_buffer.clone(),
 2138            display_map: display_map.clone(),
 2139            placeholder_display_map: None,
 2140            selections,
 2141            scroll_manager: ScrollManager::new(cx),
 2142            columnar_selection_state: None,
 2143            add_selections_state: None,
 2144            select_next_state: None,
 2145            select_prev_state: None,
 2146            selection_history: SelectionHistory::default(),
 2147            defer_selection_effects: false,
 2148            deferred_selection_effects_state: None,
 2149            autoclose_regions: Vec::new(),
 2150            snippet_stack: InvalidationStack::default(),
 2151            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2152            ime_transaction: None,
 2153            active_diagnostics: ActiveDiagnostic::None,
 2154            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2155            inline_diagnostics_update: Task::ready(()),
 2156            inline_diagnostics: Vec::new(),
 2157            soft_wrap_mode_override,
 2158            diagnostics_max_severity,
 2159            hard_wrap: None,
 2160            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2161            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2162            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2163            project,
 2164            blink_manager: blink_manager.clone(),
 2165            show_local_selections: true,
 2166            show_scrollbars: ScrollbarAxes {
 2167                horizontal: full_mode,
 2168                vertical: full_mode,
 2169            },
 2170            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2171            offset_content: !matches!(mode, EditorMode::SingleLine),
 2172            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2173            show_gutter: full_mode,
 2174            show_line_numbers: (!full_mode).then_some(false),
 2175            use_relative_line_numbers: None,
 2176            disable_expand_excerpt_buttons: !full_mode,
 2177            show_git_diff_gutter: None,
 2178            show_code_actions: None,
 2179            show_runnables: None,
 2180            show_breakpoints: None,
 2181            show_wrap_guides: None,
 2182            show_indent_guides,
 2183            highlight_order: 0,
 2184            highlighted_rows: HashMap::default(),
 2185            background_highlights: HashMap::default(),
 2186            gutter_highlights: HashMap::default(),
 2187            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2188            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2189            nav_history: None,
 2190            context_menu: RefCell::new(None),
 2191            context_menu_options: None,
 2192            mouse_context_menu: None,
 2193            completion_tasks: Vec::new(),
 2194            inline_blame_popover: None,
 2195            inline_blame_popover_show_task: None,
 2196            signature_help_state: SignatureHelpState::default(),
 2197            auto_signature_help: None,
 2198            find_all_references_task_sources: Vec::new(),
 2199            next_completion_id: 0,
 2200            next_inlay_id: 0,
 2201            code_action_providers,
 2202            available_code_actions: None,
 2203            code_actions_task: None,
 2204            quick_selection_highlight_task: None,
 2205            debounced_selection_highlight_task: None,
 2206            document_highlights_task: None,
 2207            linked_editing_range_task: None,
 2208            pending_rename: None,
 2209            searchable: !is_minimap,
 2210            cursor_shape: EditorSettings::get_global(cx)
 2211                .cursor_shape
 2212                .unwrap_or_default(),
 2213            current_line_highlight: None,
 2214            autoindent_mode: Some(AutoindentMode::EachLine),
 2215            collapse_matches: false,
 2216            workspace: None,
 2217            input_enabled: !is_minimap,
 2218            use_modal_editing: full_mode,
 2219            read_only: is_minimap,
 2220            use_autoclose: true,
 2221            use_auto_surround: true,
 2222            auto_replace_emoji_shortcode: false,
 2223            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2224            leader_id: None,
 2225            remote_id: None,
 2226            hover_state: HoverState::default(),
 2227            pending_mouse_down: None,
 2228            hovered_link_state: None,
 2229            edit_prediction_provider: None,
 2230            active_edit_prediction: None,
 2231            stale_edit_prediction_in_menu: None,
 2232            edit_prediction_preview: EditPredictionPreview::Inactive {
 2233                released_too_fast: false,
 2234            },
 2235            inline_diagnostics_enabled: full_mode,
 2236            diagnostics_enabled: full_mode,
 2237            word_completions_enabled: full_mode,
 2238            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2239            gutter_hovered: false,
 2240            pixel_position_of_newest_cursor: None,
 2241            last_bounds: None,
 2242            last_position_map: None,
 2243            expect_bounds_change: None,
 2244            gutter_dimensions: GutterDimensions::default(),
 2245            style: None,
 2246            show_cursor_names: false,
 2247            hovered_cursors: HashMap::default(),
 2248            next_editor_action_id: EditorActionId::default(),
 2249            editor_actions: Rc::default(),
 2250            edit_predictions_hidden_for_vim_mode: false,
 2251            show_edit_predictions_override: None,
 2252            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2253            edit_prediction_settings: EditPredictionSettings::Disabled,
 2254            edit_prediction_indent_conflict: false,
 2255            edit_prediction_requires_modifier_in_indent_conflict: true,
 2256            custom_context_menu: None,
 2257            show_git_blame_gutter: false,
 2258            show_git_blame_inline: false,
 2259            show_selection_menu: None,
 2260            show_git_blame_inline_delay_task: None,
 2261            git_blame_inline_enabled: full_mode
 2262                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2263            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2264            buffer_serialization: is_minimap.not().then(|| {
 2265                BufferSerialization::new(
 2266                    ProjectSettings::get_global(cx)
 2267                        .session
 2268                        .restore_unsaved_buffers,
 2269                )
 2270            }),
 2271            blame: None,
 2272            blame_subscription: None,
 2273            tasks: BTreeMap::default(),
 2274
 2275            breakpoint_store,
 2276            gutter_breakpoint_indicator: (None, None),
 2277            hovered_diff_hunk_row: None,
 2278            _subscriptions: (!is_minimap)
 2279                .then(|| {
 2280                    vec![
 2281                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2282                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2283                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2284                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2285                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2286                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2287                        cx.observe_window_activation(window, |editor, window, cx| {
 2288                            let active = window.is_window_active();
 2289                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2290                                if active {
 2291                                    blink_manager.enable(cx);
 2292                                } else {
 2293                                    blink_manager.disable(cx);
 2294                                }
 2295                            });
 2296                            if active {
 2297                                editor.show_mouse_cursor(cx);
 2298                            }
 2299                        }),
 2300                    ]
 2301                })
 2302                .unwrap_or_default(),
 2303            tasks_update_task: None,
 2304            pull_diagnostics_task: Task::ready(()),
 2305            colors: None,
 2306            refresh_colors_task: Task::ready(()),
 2307            inlay_hints: None,
 2308            next_color_inlay_id: 0,
 2309            post_scroll_update: Task::ready(()),
 2310            linked_edit_ranges: Default::default(),
 2311            in_project_search: false,
 2312            previous_search_ranges: None,
 2313            breadcrumb_header: None,
 2314            focused_block: None,
 2315            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2316            addons: HashMap::default(),
 2317            registered_buffers: HashMap::default(),
 2318            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2319            selection_mark_mode: false,
 2320            toggle_fold_multiple_buffers: Task::ready(()),
 2321            serialize_selections: Task::ready(()),
 2322            serialize_folds: Task::ready(()),
 2323            text_style_refinement: None,
 2324            load_diff_task: load_uncommitted_diff,
 2325            temporary_diff_override: false,
 2326            mouse_cursor_hidden: false,
 2327            minimap: None,
 2328            hide_mouse_mode: EditorSettings::get_global(cx)
 2329                .hide_mouse
 2330                .unwrap_or_default(),
 2331            change_list: ChangeList::new(),
 2332            mode,
 2333            selection_drag_state: SelectionDragState::None,
 2334            folding_newlines: Task::ready(()),
 2335            lookup_key: None,
 2336            select_next_is_case_sensitive: None,
 2337        };
 2338
 2339        if is_minimap {
 2340            return editor;
 2341        }
 2342
 2343        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2344            editor
 2345                ._subscriptions
 2346                .push(cx.observe(breakpoints, |_, _, cx| {
 2347                    cx.notify();
 2348                }));
 2349        }
 2350        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2351        editor._subscriptions.extend(project_subscriptions);
 2352
 2353        editor._subscriptions.push(cx.subscribe_in(
 2354            &cx.entity(),
 2355            window,
 2356            |editor, _, e: &EditorEvent, window, cx| match e {
 2357                EditorEvent::ScrollPositionChanged { local, .. } => {
 2358                    if *local {
 2359                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2360                        editor.inline_blame_popover.take();
 2361                        let new_anchor = editor.scroll_manager.anchor();
 2362                        let snapshot = editor.snapshot(window, cx);
 2363                        editor.update_restoration_data(cx, move |data| {
 2364                            data.scroll_position = (
 2365                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2366                                new_anchor.offset,
 2367                            );
 2368                        });
 2369
 2370                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2371                            cx.background_executor()
 2372                                .timer(Duration::from_millis(50))
 2373                                .await;
 2374                            editor
 2375                                .update_in(cx, |editor, window, cx| {
 2376                                    editor.register_visible_buffers(cx);
 2377                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2378                                    editor.refresh_inlay_hints(
 2379                                        InlayHintRefreshReason::NewLinesShown,
 2380                                        cx,
 2381                                    );
 2382                                })
 2383                                .ok();
 2384                        });
 2385                    }
 2386                }
 2387                EditorEvent::Edited { .. } => {
 2388                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2389                        .map(|vim_mode| vim_mode.0)
 2390                        .unwrap_or(false);
 2391                    if !vim_mode {
 2392                        let display_map = editor.display_snapshot(cx);
 2393                        let selections = editor.selections.all_adjusted_display(&display_map);
 2394                        let pop_state = editor
 2395                            .change_list
 2396                            .last()
 2397                            .map(|previous| {
 2398                                previous.len() == selections.len()
 2399                                    && previous.iter().enumerate().all(|(ix, p)| {
 2400                                        p.to_display_point(&display_map).row()
 2401                                            == selections[ix].head().row()
 2402                                    })
 2403                            })
 2404                            .unwrap_or(false);
 2405                        let new_positions = selections
 2406                            .into_iter()
 2407                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2408                            .collect();
 2409                        editor
 2410                            .change_list
 2411                            .push_to_change_list(pop_state, new_positions);
 2412                    }
 2413                }
 2414                _ => (),
 2415            },
 2416        ));
 2417
 2418        if let Some(dap_store) = editor
 2419            .project
 2420            .as_ref()
 2421            .map(|project| project.read(cx).dap_store())
 2422        {
 2423            let weak_editor = cx.weak_entity();
 2424
 2425            editor
 2426                ._subscriptions
 2427                .push(
 2428                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2429                        let session_entity = cx.entity();
 2430                        weak_editor
 2431                            .update(cx, |editor, cx| {
 2432                                editor._subscriptions.push(
 2433                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2434                                );
 2435                            })
 2436                            .ok();
 2437                    }),
 2438                );
 2439
 2440            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2441                editor
 2442                    ._subscriptions
 2443                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2444            }
 2445        }
 2446
 2447        // skip adding the initial selection to selection history
 2448        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2449        editor.end_selection(window, cx);
 2450        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2451
 2452        editor.scroll_manager.show_scrollbars(window, cx);
 2453        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2454
 2455        if full_mode {
 2456            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2457            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2458
 2459            if editor.git_blame_inline_enabled {
 2460                editor.start_git_blame_inline(false, window, cx);
 2461            }
 2462
 2463            editor.go_to_active_debug_line(window, cx);
 2464
 2465            editor.minimap =
 2466                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2467            editor.colors = Some(LspColorData::new(cx));
 2468            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2469
 2470            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2471                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2472            }
 2473            editor.update_lsp_data(None, window, cx);
 2474            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2475        }
 2476
 2477        editor
 2478    }
 2479
 2480    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2481        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2482    }
 2483
 2484    pub fn deploy_mouse_context_menu(
 2485        &mut self,
 2486        position: gpui::Point<Pixels>,
 2487        context_menu: Entity<ContextMenu>,
 2488        window: &mut Window,
 2489        cx: &mut Context<Self>,
 2490    ) {
 2491        self.mouse_context_menu = Some(MouseContextMenu::new(
 2492            self,
 2493            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2494            context_menu,
 2495            window,
 2496            cx,
 2497        ));
 2498    }
 2499
 2500    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2501        self.mouse_context_menu
 2502            .as_ref()
 2503            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2504    }
 2505
 2506    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2507        if self
 2508            .selections
 2509            .pending_anchor()
 2510            .is_some_and(|pending_selection| {
 2511                let snapshot = self.buffer().read(cx).snapshot(cx);
 2512                pending_selection.range().includes(range, &snapshot)
 2513            })
 2514        {
 2515            return true;
 2516        }
 2517
 2518        self.selections
 2519            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2520            .into_iter()
 2521            .any(|selection| {
 2522                // This is needed to cover a corner case, if we just check for an existing
 2523                // selection in the fold range, having a cursor at the start of the fold
 2524                // marks it as selected. Non-empty selections don't cause this.
 2525                let length = selection.end - selection.start;
 2526                length > 0
 2527            })
 2528    }
 2529
 2530    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2531        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2532    }
 2533
 2534    fn key_context_internal(
 2535        &self,
 2536        has_active_edit_prediction: bool,
 2537        window: &mut Window,
 2538        cx: &mut App,
 2539    ) -> KeyContext {
 2540        let mut key_context = KeyContext::new_with_defaults();
 2541        key_context.add("Editor");
 2542        let mode = match self.mode {
 2543            EditorMode::SingleLine => "single_line",
 2544            EditorMode::AutoHeight { .. } => "auto_height",
 2545            EditorMode::Minimap { .. } => "minimap",
 2546            EditorMode::Full { .. } => "full",
 2547        };
 2548
 2549        if EditorSettings::jupyter_enabled(cx) {
 2550            key_context.add("jupyter");
 2551        }
 2552
 2553        key_context.set("mode", mode);
 2554        if self.pending_rename.is_some() {
 2555            key_context.add("renaming");
 2556        }
 2557
 2558        if let Some(snippet_stack) = self.snippet_stack.last() {
 2559            key_context.add("in_snippet");
 2560
 2561            if snippet_stack.active_index > 0 {
 2562                key_context.add("has_previous_tabstop");
 2563            }
 2564
 2565            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2566                key_context.add("has_next_tabstop");
 2567            }
 2568        }
 2569
 2570        match self.context_menu.borrow().as_ref() {
 2571            Some(CodeContextMenu::Completions(menu)) => {
 2572                if menu.visible() {
 2573                    key_context.add("menu");
 2574                    key_context.add("showing_completions");
 2575                }
 2576            }
 2577            Some(CodeContextMenu::CodeActions(menu)) => {
 2578                if menu.visible() {
 2579                    key_context.add("menu");
 2580                    key_context.add("showing_code_actions")
 2581                }
 2582            }
 2583            None => {}
 2584        }
 2585
 2586        if self.signature_help_state.has_multiple_signatures() {
 2587            key_context.add("showing_signature_help");
 2588        }
 2589
 2590        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2591        if !self.focus_handle(cx).contains_focused(window, cx)
 2592            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2593        {
 2594            for addon in self.addons.values() {
 2595                addon.extend_key_context(&mut key_context, cx)
 2596            }
 2597        }
 2598
 2599        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2600            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2601                Some(
 2602                    file.full_path(cx)
 2603                        .extension()?
 2604                        .to_string_lossy()
 2605                        .into_owned(),
 2606                )
 2607            }) {
 2608                key_context.set("extension", extension);
 2609            }
 2610        } else {
 2611            key_context.add("multibuffer");
 2612        }
 2613
 2614        if has_active_edit_prediction {
 2615            if self.edit_prediction_in_conflict() {
 2616                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2617            } else {
 2618                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2619                key_context.add("copilot_suggestion");
 2620            }
 2621        }
 2622
 2623        if self.selection_mark_mode {
 2624            key_context.add("selection_mode");
 2625        }
 2626
 2627        let disjoint = self.selections.disjoint_anchors();
 2628        let snapshot = self.snapshot(window, cx);
 2629        let snapshot = snapshot.buffer_snapshot();
 2630        if self.mode == EditorMode::SingleLine
 2631            && let [selection] = disjoint
 2632            && selection.start == selection.end
 2633            && selection.end.to_offset(snapshot) == snapshot.len()
 2634        {
 2635            key_context.add("end_of_input");
 2636        }
 2637
 2638        if self.has_any_expanded_diff_hunks(cx) {
 2639            key_context.add("diffs_expanded");
 2640        }
 2641
 2642        key_context
 2643    }
 2644
 2645    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2646        self.last_bounds.as_ref()
 2647    }
 2648
 2649    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2650        if self.mouse_cursor_hidden {
 2651            self.mouse_cursor_hidden = false;
 2652            cx.notify();
 2653        }
 2654    }
 2655
 2656    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2657        let hide_mouse_cursor = match origin {
 2658            HideMouseCursorOrigin::TypingAction => {
 2659                matches!(
 2660                    self.hide_mouse_mode,
 2661                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2662                )
 2663            }
 2664            HideMouseCursorOrigin::MovementAction => {
 2665                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2666            }
 2667        };
 2668        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2669            self.mouse_cursor_hidden = hide_mouse_cursor;
 2670            cx.notify();
 2671        }
 2672    }
 2673
 2674    pub fn edit_prediction_in_conflict(&self) -> bool {
 2675        if !self.show_edit_predictions_in_menu() {
 2676            return false;
 2677        }
 2678
 2679        let showing_completions = self
 2680            .context_menu
 2681            .borrow()
 2682            .as_ref()
 2683            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2684
 2685        showing_completions
 2686            || self.edit_prediction_requires_modifier()
 2687            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2688            // bindings to insert tab characters.
 2689            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2690    }
 2691
 2692    pub fn accept_edit_prediction_keybind(
 2693        &self,
 2694        accept_partial: bool,
 2695        window: &mut Window,
 2696        cx: &mut App,
 2697    ) -> AcceptEditPredictionBinding {
 2698        let key_context = self.key_context_internal(true, window, cx);
 2699        let in_conflict = self.edit_prediction_in_conflict();
 2700
 2701        let bindings = if accept_partial {
 2702            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2703        } else {
 2704            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2705        };
 2706
 2707        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2708        // just the first one.
 2709        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2710            !in_conflict
 2711                || binding
 2712                    .keystrokes()
 2713                    .first()
 2714                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2715        }))
 2716    }
 2717
 2718    pub fn new_file(
 2719        workspace: &mut Workspace,
 2720        _: &workspace::NewFile,
 2721        window: &mut Window,
 2722        cx: &mut Context<Workspace>,
 2723    ) {
 2724        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2725            "Failed to create buffer",
 2726            window,
 2727            cx,
 2728            |e, _, _| match e.error_code() {
 2729                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2730                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2731                e.error_tag("required").unwrap_or("the latest version")
 2732            )),
 2733                _ => None,
 2734            },
 2735        );
 2736    }
 2737
 2738    pub fn new_in_workspace(
 2739        workspace: &mut Workspace,
 2740        window: &mut Window,
 2741        cx: &mut Context<Workspace>,
 2742    ) -> Task<Result<Entity<Editor>>> {
 2743        let project = workspace.project().clone();
 2744        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2745
 2746        cx.spawn_in(window, async move |workspace, cx| {
 2747            let buffer = create.await?;
 2748            workspace.update_in(cx, |workspace, window, cx| {
 2749                let editor =
 2750                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2751                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2752                editor
 2753            })
 2754        })
 2755    }
 2756
 2757    fn new_file_vertical(
 2758        workspace: &mut Workspace,
 2759        _: &workspace::NewFileSplitVertical,
 2760        window: &mut Window,
 2761        cx: &mut Context<Workspace>,
 2762    ) {
 2763        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2764    }
 2765
 2766    fn new_file_horizontal(
 2767        workspace: &mut Workspace,
 2768        _: &workspace::NewFileSplitHorizontal,
 2769        window: &mut Window,
 2770        cx: &mut Context<Workspace>,
 2771    ) {
 2772        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2773    }
 2774
 2775    fn new_file_split(
 2776        workspace: &mut Workspace,
 2777        action: &workspace::NewFileSplit,
 2778        window: &mut Window,
 2779        cx: &mut Context<Workspace>,
 2780    ) {
 2781        Self::new_file_in_direction(workspace, action.0, window, cx)
 2782    }
 2783
 2784    fn new_file_in_direction(
 2785        workspace: &mut Workspace,
 2786        direction: SplitDirection,
 2787        window: &mut Window,
 2788        cx: &mut Context<Workspace>,
 2789    ) {
 2790        let project = workspace.project().clone();
 2791        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2792
 2793        cx.spawn_in(window, async move |workspace, cx| {
 2794            let buffer = create.await?;
 2795            workspace.update_in(cx, move |workspace, window, cx| {
 2796                workspace.split_item(
 2797                    direction,
 2798                    Box::new(
 2799                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2800                    ),
 2801                    window,
 2802                    cx,
 2803                )
 2804            })?;
 2805            anyhow::Ok(())
 2806        })
 2807        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2808            match e.error_code() {
 2809                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2810                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2811                e.error_tag("required").unwrap_or("the latest version")
 2812            )),
 2813                _ => None,
 2814            }
 2815        });
 2816    }
 2817
 2818    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2819        self.leader_id
 2820    }
 2821
 2822    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2823        &self.buffer
 2824    }
 2825
 2826    pub fn project(&self) -> Option<&Entity<Project>> {
 2827        self.project.as_ref()
 2828    }
 2829
 2830    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2831        self.workspace.as_ref()?.0.upgrade()
 2832    }
 2833
 2834    /// Returns the workspace serialization ID if this editor should be serialized.
 2835    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2836        self.workspace
 2837            .as_ref()
 2838            .filter(|_| self.should_serialize_buffer())
 2839            .and_then(|workspace| workspace.1)
 2840    }
 2841
 2842    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2843        self.buffer().read(cx).title(cx)
 2844    }
 2845
 2846    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2847        let git_blame_gutter_max_author_length = self
 2848            .render_git_blame_gutter(cx)
 2849            .then(|| {
 2850                if let Some(blame) = self.blame.as_ref() {
 2851                    let max_author_length =
 2852                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2853                    Some(max_author_length)
 2854                } else {
 2855                    None
 2856                }
 2857            })
 2858            .flatten();
 2859
 2860        EditorSnapshot {
 2861            mode: self.mode.clone(),
 2862            show_gutter: self.show_gutter,
 2863            show_line_numbers: self.show_line_numbers,
 2864            show_git_diff_gutter: self.show_git_diff_gutter,
 2865            show_code_actions: self.show_code_actions,
 2866            show_runnables: self.show_runnables,
 2867            show_breakpoints: self.show_breakpoints,
 2868            git_blame_gutter_max_author_length,
 2869            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2870            placeholder_display_snapshot: self
 2871                .placeholder_display_map
 2872                .as_ref()
 2873                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2874            scroll_anchor: self.scroll_manager.anchor(),
 2875            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2876            is_focused: self.focus_handle.is_focused(window),
 2877            current_line_highlight: self
 2878                .current_line_highlight
 2879                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2880            gutter_hovered: self.gutter_hovered,
 2881        }
 2882    }
 2883
 2884    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2885        self.buffer.read(cx).language_at(point, cx)
 2886    }
 2887
 2888    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2889        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2890    }
 2891
 2892    pub fn active_excerpt(
 2893        &self,
 2894        cx: &App,
 2895    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2896        self.buffer
 2897            .read(cx)
 2898            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2899    }
 2900
 2901    pub fn mode(&self) -> &EditorMode {
 2902        &self.mode
 2903    }
 2904
 2905    pub fn set_mode(&mut self, mode: EditorMode) {
 2906        self.mode = mode;
 2907    }
 2908
 2909    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2910        self.collaboration_hub.as_deref()
 2911    }
 2912
 2913    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2914        self.collaboration_hub = Some(hub);
 2915    }
 2916
 2917    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2918        self.in_project_search = in_project_search;
 2919    }
 2920
 2921    pub fn set_custom_context_menu(
 2922        &mut self,
 2923        f: impl 'static
 2924        + Fn(
 2925            &mut Self,
 2926            DisplayPoint,
 2927            &mut Window,
 2928            &mut Context<Self>,
 2929        ) -> Option<Entity<ui::ContextMenu>>,
 2930    ) {
 2931        self.custom_context_menu = Some(Box::new(f))
 2932    }
 2933
 2934    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2935        self.completion_provider = provider;
 2936    }
 2937
 2938    #[cfg(any(test, feature = "test-support"))]
 2939    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2940        self.completion_provider.clone()
 2941    }
 2942
 2943    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2944        self.semantics_provider.clone()
 2945    }
 2946
 2947    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2948        self.semantics_provider = provider;
 2949    }
 2950
 2951    pub fn set_edit_prediction_provider<T>(
 2952        &mut self,
 2953        provider: Option<Entity<T>>,
 2954        window: &mut Window,
 2955        cx: &mut Context<Self>,
 2956    ) where
 2957        T: EditPredictionProvider,
 2958    {
 2959        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2960            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2961                if this.focus_handle.is_focused(window) {
 2962                    this.update_visible_edit_prediction(window, cx);
 2963                }
 2964            }),
 2965            provider: Arc::new(provider),
 2966        });
 2967        self.update_edit_prediction_settings(cx);
 2968        self.refresh_edit_prediction(false, false, window, cx);
 2969    }
 2970
 2971    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2972        self.placeholder_display_map
 2973            .as_ref()
 2974            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2975    }
 2976
 2977    pub fn set_placeholder_text(
 2978        &mut self,
 2979        placeholder_text: &str,
 2980        window: &mut Window,
 2981        cx: &mut Context<Self>,
 2982    ) {
 2983        let multibuffer = cx
 2984            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2985
 2986        let style = window.text_style();
 2987
 2988        self.placeholder_display_map = Some(cx.new(|cx| {
 2989            DisplayMap::new(
 2990                multibuffer,
 2991                style.font(),
 2992                style.font_size.to_pixels(window.rem_size()),
 2993                None,
 2994                FILE_HEADER_HEIGHT,
 2995                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2996                Default::default(),
 2997                DiagnosticSeverity::Off,
 2998                cx,
 2999            )
 3000        }));
 3001        cx.notify();
 3002    }
 3003
 3004    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3005        self.cursor_shape = cursor_shape;
 3006
 3007        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3008        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3009
 3010        cx.notify();
 3011    }
 3012
 3013    pub fn set_current_line_highlight(
 3014        &mut self,
 3015        current_line_highlight: Option<CurrentLineHighlight>,
 3016    ) {
 3017        self.current_line_highlight = current_line_highlight;
 3018    }
 3019
 3020    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3021        self.collapse_matches = collapse_matches;
 3022    }
 3023
 3024    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3025        if self.collapse_matches {
 3026            return range.start..range.start;
 3027        }
 3028        range.clone()
 3029    }
 3030
 3031    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3032        self.display_map.read(cx).clip_at_line_ends
 3033    }
 3034
 3035    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3036        if self.display_map.read(cx).clip_at_line_ends != clip {
 3037            self.display_map
 3038                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3039        }
 3040    }
 3041
 3042    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3043        self.input_enabled = input_enabled;
 3044    }
 3045
 3046    pub fn set_edit_predictions_hidden_for_vim_mode(
 3047        &mut self,
 3048        hidden: bool,
 3049        window: &mut Window,
 3050        cx: &mut Context<Self>,
 3051    ) {
 3052        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3053            self.edit_predictions_hidden_for_vim_mode = hidden;
 3054            if hidden {
 3055                self.update_visible_edit_prediction(window, cx);
 3056            } else {
 3057                self.refresh_edit_prediction(true, false, window, cx);
 3058            }
 3059        }
 3060    }
 3061
 3062    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3063        self.menu_edit_predictions_policy = value;
 3064    }
 3065
 3066    pub fn set_autoindent(&mut self, autoindent: bool) {
 3067        if autoindent {
 3068            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3069        } else {
 3070            self.autoindent_mode = None;
 3071        }
 3072    }
 3073
 3074    pub fn read_only(&self, cx: &App) -> bool {
 3075        self.read_only || self.buffer.read(cx).read_only()
 3076    }
 3077
 3078    pub fn set_read_only(&mut self, read_only: bool) {
 3079        self.read_only = read_only;
 3080    }
 3081
 3082    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3083        self.use_autoclose = autoclose;
 3084    }
 3085
 3086    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3087        self.use_auto_surround = auto_surround;
 3088    }
 3089
 3090    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3091        self.auto_replace_emoji_shortcode = auto_replace;
 3092    }
 3093
 3094    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3095        self.buffer_serialization = should_serialize.then(|| {
 3096            BufferSerialization::new(
 3097                ProjectSettings::get_global(cx)
 3098                    .session
 3099                    .restore_unsaved_buffers,
 3100            )
 3101        })
 3102    }
 3103
 3104    fn should_serialize_buffer(&self) -> bool {
 3105        self.buffer_serialization.is_some()
 3106    }
 3107
 3108    pub fn toggle_edit_predictions(
 3109        &mut self,
 3110        _: &ToggleEditPrediction,
 3111        window: &mut Window,
 3112        cx: &mut Context<Self>,
 3113    ) {
 3114        if self.show_edit_predictions_override.is_some() {
 3115            self.set_show_edit_predictions(None, window, cx);
 3116        } else {
 3117            let show_edit_predictions = !self.edit_predictions_enabled();
 3118            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3119        }
 3120    }
 3121
 3122    pub fn set_show_edit_predictions(
 3123        &mut self,
 3124        show_edit_predictions: Option<bool>,
 3125        window: &mut Window,
 3126        cx: &mut Context<Self>,
 3127    ) {
 3128        self.show_edit_predictions_override = show_edit_predictions;
 3129        self.update_edit_prediction_settings(cx);
 3130
 3131        if let Some(false) = show_edit_predictions {
 3132            self.discard_edit_prediction(false, cx);
 3133        } else {
 3134            self.refresh_edit_prediction(false, true, window, cx);
 3135        }
 3136    }
 3137
 3138    fn edit_predictions_disabled_in_scope(
 3139        &self,
 3140        buffer: &Entity<Buffer>,
 3141        buffer_position: language::Anchor,
 3142        cx: &App,
 3143    ) -> bool {
 3144        let snapshot = buffer.read(cx).snapshot();
 3145        let settings = snapshot.settings_at(buffer_position, cx);
 3146
 3147        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3148            return false;
 3149        };
 3150
 3151        scope.override_name().is_some_and(|scope_name| {
 3152            settings
 3153                .edit_predictions_disabled_in
 3154                .iter()
 3155                .any(|s| s == scope_name)
 3156        })
 3157    }
 3158
 3159    pub fn set_use_modal_editing(&mut self, to: bool) {
 3160        self.use_modal_editing = to;
 3161    }
 3162
 3163    pub fn use_modal_editing(&self) -> bool {
 3164        self.use_modal_editing
 3165    }
 3166
 3167    fn selections_did_change(
 3168        &mut self,
 3169        local: bool,
 3170        old_cursor_position: &Anchor,
 3171        effects: SelectionEffects,
 3172        window: &mut Window,
 3173        cx: &mut Context<Self>,
 3174    ) {
 3175        window.invalidate_character_coordinates();
 3176
 3177        // Copy selections to primary selection buffer
 3178        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3179        if local {
 3180            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3181            let buffer_handle = self.buffer.read(cx).read(cx);
 3182
 3183            let mut text = String::new();
 3184            for (index, selection) in selections.iter().enumerate() {
 3185                let text_for_selection = buffer_handle
 3186                    .text_for_range(selection.start..selection.end)
 3187                    .collect::<String>();
 3188
 3189                text.push_str(&text_for_selection);
 3190                if index != selections.len() - 1 {
 3191                    text.push('\n');
 3192                }
 3193            }
 3194
 3195            if !text.is_empty() {
 3196                cx.write_to_primary(ClipboardItem::new_string(text));
 3197            }
 3198        }
 3199
 3200        let selection_anchors = self.selections.disjoint_anchors_arc();
 3201
 3202        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3203            self.buffer.update(cx, |buffer, cx| {
 3204                buffer.set_active_selections(
 3205                    &selection_anchors,
 3206                    self.selections.line_mode(),
 3207                    self.cursor_shape,
 3208                    cx,
 3209                )
 3210            });
 3211        }
 3212        let display_map = self
 3213            .display_map
 3214            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3215        let buffer = display_map.buffer_snapshot();
 3216        if self.selections.count() == 1 {
 3217            self.add_selections_state = None;
 3218        }
 3219        self.select_next_state = None;
 3220        self.select_prev_state = None;
 3221        self.select_syntax_node_history.try_clear();
 3222        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3223        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3224        self.take_rename(false, window, cx);
 3225
 3226        let newest_selection = self.selections.newest_anchor();
 3227        let new_cursor_position = newest_selection.head();
 3228        let selection_start = newest_selection.start;
 3229
 3230        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3231            self.push_to_nav_history(
 3232                *old_cursor_position,
 3233                Some(new_cursor_position.to_point(buffer)),
 3234                false,
 3235                effects.nav_history == Some(true),
 3236                cx,
 3237            );
 3238        }
 3239
 3240        if local {
 3241            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3242                self.register_buffer(buffer_id, cx);
 3243            }
 3244
 3245            let mut context_menu = self.context_menu.borrow_mut();
 3246            let completion_menu = match context_menu.as_ref() {
 3247                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3248                Some(CodeContextMenu::CodeActions(_)) => {
 3249                    *context_menu = None;
 3250                    None
 3251                }
 3252                None => None,
 3253            };
 3254            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3255            drop(context_menu);
 3256
 3257            if effects.completions
 3258                && let Some(completion_position) = completion_position
 3259            {
 3260                let start_offset = selection_start.to_offset(buffer);
 3261                let position_matches = start_offset == completion_position.to_offset(buffer);
 3262                let continue_showing = if position_matches {
 3263                    if self.snippet_stack.is_empty() {
 3264                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3265                            == Some(CharKind::Word)
 3266                    } else {
 3267                        // Snippet choices can be shown even when the cursor is in whitespace.
 3268                        // Dismissing the menu with actions like backspace is handled by
 3269                        // invalidation regions.
 3270                        true
 3271                    }
 3272                } else {
 3273                    false
 3274                };
 3275
 3276                if continue_showing {
 3277                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3278                } else {
 3279                    self.hide_context_menu(window, cx);
 3280                }
 3281            }
 3282
 3283            hide_hover(self, cx);
 3284
 3285            if old_cursor_position.to_display_point(&display_map).row()
 3286                != new_cursor_position.to_display_point(&display_map).row()
 3287            {
 3288                self.available_code_actions.take();
 3289            }
 3290            self.refresh_code_actions(window, cx);
 3291            self.refresh_document_highlights(cx);
 3292            refresh_linked_ranges(self, window, cx);
 3293
 3294            self.refresh_selected_text_highlights(false, window, cx);
 3295            self.refresh_matching_bracket_highlights(window, cx);
 3296            self.update_visible_edit_prediction(window, cx);
 3297            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3298            self.inline_blame_popover.take();
 3299            if self.git_blame_inline_enabled {
 3300                self.start_inline_blame_timer(window, cx);
 3301            }
 3302        }
 3303
 3304        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3305        cx.emit(EditorEvent::SelectionsChanged { local });
 3306
 3307        let selections = &self.selections.disjoint_anchors_arc();
 3308        if selections.len() == 1 {
 3309            cx.emit(SearchEvent::ActiveMatchChanged)
 3310        }
 3311        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3312            let inmemory_selections = selections
 3313                .iter()
 3314                .map(|s| {
 3315                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3316                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3317                })
 3318                .collect();
 3319            self.update_restoration_data(cx, |data| {
 3320                data.selections = inmemory_selections;
 3321            });
 3322
 3323            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3324                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3325            {
 3326                let snapshot = self.buffer().read(cx).snapshot(cx);
 3327                let selections = selections.clone();
 3328                let background_executor = cx.background_executor().clone();
 3329                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3330                self.serialize_selections = cx.background_spawn(async move {
 3331                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3332                    let db_selections = selections
 3333                        .iter()
 3334                        .map(|selection| {
 3335                            (
 3336                                selection.start.to_offset(&snapshot),
 3337                                selection.end.to_offset(&snapshot),
 3338                            )
 3339                        })
 3340                        .collect();
 3341
 3342                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3343                        .await
 3344                        .with_context(|| {
 3345                            format!(
 3346                                "persisting editor selections for editor {editor_id}, \
 3347                                workspace {workspace_id:?}"
 3348                            )
 3349                        })
 3350                        .log_err();
 3351                });
 3352            }
 3353        }
 3354
 3355        cx.notify();
 3356    }
 3357
 3358    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3359        use text::ToOffset as _;
 3360        use text::ToPoint as _;
 3361
 3362        if self.mode.is_minimap()
 3363            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3364        {
 3365            return;
 3366        }
 3367
 3368        if !self.buffer().read(cx).is_singleton() {
 3369            return;
 3370        }
 3371
 3372        let display_snapshot = self
 3373            .display_map
 3374            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3375        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3376            return;
 3377        };
 3378        let inmemory_folds = display_snapshot
 3379            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3380            .map(|fold| {
 3381                fold.range.start.text_anchor.to_point(&snapshot)
 3382                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3383            })
 3384            .collect();
 3385        self.update_restoration_data(cx, |data| {
 3386            data.folds = inmemory_folds;
 3387        });
 3388
 3389        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3390            return;
 3391        };
 3392        let background_executor = cx.background_executor().clone();
 3393        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3394        let db_folds = display_snapshot
 3395            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3396            .map(|fold| {
 3397                (
 3398                    fold.range.start.text_anchor.to_offset(&snapshot),
 3399                    fold.range.end.text_anchor.to_offset(&snapshot),
 3400                )
 3401            })
 3402            .collect();
 3403        self.serialize_folds = cx.background_spawn(async move {
 3404            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3405            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3406                .await
 3407                .with_context(|| {
 3408                    format!(
 3409                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3410                    )
 3411                })
 3412                .log_err();
 3413        });
 3414    }
 3415
 3416    pub fn sync_selections(
 3417        &mut self,
 3418        other: Entity<Editor>,
 3419        cx: &mut Context<Self>,
 3420    ) -> gpui::Subscription {
 3421        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3422        if !other_selections.is_empty() {
 3423            self.selections
 3424                .change_with(&self.display_snapshot(cx), |selections| {
 3425                    selections.select_anchors(other_selections);
 3426                });
 3427        }
 3428
 3429        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3430            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3431                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3432                if other_selections.is_empty() {
 3433                    return;
 3434                }
 3435                let snapshot = this.display_snapshot(cx);
 3436                this.selections.change_with(&snapshot, |selections| {
 3437                    selections.select_anchors(other_selections);
 3438                });
 3439            }
 3440        });
 3441
 3442        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3443            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3444                let these_selections = this.selections.disjoint_anchors().to_vec();
 3445                if these_selections.is_empty() {
 3446                    return;
 3447                }
 3448                other.update(cx, |other_editor, cx| {
 3449                    let snapshot = other_editor.display_snapshot(cx);
 3450                    other_editor
 3451                        .selections
 3452                        .change_with(&snapshot, |selections| {
 3453                            selections.select_anchors(these_selections);
 3454                        })
 3455                });
 3456            }
 3457        });
 3458
 3459        Subscription::join(other_subscription, this_subscription)
 3460    }
 3461
 3462    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3463        if self.buffer().read(cx).is_singleton() {
 3464            return;
 3465        }
 3466        let snapshot = self.buffer.read(cx).snapshot(cx);
 3467        let buffer_ids: HashSet<BufferId> = self
 3468            .selections
 3469            .disjoint_anchor_ranges()
 3470            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3471            .collect();
 3472        for buffer_id in buffer_ids {
 3473            self.unfold_buffer(buffer_id, cx);
 3474        }
 3475    }
 3476
 3477    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3478    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3479    /// effects of selection change occur at the end of the transaction.
 3480    pub fn change_selections<R>(
 3481        &mut self,
 3482        effects: SelectionEffects,
 3483        window: &mut Window,
 3484        cx: &mut Context<Self>,
 3485        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3486    ) -> R {
 3487        let snapshot = self.display_snapshot(cx);
 3488        if let Some(state) = &mut self.deferred_selection_effects_state {
 3489            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3490            state.effects.completions = effects.completions;
 3491            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3492            let (changed, result) = self.selections.change_with(&snapshot, change);
 3493            state.changed |= changed;
 3494            return result;
 3495        }
 3496        let mut state = DeferredSelectionEffectsState {
 3497            changed: false,
 3498            effects,
 3499            old_cursor_position: self.selections.newest_anchor().head(),
 3500            history_entry: SelectionHistoryEntry {
 3501                selections: self.selections.disjoint_anchors_arc(),
 3502                select_next_state: self.select_next_state.clone(),
 3503                select_prev_state: self.select_prev_state.clone(),
 3504                add_selections_state: self.add_selections_state.clone(),
 3505            },
 3506        };
 3507        let (changed, result) = self.selections.change_with(&snapshot, change);
 3508        state.changed = state.changed || changed;
 3509        if self.defer_selection_effects {
 3510            self.deferred_selection_effects_state = Some(state);
 3511        } else {
 3512            self.apply_selection_effects(state, window, cx);
 3513        }
 3514        result
 3515    }
 3516
 3517    /// Defers the effects of selection change, so that the effects of multiple calls to
 3518    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3519    /// to selection history and the state of popovers based on selection position aren't
 3520    /// erroneously updated.
 3521    pub fn with_selection_effects_deferred<R>(
 3522        &mut self,
 3523        window: &mut Window,
 3524        cx: &mut Context<Self>,
 3525        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3526    ) -> R {
 3527        let already_deferred = self.defer_selection_effects;
 3528        self.defer_selection_effects = true;
 3529        let result = update(self, window, cx);
 3530        if !already_deferred {
 3531            self.defer_selection_effects = false;
 3532            if let Some(state) = self.deferred_selection_effects_state.take() {
 3533                self.apply_selection_effects(state, window, cx);
 3534            }
 3535        }
 3536        result
 3537    }
 3538
 3539    fn apply_selection_effects(
 3540        &mut self,
 3541        state: DeferredSelectionEffectsState,
 3542        window: &mut Window,
 3543        cx: &mut Context<Self>,
 3544    ) {
 3545        if state.changed {
 3546            self.selection_history.push(state.history_entry);
 3547
 3548            if let Some(autoscroll) = state.effects.scroll {
 3549                self.request_autoscroll(autoscroll, cx);
 3550            }
 3551
 3552            let old_cursor_position = &state.old_cursor_position;
 3553
 3554            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3555
 3556            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3557                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3558            }
 3559        }
 3560    }
 3561
 3562    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3563    where
 3564        I: IntoIterator<Item = (Range<S>, T)>,
 3565        S: ToOffset,
 3566        T: Into<Arc<str>>,
 3567    {
 3568        if self.read_only(cx) {
 3569            return;
 3570        }
 3571
 3572        self.buffer
 3573            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3574    }
 3575
 3576    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3577    where
 3578        I: IntoIterator<Item = (Range<S>, T)>,
 3579        S: ToOffset,
 3580        T: Into<Arc<str>>,
 3581    {
 3582        if self.read_only(cx) {
 3583            return;
 3584        }
 3585
 3586        self.buffer.update(cx, |buffer, cx| {
 3587            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3588        });
 3589    }
 3590
 3591    pub fn edit_with_block_indent<I, S, T>(
 3592        &mut self,
 3593        edits: I,
 3594        original_indent_columns: Vec<Option<u32>>,
 3595        cx: &mut Context<Self>,
 3596    ) where
 3597        I: IntoIterator<Item = (Range<S>, T)>,
 3598        S: ToOffset,
 3599        T: Into<Arc<str>>,
 3600    {
 3601        if self.read_only(cx) {
 3602            return;
 3603        }
 3604
 3605        self.buffer.update(cx, |buffer, cx| {
 3606            buffer.edit(
 3607                edits,
 3608                Some(AutoindentMode::Block {
 3609                    original_indent_columns,
 3610                }),
 3611                cx,
 3612            )
 3613        });
 3614    }
 3615
 3616    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3617        self.hide_context_menu(window, cx);
 3618
 3619        match phase {
 3620            SelectPhase::Begin {
 3621                position,
 3622                add,
 3623                click_count,
 3624            } => self.begin_selection(position, add, click_count, window, cx),
 3625            SelectPhase::BeginColumnar {
 3626                position,
 3627                goal_column,
 3628                reset,
 3629                mode,
 3630            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3631            SelectPhase::Extend {
 3632                position,
 3633                click_count,
 3634            } => self.extend_selection(position, click_count, window, cx),
 3635            SelectPhase::Update {
 3636                position,
 3637                goal_column,
 3638                scroll_delta,
 3639            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3640            SelectPhase::End => self.end_selection(window, cx),
 3641        }
 3642    }
 3643
 3644    fn extend_selection(
 3645        &mut self,
 3646        position: DisplayPoint,
 3647        click_count: usize,
 3648        window: &mut Window,
 3649        cx: &mut Context<Self>,
 3650    ) {
 3651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3652        let tail = self.selections.newest::<usize>(&display_map).tail();
 3653        let click_count = click_count.max(match self.selections.select_mode() {
 3654            SelectMode::Character => 1,
 3655            SelectMode::Word(_) => 2,
 3656            SelectMode::Line(_) => 3,
 3657            SelectMode::All => 4,
 3658        });
 3659        self.begin_selection(position, false, click_count, window, cx);
 3660
 3661        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3662
 3663        let current_selection = match self.selections.select_mode() {
 3664            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3665            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3666        };
 3667
 3668        let mut pending_selection = self
 3669            .selections
 3670            .pending_anchor()
 3671            .cloned()
 3672            .expect("extend_selection not called with pending selection");
 3673
 3674        if pending_selection
 3675            .start
 3676            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3677            == Ordering::Greater
 3678        {
 3679            pending_selection.start = current_selection.start;
 3680        }
 3681        if pending_selection
 3682            .end
 3683            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3684            == Ordering::Less
 3685        {
 3686            pending_selection.end = current_selection.end;
 3687            pending_selection.reversed = true;
 3688        }
 3689
 3690        let mut pending_mode = self.selections.pending_mode().unwrap();
 3691        match &mut pending_mode {
 3692            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3693            _ => {}
 3694        }
 3695
 3696        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3697            SelectionEffects::scroll(Autoscroll::fit())
 3698        } else {
 3699            SelectionEffects::no_scroll()
 3700        };
 3701
 3702        self.change_selections(effects, window, cx, |s| {
 3703            s.set_pending(pending_selection.clone(), pending_mode);
 3704            s.set_is_extending(true);
 3705        });
 3706    }
 3707
 3708    fn begin_selection(
 3709        &mut self,
 3710        position: DisplayPoint,
 3711        add: bool,
 3712        click_count: usize,
 3713        window: &mut Window,
 3714        cx: &mut Context<Self>,
 3715    ) {
 3716        if !self.focus_handle.is_focused(window) {
 3717            self.last_focused_descendant = None;
 3718            window.focus(&self.focus_handle);
 3719        }
 3720
 3721        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3722        let buffer = display_map.buffer_snapshot();
 3723        let position = display_map.clip_point(position, Bias::Left);
 3724
 3725        let start;
 3726        let end;
 3727        let mode;
 3728        let mut auto_scroll;
 3729        match click_count {
 3730            1 => {
 3731                start = buffer.anchor_before(position.to_point(&display_map));
 3732                end = start;
 3733                mode = SelectMode::Character;
 3734                auto_scroll = true;
 3735            }
 3736            2 => {
 3737                let position = display_map
 3738                    .clip_point(position, Bias::Left)
 3739                    .to_offset(&display_map, Bias::Left);
 3740                let (range, _) = buffer.surrounding_word(position, None);
 3741                start = buffer.anchor_before(range.start);
 3742                end = buffer.anchor_before(range.end);
 3743                mode = SelectMode::Word(start..end);
 3744                auto_scroll = true;
 3745            }
 3746            3 => {
 3747                let position = display_map
 3748                    .clip_point(position, Bias::Left)
 3749                    .to_point(&display_map);
 3750                let line_start = display_map.prev_line_boundary(position).0;
 3751                let next_line_start = buffer.clip_point(
 3752                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3753                    Bias::Left,
 3754                );
 3755                start = buffer.anchor_before(line_start);
 3756                end = buffer.anchor_before(next_line_start);
 3757                mode = SelectMode::Line(start..end);
 3758                auto_scroll = true;
 3759            }
 3760            _ => {
 3761                start = buffer.anchor_before(0);
 3762                end = buffer.anchor_before(buffer.len());
 3763                mode = SelectMode::All;
 3764                auto_scroll = false;
 3765            }
 3766        }
 3767        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3768
 3769        let point_to_delete: Option<usize> = {
 3770            let selected_points: Vec<Selection<Point>> =
 3771                self.selections.disjoint_in_range(start..end, &display_map);
 3772
 3773            if !add || click_count > 1 {
 3774                None
 3775            } else if !selected_points.is_empty() {
 3776                Some(selected_points[0].id)
 3777            } else {
 3778                let clicked_point_already_selected =
 3779                    self.selections.disjoint_anchors().iter().find(|selection| {
 3780                        selection.start.to_point(buffer) == start.to_point(buffer)
 3781                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3782                    });
 3783
 3784                clicked_point_already_selected.map(|selection| selection.id)
 3785            }
 3786        };
 3787
 3788        let selections_count = self.selections.count();
 3789        let effects = if auto_scroll {
 3790            SelectionEffects::default()
 3791        } else {
 3792            SelectionEffects::no_scroll()
 3793        };
 3794
 3795        self.change_selections(effects, window, cx, |s| {
 3796            if let Some(point_to_delete) = point_to_delete {
 3797                s.delete(point_to_delete);
 3798
 3799                if selections_count == 1 {
 3800                    s.set_pending_anchor_range(start..end, mode);
 3801                }
 3802            } else {
 3803                if !add {
 3804                    s.clear_disjoint();
 3805                }
 3806
 3807                s.set_pending_anchor_range(start..end, mode);
 3808            }
 3809        });
 3810    }
 3811
 3812    fn begin_columnar_selection(
 3813        &mut self,
 3814        position: DisplayPoint,
 3815        goal_column: u32,
 3816        reset: bool,
 3817        mode: ColumnarMode,
 3818        window: &mut Window,
 3819        cx: &mut Context<Self>,
 3820    ) {
 3821        if !self.focus_handle.is_focused(window) {
 3822            self.last_focused_descendant = None;
 3823            window.focus(&self.focus_handle);
 3824        }
 3825
 3826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3827
 3828        if reset {
 3829            let pointer_position = display_map
 3830                .buffer_snapshot()
 3831                .anchor_before(position.to_point(&display_map));
 3832
 3833            self.change_selections(
 3834                SelectionEffects::scroll(Autoscroll::newest()),
 3835                window,
 3836                cx,
 3837                |s| {
 3838                    s.clear_disjoint();
 3839                    s.set_pending_anchor_range(
 3840                        pointer_position..pointer_position,
 3841                        SelectMode::Character,
 3842                    );
 3843                },
 3844            );
 3845        };
 3846
 3847        let tail = self.selections.newest::<Point>(&display_map).tail();
 3848        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3849        self.columnar_selection_state = match mode {
 3850            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3851                selection_tail: selection_anchor,
 3852                display_point: if reset {
 3853                    if position.column() != goal_column {
 3854                        Some(DisplayPoint::new(position.row(), goal_column))
 3855                    } else {
 3856                        None
 3857                    }
 3858                } else {
 3859                    None
 3860                },
 3861            }),
 3862            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3863                selection_tail: selection_anchor,
 3864            }),
 3865        };
 3866
 3867        if !reset {
 3868            self.select_columns(position, goal_column, &display_map, window, cx);
 3869        }
 3870    }
 3871
 3872    fn update_selection(
 3873        &mut self,
 3874        position: DisplayPoint,
 3875        goal_column: u32,
 3876        scroll_delta: gpui::Point<f32>,
 3877        window: &mut Window,
 3878        cx: &mut Context<Self>,
 3879    ) {
 3880        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3881
 3882        if self.columnar_selection_state.is_some() {
 3883            self.select_columns(position, goal_column, &display_map, window, cx);
 3884        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3885            let buffer = display_map.buffer_snapshot();
 3886            let head;
 3887            let tail;
 3888            let mode = self.selections.pending_mode().unwrap();
 3889            match &mode {
 3890                SelectMode::Character => {
 3891                    head = position.to_point(&display_map);
 3892                    tail = pending.tail().to_point(buffer);
 3893                }
 3894                SelectMode::Word(original_range) => {
 3895                    let offset = display_map
 3896                        .clip_point(position, Bias::Left)
 3897                        .to_offset(&display_map, Bias::Left);
 3898                    let original_range = original_range.to_offset(buffer);
 3899
 3900                    let head_offset = if buffer.is_inside_word(offset, None)
 3901                        || original_range.contains(&offset)
 3902                    {
 3903                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3904                        if word_range.start < original_range.start {
 3905                            word_range.start
 3906                        } else {
 3907                            word_range.end
 3908                        }
 3909                    } else {
 3910                        offset
 3911                    };
 3912
 3913                    head = head_offset.to_point(buffer);
 3914                    if head_offset <= original_range.start {
 3915                        tail = original_range.end.to_point(buffer);
 3916                    } else {
 3917                        tail = original_range.start.to_point(buffer);
 3918                    }
 3919                }
 3920                SelectMode::Line(original_range) => {
 3921                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3922
 3923                    let position = display_map
 3924                        .clip_point(position, Bias::Left)
 3925                        .to_point(&display_map);
 3926                    let line_start = display_map.prev_line_boundary(position).0;
 3927                    let next_line_start = buffer.clip_point(
 3928                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3929                        Bias::Left,
 3930                    );
 3931
 3932                    if line_start < original_range.start {
 3933                        head = line_start
 3934                    } else {
 3935                        head = next_line_start
 3936                    }
 3937
 3938                    if head <= original_range.start {
 3939                        tail = original_range.end;
 3940                    } else {
 3941                        tail = original_range.start;
 3942                    }
 3943                }
 3944                SelectMode::All => {
 3945                    return;
 3946                }
 3947            };
 3948
 3949            if head < tail {
 3950                pending.start = buffer.anchor_before(head);
 3951                pending.end = buffer.anchor_before(tail);
 3952                pending.reversed = true;
 3953            } else {
 3954                pending.start = buffer.anchor_before(tail);
 3955                pending.end = buffer.anchor_before(head);
 3956                pending.reversed = false;
 3957            }
 3958
 3959            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3960                s.set_pending(pending.clone(), mode);
 3961            });
 3962        } else {
 3963            log::error!("update_selection dispatched with no pending selection");
 3964            return;
 3965        }
 3966
 3967        self.apply_scroll_delta(scroll_delta, window, cx);
 3968        cx.notify();
 3969    }
 3970
 3971    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3972        self.columnar_selection_state.take();
 3973        if let Some(pending_mode) = self.selections.pending_mode() {
 3974            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3975            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3976                s.select(selections);
 3977                s.clear_pending();
 3978                if s.is_extending() {
 3979                    s.set_is_extending(false);
 3980                } else {
 3981                    s.set_select_mode(pending_mode);
 3982                }
 3983            });
 3984        }
 3985    }
 3986
 3987    fn select_columns(
 3988        &mut self,
 3989        head: DisplayPoint,
 3990        goal_column: u32,
 3991        display_map: &DisplaySnapshot,
 3992        window: &mut Window,
 3993        cx: &mut Context<Self>,
 3994    ) {
 3995        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3996            return;
 3997        };
 3998
 3999        let tail = match columnar_state {
 4000            ColumnarSelectionState::FromMouse {
 4001                selection_tail,
 4002                display_point,
 4003            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4004            ColumnarSelectionState::FromSelection { selection_tail } => {
 4005                selection_tail.to_display_point(display_map)
 4006            }
 4007        };
 4008
 4009        let start_row = cmp::min(tail.row(), head.row());
 4010        let end_row = cmp::max(tail.row(), head.row());
 4011        let start_column = cmp::min(tail.column(), goal_column);
 4012        let end_column = cmp::max(tail.column(), goal_column);
 4013        let reversed = start_column < tail.column();
 4014
 4015        let selection_ranges = (start_row.0..=end_row.0)
 4016            .map(DisplayRow)
 4017            .filter_map(|row| {
 4018                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4019                    || start_column <= display_map.line_len(row))
 4020                    && !display_map.is_block_line(row)
 4021                {
 4022                    let start = display_map
 4023                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4024                        .to_point(display_map);
 4025                    let end = display_map
 4026                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4027                        .to_point(display_map);
 4028                    if reversed {
 4029                        Some(end..start)
 4030                    } else {
 4031                        Some(start..end)
 4032                    }
 4033                } else {
 4034                    None
 4035                }
 4036            })
 4037            .collect::<Vec<_>>();
 4038        if selection_ranges.is_empty() {
 4039            return;
 4040        }
 4041
 4042        let ranges = match columnar_state {
 4043            ColumnarSelectionState::FromMouse { .. } => {
 4044                let mut non_empty_ranges = selection_ranges
 4045                    .iter()
 4046                    .filter(|selection_range| selection_range.start != selection_range.end)
 4047                    .peekable();
 4048                if non_empty_ranges.peek().is_some() {
 4049                    non_empty_ranges.cloned().collect()
 4050                } else {
 4051                    selection_ranges
 4052                }
 4053            }
 4054            _ => selection_ranges,
 4055        };
 4056
 4057        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4058            s.select_ranges(ranges);
 4059        });
 4060        cx.notify();
 4061    }
 4062
 4063    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4064        self.selections
 4065            .all_adjusted(snapshot)
 4066            .iter()
 4067            .any(|selection| !selection.is_empty())
 4068    }
 4069
 4070    pub fn has_pending_nonempty_selection(&self) -> bool {
 4071        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4072            Some(Selection { start, end, .. }) => start != end,
 4073            None => false,
 4074        };
 4075
 4076        pending_nonempty_selection
 4077            || (self.columnar_selection_state.is_some()
 4078                && self.selections.disjoint_anchors().len() > 1)
 4079    }
 4080
 4081    pub fn has_pending_selection(&self) -> bool {
 4082        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4083    }
 4084
 4085    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4086        self.selection_mark_mode = false;
 4087        self.selection_drag_state = SelectionDragState::None;
 4088
 4089        if self.dismiss_menus_and_popups(true, window, cx) {
 4090            cx.notify();
 4091            return;
 4092        }
 4093        if self.clear_expanded_diff_hunks(cx) {
 4094            cx.notify();
 4095            return;
 4096        }
 4097        if self.show_git_blame_gutter {
 4098            self.show_git_blame_gutter = false;
 4099            cx.notify();
 4100            return;
 4101        }
 4102
 4103        if self.mode.is_full()
 4104            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4105        {
 4106            cx.notify();
 4107            return;
 4108        }
 4109
 4110        cx.propagate();
 4111    }
 4112
 4113    pub fn dismiss_menus_and_popups(
 4114        &mut self,
 4115        is_user_requested: bool,
 4116        window: &mut Window,
 4117        cx: &mut Context<Self>,
 4118    ) -> bool {
 4119        if self.take_rename(false, window, cx).is_some() {
 4120            return true;
 4121        }
 4122
 4123        if self.hide_blame_popover(true, cx) {
 4124            return true;
 4125        }
 4126
 4127        if hide_hover(self, cx) {
 4128            return true;
 4129        }
 4130
 4131        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4132            return true;
 4133        }
 4134
 4135        if self.hide_context_menu(window, cx).is_some() {
 4136            return true;
 4137        }
 4138
 4139        if self.mouse_context_menu.take().is_some() {
 4140            return true;
 4141        }
 4142
 4143        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4144            return true;
 4145        }
 4146
 4147        if self.snippet_stack.pop().is_some() {
 4148            return true;
 4149        }
 4150
 4151        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4152            self.dismiss_diagnostics(cx);
 4153            return true;
 4154        }
 4155
 4156        false
 4157    }
 4158
 4159    fn linked_editing_ranges_for(
 4160        &self,
 4161        selection: Range<text::Anchor>,
 4162        cx: &App,
 4163    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4164        if self.linked_edit_ranges.is_empty() {
 4165            return None;
 4166        }
 4167        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4168            selection.end.buffer_id.and_then(|end_buffer_id| {
 4169                if selection.start.buffer_id != Some(end_buffer_id) {
 4170                    return None;
 4171                }
 4172                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4173                let snapshot = buffer.read(cx).snapshot();
 4174                self.linked_edit_ranges
 4175                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4176                    .map(|ranges| (ranges, snapshot, buffer))
 4177            })?;
 4178        use text::ToOffset as TO;
 4179        // find offset from the start of current range to current cursor position
 4180        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4181
 4182        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4183        let start_difference = start_offset - start_byte_offset;
 4184        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4185        let end_difference = end_offset - start_byte_offset;
 4186        // Current range has associated linked ranges.
 4187        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4188        for range in linked_ranges.iter() {
 4189            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4190            let end_offset = start_offset + end_difference;
 4191            let start_offset = start_offset + start_difference;
 4192            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4193                continue;
 4194            }
 4195            if self.selections.disjoint_anchor_ranges().any(|s| {
 4196                if s.start.buffer_id != selection.start.buffer_id
 4197                    || s.end.buffer_id != selection.end.buffer_id
 4198                {
 4199                    return false;
 4200                }
 4201                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4202                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4203            }) {
 4204                continue;
 4205            }
 4206            let start = buffer_snapshot.anchor_after(start_offset);
 4207            let end = buffer_snapshot.anchor_after(end_offset);
 4208            linked_edits
 4209                .entry(buffer.clone())
 4210                .or_default()
 4211                .push(start..end);
 4212        }
 4213        Some(linked_edits)
 4214    }
 4215
 4216    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4217        let text: Arc<str> = text.into();
 4218
 4219        if self.read_only(cx) {
 4220            return;
 4221        }
 4222
 4223        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4224
 4225        self.unfold_buffers_with_selections(cx);
 4226
 4227        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4228        let mut bracket_inserted = false;
 4229        let mut edits = Vec::new();
 4230        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4231        let mut new_selections = Vec::with_capacity(selections.len());
 4232        let mut new_autoclose_regions = Vec::new();
 4233        let snapshot = self.buffer.read(cx).read(cx);
 4234        let mut clear_linked_edit_ranges = false;
 4235
 4236        for (selection, autoclose_region) in
 4237            self.selections_with_autoclose_regions(selections, &snapshot)
 4238        {
 4239            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4240                // Determine if the inserted text matches the opening or closing
 4241                // bracket of any of this language's bracket pairs.
 4242                let mut bracket_pair = None;
 4243                let mut is_bracket_pair_start = false;
 4244                let mut is_bracket_pair_end = false;
 4245                if !text.is_empty() {
 4246                    let mut bracket_pair_matching_end = None;
 4247                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4248                    //  and they are removing the character that triggered IME popup.
 4249                    for (pair, enabled) in scope.brackets() {
 4250                        if !pair.close && !pair.surround {
 4251                            continue;
 4252                        }
 4253
 4254                        if enabled && pair.start.ends_with(text.as_ref()) {
 4255                            let prefix_len = pair.start.len() - text.len();
 4256                            let preceding_text_matches_prefix = prefix_len == 0
 4257                                || (selection.start.column >= (prefix_len as u32)
 4258                                    && snapshot.contains_str_at(
 4259                                        Point::new(
 4260                                            selection.start.row,
 4261                                            selection.start.column - (prefix_len as u32),
 4262                                        ),
 4263                                        &pair.start[..prefix_len],
 4264                                    ));
 4265                            if preceding_text_matches_prefix {
 4266                                bracket_pair = Some(pair.clone());
 4267                                is_bracket_pair_start = true;
 4268                                break;
 4269                            }
 4270                        }
 4271                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4272                        {
 4273                            // take first bracket pair matching end, but don't break in case a later bracket
 4274                            // pair matches start
 4275                            bracket_pair_matching_end = Some(pair.clone());
 4276                        }
 4277                    }
 4278                    if let Some(end) = bracket_pair_matching_end
 4279                        && bracket_pair.is_none()
 4280                    {
 4281                        bracket_pair = Some(end);
 4282                        is_bracket_pair_end = true;
 4283                    }
 4284                }
 4285
 4286                if let Some(bracket_pair) = bracket_pair {
 4287                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4288                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4289                    let auto_surround =
 4290                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4291                    if selection.is_empty() {
 4292                        if is_bracket_pair_start {
 4293                            // If the inserted text is a suffix of an opening bracket and the
 4294                            // selection is preceded by the rest of the opening bracket, then
 4295                            // insert the closing bracket.
 4296                            let following_text_allows_autoclose = snapshot
 4297                                .chars_at(selection.start)
 4298                                .next()
 4299                                .is_none_or(|c| scope.should_autoclose_before(c));
 4300
 4301                            let preceding_text_allows_autoclose = selection.start.column == 0
 4302                                || snapshot
 4303                                    .reversed_chars_at(selection.start)
 4304                                    .next()
 4305                                    .is_none_or(|c| {
 4306                                        bracket_pair.start != bracket_pair.end
 4307                                            || !snapshot
 4308                                                .char_classifier_at(selection.start)
 4309                                                .is_word(c)
 4310                                    });
 4311
 4312                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4313                                && bracket_pair.start.len() == 1
 4314                            {
 4315                                let target = bracket_pair.start.chars().next().unwrap();
 4316                                let current_line_count = snapshot
 4317                                    .reversed_chars_at(selection.start)
 4318                                    .take_while(|&c| c != '\n')
 4319                                    .filter(|&c| c == target)
 4320                                    .count();
 4321                                current_line_count % 2 == 1
 4322                            } else {
 4323                                false
 4324                            };
 4325
 4326                            if autoclose
 4327                                && bracket_pair.close
 4328                                && following_text_allows_autoclose
 4329                                && preceding_text_allows_autoclose
 4330                                && !is_closing_quote
 4331                            {
 4332                                let anchor = snapshot.anchor_before(selection.end);
 4333                                new_selections.push((selection.map(|_| anchor), text.len()));
 4334                                new_autoclose_regions.push((
 4335                                    anchor,
 4336                                    text.len(),
 4337                                    selection.id,
 4338                                    bracket_pair.clone(),
 4339                                ));
 4340                                edits.push((
 4341                                    selection.range(),
 4342                                    format!("{}{}", text, bracket_pair.end).into(),
 4343                                ));
 4344                                bracket_inserted = true;
 4345                                continue;
 4346                            }
 4347                        }
 4348
 4349                        if let Some(region) = autoclose_region {
 4350                            // If the selection is followed by an auto-inserted closing bracket,
 4351                            // then don't insert that closing bracket again; just move the selection
 4352                            // past the closing bracket.
 4353                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4354                                && text.as_ref() == region.pair.end.as_str()
 4355                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4356                            if should_skip {
 4357                                let anchor = snapshot.anchor_after(selection.end);
 4358                                new_selections
 4359                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4360                                continue;
 4361                            }
 4362                        }
 4363
 4364                        let always_treat_brackets_as_autoclosed = snapshot
 4365                            .language_settings_at(selection.start, cx)
 4366                            .always_treat_brackets_as_autoclosed;
 4367                        if always_treat_brackets_as_autoclosed
 4368                            && is_bracket_pair_end
 4369                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4370                        {
 4371                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4372                            // and the inserted text is a closing bracket and the selection is followed
 4373                            // by the closing bracket then move the selection past the closing bracket.
 4374                            let anchor = snapshot.anchor_after(selection.end);
 4375                            new_selections.push((selection.map(|_| anchor), text.len()));
 4376                            continue;
 4377                        }
 4378                    }
 4379                    // If an opening bracket is 1 character long and is typed while
 4380                    // text is selected, then surround that text with the bracket pair.
 4381                    else if auto_surround
 4382                        && bracket_pair.surround
 4383                        && is_bracket_pair_start
 4384                        && bracket_pair.start.chars().count() == 1
 4385                    {
 4386                        edits.push((selection.start..selection.start, text.clone()));
 4387                        edits.push((
 4388                            selection.end..selection.end,
 4389                            bracket_pair.end.as_str().into(),
 4390                        ));
 4391                        bracket_inserted = true;
 4392                        new_selections.push((
 4393                            Selection {
 4394                                id: selection.id,
 4395                                start: snapshot.anchor_after(selection.start),
 4396                                end: snapshot.anchor_before(selection.end),
 4397                                reversed: selection.reversed,
 4398                                goal: selection.goal,
 4399                            },
 4400                            0,
 4401                        ));
 4402                        continue;
 4403                    }
 4404                }
 4405            }
 4406
 4407            if self.auto_replace_emoji_shortcode
 4408                && selection.is_empty()
 4409                && text.as_ref().ends_with(':')
 4410                && let Some(possible_emoji_short_code) =
 4411                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4412                && !possible_emoji_short_code.is_empty()
 4413                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4414            {
 4415                let emoji_shortcode_start = Point::new(
 4416                    selection.start.row,
 4417                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4418                );
 4419
 4420                // Remove shortcode from buffer
 4421                edits.push((
 4422                    emoji_shortcode_start..selection.start,
 4423                    "".to_string().into(),
 4424                ));
 4425                new_selections.push((
 4426                    Selection {
 4427                        id: selection.id,
 4428                        start: snapshot.anchor_after(emoji_shortcode_start),
 4429                        end: snapshot.anchor_before(selection.start),
 4430                        reversed: selection.reversed,
 4431                        goal: selection.goal,
 4432                    },
 4433                    0,
 4434                ));
 4435
 4436                // Insert emoji
 4437                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4438                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4439                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4440
 4441                continue;
 4442            }
 4443
 4444            // If not handling any auto-close operation, then just replace the selected
 4445            // text with the given input and move the selection to the end of the
 4446            // newly inserted text.
 4447            let anchor = snapshot.anchor_after(selection.end);
 4448            if !self.linked_edit_ranges.is_empty() {
 4449                let start_anchor = snapshot.anchor_before(selection.start);
 4450
 4451                let is_word_char = text.chars().next().is_none_or(|char| {
 4452                    let classifier = snapshot
 4453                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4454                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4455                    classifier.is_word(char)
 4456                });
 4457
 4458                if is_word_char {
 4459                    if let Some(ranges) = self
 4460                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4461                    {
 4462                        for (buffer, edits) in ranges {
 4463                            linked_edits
 4464                                .entry(buffer.clone())
 4465                                .or_default()
 4466                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4467                        }
 4468                    }
 4469                } else {
 4470                    clear_linked_edit_ranges = true;
 4471                }
 4472            }
 4473
 4474            new_selections.push((selection.map(|_| anchor), 0));
 4475            edits.push((selection.start..selection.end, text.clone()));
 4476        }
 4477
 4478        drop(snapshot);
 4479
 4480        self.transact(window, cx, |this, window, cx| {
 4481            if clear_linked_edit_ranges {
 4482                this.linked_edit_ranges.clear();
 4483            }
 4484            let initial_buffer_versions =
 4485                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4486
 4487            this.buffer.update(cx, |buffer, cx| {
 4488                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4489            });
 4490            for (buffer, edits) in linked_edits {
 4491                buffer.update(cx, |buffer, cx| {
 4492                    let snapshot = buffer.snapshot();
 4493                    let edits = edits
 4494                        .into_iter()
 4495                        .map(|(range, text)| {
 4496                            use text::ToPoint as TP;
 4497                            let end_point = TP::to_point(&range.end, &snapshot);
 4498                            let start_point = TP::to_point(&range.start, &snapshot);
 4499                            (start_point..end_point, text)
 4500                        })
 4501                        .sorted_by_key(|(range, _)| range.start);
 4502                    buffer.edit(edits, None, cx);
 4503                })
 4504            }
 4505            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4506            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4507            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4508            let new_selections =
 4509                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4510                    .zip(new_selection_deltas)
 4511                    .map(|(selection, delta)| Selection {
 4512                        id: selection.id,
 4513                        start: selection.start + delta,
 4514                        end: selection.end + delta,
 4515                        reversed: selection.reversed,
 4516                        goal: SelectionGoal::None,
 4517                    })
 4518                    .collect::<Vec<_>>();
 4519
 4520            let mut i = 0;
 4521            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4522                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4523                let start = map.buffer_snapshot().anchor_before(position);
 4524                let end = map.buffer_snapshot().anchor_after(position);
 4525                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4526                    match existing_state
 4527                        .range
 4528                        .start
 4529                        .cmp(&start, map.buffer_snapshot())
 4530                    {
 4531                        Ordering::Less => i += 1,
 4532                        Ordering::Greater => break,
 4533                        Ordering::Equal => {
 4534                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4535                                Ordering::Less => i += 1,
 4536                                Ordering::Equal => break,
 4537                                Ordering::Greater => break,
 4538                            }
 4539                        }
 4540                    }
 4541                }
 4542                this.autoclose_regions.insert(
 4543                    i,
 4544                    AutocloseRegion {
 4545                        selection_id,
 4546                        range: start..end,
 4547                        pair,
 4548                    },
 4549                );
 4550            }
 4551
 4552            let had_active_edit_prediction = this.has_active_edit_prediction();
 4553            this.change_selections(
 4554                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4555                window,
 4556                cx,
 4557                |s| s.select(new_selections),
 4558            );
 4559
 4560            if !bracket_inserted
 4561                && let Some(on_type_format_task) =
 4562                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4563            {
 4564                on_type_format_task.detach_and_log_err(cx);
 4565            }
 4566
 4567            let editor_settings = EditorSettings::get_global(cx);
 4568            if bracket_inserted
 4569                && (editor_settings.auto_signature_help
 4570                    || editor_settings.show_signature_help_after_edits)
 4571            {
 4572                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4573            }
 4574
 4575            let trigger_in_words =
 4576                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4577            if this.hard_wrap.is_some() {
 4578                let latest: Range<Point> = this.selections.newest(&map).range();
 4579                if latest.is_empty()
 4580                    && this
 4581                        .buffer()
 4582                        .read(cx)
 4583                        .snapshot(cx)
 4584                        .line_len(MultiBufferRow(latest.start.row))
 4585                        == latest.start.column
 4586                {
 4587                    this.rewrap_impl(
 4588                        RewrapOptions {
 4589                            override_language_settings: true,
 4590                            preserve_existing_whitespace: true,
 4591                        },
 4592                        cx,
 4593                    )
 4594                }
 4595            }
 4596            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4597            refresh_linked_ranges(this, window, cx);
 4598            this.refresh_edit_prediction(true, false, window, cx);
 4599            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4600        });
 4601    }
 4602
 4603    fn find_possible_emoji_shortcode_at_position(
 4604        snapshot: &MultiBufferSnapshot,
 4605        position: Point,
 4606    ) -> Option<String> {
 4607        let mut chars = Vec::new();
 4608        let mut found_colon = false;
 4609        for char in snapshot.reversed_chars_at(position).take(100) {
 4610            // Found a possible emoji shortcode in the middle of the buffer
 4611            if found_colon {
 4612                if char.is_whitespace() {
 4613                    chars.reverse();
 4614                    return Some(chars.iter().collect());
 4615                }
 4616                // If the previous character is not a whitespace, we are in the middle of a word
 4617                // and we only want to complete the shortcode if the word is made up of other emojis
 4618                let mut containing_word = String::new();
 4619                for ch in snapshot
 4620                    .reversed_chars_at(position)
 4621                    .skip(chars.len() + 1)
 4622                    .take(100)
 4623                {
 4624                    if ch.is_whitespace() {
 4625                        break;
 4626                    }
 4627                    containing_word.push(ch);
 4628                }
 4629                let containing_word = containing_word.chars().rev().collect::<String>();
 4630                if util::word_consists_of_emojis(containing_word.as_str()) {
 4631                    chars.reverse();
 4632                    return Some(chars.iter().collect());
 4633                }
 4634            }
 4635
 4636            if char.is_whitespace() || !char.is_ascii() {
 4637                return None;
 4638            }
 4639            if char == ':' {
 4640                found_colon = true;
 4641            } else {
 4642                chars.push(char);
 4643            }
 4644        }
 4645        // Found a possible emoji shortcode at the beginning of the buffer
 4646        chars.reverse();
 4647        Some(chars.iter().collect())
 4648    }
 4649
 4650    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4651        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4652        self.transact(window, cx, |this, window, cx| {
 4653            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4654                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4655                let multi_buffer = this.buffer.read(cx);
 4656                let buffer = multi_buffer.snapshot(cx);
 4657                selections
 4658                    .iter()
 4659                    .map(|selection| {
 4660                        let start_point = selection.start.to_point(&buffer);
 4661                        let mut existing_indent =
 4662                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4663                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4664                        let start = selection.start;
 4665                        let end = selection.end;
 4666                        let selection_is_empty = start == end;
 4667                        let language_scope = buffer.language_scope_at(start);
 4668                        let (
 4669                            comment_delimiter,
 4670                            doc_delimiter,
 4671                            insert_extra_newline,
 4672                            indent_on_newline,
 4673                            indent_on_extra_newline,
 4674                        ) = if let Some(language) = &language_scope {
 4675                            let mut insert_extra_newline =
 4676                                insert_extra_newline_brackets(&buffer, start..end, language)
 4677                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4678
 4679                            // Comment extension on newline is allowed only for cursor selections
 4680                            let comment_delimiter = maybe!({
 4681                                if !selection_is_empty {
 4682                                    return None;
 4683                                }
 4684
 4685                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4686                                    return None;
 4687                                }
 4688
 4689                                let delimiters = language.line_comment_prefixes();
 4690                                let max_len_of_delimiter =
 4691                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4692                                let (snapshot, range) =
 4693                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4694
 4695                                let num_of_whitespaces = snapshot
 4696                                    .chars_for_range(range.clone())
 4697                                    .take_while(|c| c.is_whitespace())
 4698                                    .count();
 4699                                let comment_candidate = snapshot
 4700                                    .chars_for_range(range.clone())
 4701                                    .skip(num_of_whitespaces)
 4702                                    .take(max_len_of_delimiter)
 4703                                    .collect::<String>();
 4704                                let (delimiter, trimmed_len) = delimiters
 4705                                    .iter()
 4706                                    .filter_map(|delimiter| {
 4707                                        let prefix = delimiter.trim_end();
 4708                                        if comment_candidate.starts_with(prefix) {
 4709                                            Some((delimiter, prefix.len()))
 4710                                        } else {
 4711                                            None
 4712                                        }
 4713                                    })
 4714                                    .max_by_key(|(_, len)| *len)?;
 4715
 4716                                if let Some(BlockCommentConfig {
 4717                                    start: block_start, ..
 4718                                }) = language.block_comment()
 4719                                {
 4720                                    let block_start_trimmed = block_start.trim_end();
 4721                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4722                                        let line_content = snapshot
 4723                                            .chars_for_range(range)
 4724                                            .skip(num_of_whitespaces)
 4725                                            .take(block_start_trimmed.len())
 4726                                            .collect::<String>();
 4727
 4728                                        if line_content.starts_with(block_start_trimmed) {
 4729                                            return None;
 4730                                        }
 4731                                    }
 4732                                }
 4733
 4734                                let cursor_is_placed_after_comment_marker =
 4735                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4736                                if cursor_is_placed_after_comment_marker {
 4737                                    Some(delimiter.clone())
 4738                                } else {
 4739                                    None
 4740                                }
 4741                            });
 4742
 4743                            let mut indent_on_newline = IndentSize::spaces(0);
 4744                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4745
 4746                            let doc_delimiter = maybe!({
 4747                                if !selection_is_empty {
 4748                                    return None;
 4749                                }
 4750
 4751                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4752                                    return None;
 4753                                }
 4754
 4755                                let BlockCommentConfig {
 4756                                    start: start_tag,
 4757                                    end: end_tag,
 4758                                    prefix: delimiter,
 4759                                    tab_size: len,
 4760                                } = language.documentation_comment()?;
 4761                                let is_within_block_comment = buffer
 4762                                    .language_scope_at(start_point)
 4763                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4764                                if !is_within_block_comment {
 4765                                    return None;
 4766                                }
 4767
 4768                                let (snapshot, range) =
 4769                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4770
 4771                                let num_of_whitespaces = snapshot
 4772                                    .chars_for_range(range.clone())
 4773                                    .take_while(|c| c.is_whitespace())
 4774                                    .count();
 4775
 4776                                // 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.
 4777                                let column = start_point.column;
 4778                                let cursor_is_after_start_tag = {
 4779                                    let start_tag_len = start_tag.len();
 4780                                    let start_tag_line = snapshot
 4781                                        .chars_for_range(range.clone())
 4782                                        .skip(num_of_whitespaces)
 4783                                        .take(start_tag_len)
 4784                                        .collect::<String>();
 4785                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4786                                        num_of_whitespaces + start_tag_len <= column as usize
 4787                                    } else {
 4788                                        false
 4789                                    }
 4790                                };
 4791
 4792                                let cursor_is_after_delimiter = {
 4793                                    let delimiter_trim = delimiter.trim_end();
 4794                                    let delimiter_line = snapshot
 4795                                        .chars_for_range(range.clone())
 4796                                        .skip(num_of_whitespaces)
 4797                                        .take(delimiter_trim.len())
 4798                                        .collect::<String>();
 4799                                    if delimiter_line.starts_with(delimiter_trim) {
 4800                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4801                                    } else {
 4802                                        false
 4803                                    }
 4804                                };
 4805
 4806                                let cursor_is_before_end_tag_if_exists = {
 4807                                    let mut char_position = 0u32;
 4808                                    let mut end_tag_offset = None;
 4809
 4810                                    'outer: for chunk in snapshot.text_for_range(range) {
 4811                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4812                                            let chars_before_match =
 4813                                                chunk[..byte_pos].chars().count() as u32;
 4814                                            end_tag_offset =
 4815                                                Some(char_position + chars_before_match);
 4816                                            break 'outer;
 4817                                        }
 4818                                        char_position += chunk.chars().count() as u32;
 4819                                    }
 4820
 4821                                    if let Some(end_tag_offset) = end_tag_offset {
 4822                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4823                                        if cursor_is_after_start_tag {
 4824                                            if cursor_is_before_end_tag {
 4825                                                insert_extra_newline = true;
 4826                                            }
 4827                                            let cursor_is_at_start_of_end_tag =
 4828                                                column == end_tag_offset;
 4829                                            if cursor_is_at_start_of_end_tag {
 4830                                                indent_on_extra_newline.len = *len;
 4831                                            }
 4832                                        }
 4833                                        cursor_is_before_end_tag
 4834                                    } else {
 4835                                        true
 4836                                    }
 4837                                };
 4838
 4839                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4840                                    && cursor_is_before_end_tag_if_exists
 4841                                {
 4842                                    if cursor_is_after_start_tag {
 4843                                        indent_on_newline.len = *len;
 4844                                    }
 4845                                    Some(delimiter.clone())
 4846                                } else {
 4847                                    None
 4848                                }
 4849                            });
 4850
 4851                            (
 4852                                comment_delimiter,
 4853                                doc_delimiter,
 4854                                insert_extra_newline,
 4855                                indent_on_newline,
 4856                                indent_on_extra_newline,
 4857                            )
 4858                        } else {
 4859                            (
 4860                                None,
 4861                                None,
 4862                                false,
 4863                                IndentSize::default(),
 4864                                IndentSize::default(),
 4865                            )
 4866                        };
 4867
 4868                        let prevent_auto_indent = doc_delimiter.is_some();
 4869                        let delimiter = comment_delimiter.or(doc_delimiter);
 4870
 4871                        let capacity_for_delimiter =
 4872                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4873                        let mut new_text = String::with_capacity(
 4874                            1 + capacity_for_delimiter
 4875                                + existing_indent.len as usize
 4876                                + indent_on_newline.len as usize
 4877                                + indent_on_extra_newline.len as usize,
 4878                        );
 4879                        new_text.push('\n');
 4880                        new_text.extend(existing_indent.chars());
 4881                        new_text.extend(indent_on_newline.chars());
 4882
 4883                        if let Some(delimiter) = &delimiter {
 4884                            new_text.push_str(delimiter);
 4885                        }
 4886
 4887                        if insert_extra_newline {
 4888                            new_text.push('\n');
 4889                            new_text.extend(existing_indent.chars());
 4890                            new_text.extend(indent_on_extra_newline.chars());
 4891                        }
 4892
 4893                        let anchor = buffer.anchor_after(end);
 4894                        let new_selection = selection.map(|_| anchor);
 4895                        (
 4896                            ((start..end, new_text), prevent_auto_indent),
 4897                            (insert_extra_newline, new_selection),
 4898                        )
 4899                    })
 4900                    .unzip()
 4901            };
 4902
 4903            let mut auto_indent_edits = Vec::new();
 4904            let mut edits = Vec::new();
 4905            for (edit, prevent_auto_indent) in edits_with_flags {
 4906                if prevent_auto_indent {
 4907                    edits.push(edit);
 4908                } else {
 4909                    auto_indent_edits.push(edit);
 4910                }
 4911            }
 4912            if !edits.is_empty() {
 4913                this.edit(edits, cx);
 4914            }
 4915            if !auto_indent_edits.is_empty() {
 4916                this.edit_with_autoindent(auto_indent_edits, cx);
 4917            }
 4918
 4919            let buffer = this.buffer.read(cx).snapshot(cx);
 4920            let new_selections = selection_info
 4921                .into_iter()
 4922                .map(|(extra_newline_inserted, new_selection)| {
 4923                    let mut cursor = new_selection.end.to_point(&buffer);
 4924                    if extra_newline_inserted {
 4925                        cursor.row -= 1;
 4926                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4927                    }
 4928                    new_selection.map(|_| cursor)
 4929                })
 4930                .collect();
 4931
 4932            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4933            this.refresh_edit_prediction(true, false, window, cx);
 4934        });
 4935    }
 4936
 4937    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4939
 4940        let buffer = self.buffer.read(cx);
 4941        let snapshot = buffer.snapshot(cx);
 4942
 4943        let mut edits = Vec::new();
 4944        let mut rows = Vec::new();
 4945
 4946        for (rows_inserted, selection) in self
 4947            .selections
 4948            .all_adjusted(&self.display_snapshot(cx))
 4949            .into_iter()
 4950            .enumerate()
 4951        {
 4952            let cursor = selection.head();
 4953            let row = cursor.row;
 4954
 4955            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4956
 4957            let newline = "\n".to_string();
 4958            edits.push((start_of_line..start_of_line, newline));
 4959
 4960            rows.push(row + rows_inserted as u32);
 4961        }
 4962
 4963        self.transact(window, cx, |editor, window, cx| {
 4964            editor.edit(edits, cx);
 4965
 4966            editor.change_selections(Default::default(), window, cx, |s| {
 4967                let mut index = 0;
 4968                s.move_cursors_with(|map, _, _| {
 4969                    let row = rows[index];
 4970                    index += 1;
 4971
 4972                    let point = Point::new(row, 0);
 4973                    let boundary = map.next_line_boundary(point).1;
 4974                    let clipped = map.clip_point(boundary, Bias::Left);
 4975
 4976                    (clipped, SelectionGoal::None)
 4977                });
 4978            });
 4979
 4980            let mut indent_edits = Vec::new();
 4981            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4982            for row in rows {
 4983                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4984                for (row, indent) in indents {
 4985                    if indent.len == 0 {
 4986                        continue;
 4987                    }
 4988
 4989                    let text = match indent.kind {
 4990                        IndentKind::Space => " ".repeat(indent.len as usize),
 4991                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4992                    };
 4993                    let point = Point::new(row.0, 0);
 4994                    indent_edits.push((point..point, text));
 4995                }
 4996            }
 4997            editor.edit(indent_edits, cx);
 4998        });
 4999    }
 5000
 5001    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5003
 5004        let buffer = self.buffer.read(cx);
 5005        let snapshot = buffer.snapshot(cx);
 5006
 5007        let mut edits = Vec::new();
 5008        let mut rows = Vec::new();
 5009        let mut rows_inserted = 0;
 5010
 5011        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5012            let cursor = selection.head();
 5013            let row = cursor.row;
 5014
 5015            let point = Point::new(row + 1, 0);
 5016            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5017
 5018            let newline = "\n".to_string();
 5019            edits.push((start_of_line..start_of_line, newline));
 5020
 5021            rows_inserted += 1;
 5022            rows.push(row + rows_inserted);
 5023        }
 5024
 5025        self.transact(window, cx, |editor, window, cx| {
 5026            editor.edit(edits, cx);
 5027
 5028            editor.change_selections(Default::default(), window, cx, |s| {
 5029                let mut index = 0;
 5030                s.move_cursors_with(|map, _, _| {
 5031                    let row = rows[index];
 5032                    index += 1;
 5033
 5034                    let point = Point::new(row, 0);
 5035                    let boundary = map.next_line_boundary(point).1;
 5036                    let clipped = map.clip_point(boundary, Bias::Left);
 5037
 5038                    (clipped, SelectionGoal::None)
 5039                });
 5040            });
 5041
 5042            let mut indent_edits = Vec::new();
 5043            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5044            for row in rows {
 5045                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5046                for (row, indent) in indents {
 5047                    if indent.len == 0 {
 5048                        continue;
 5049                    }
 5050
 5051                    let text = match indent.kind {
 5052                        IndentKind::Space => " ".repeat(indent.len as usize),
 5053                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5054                    };
 5055                    let point = Point::new(row.0, 0);
 5056                    indent_edits.push((point..point, text));
 5057                }
 5058            }
 5059            editor.edit(indent_edits, cx);
 5060        });
 5061    }
 5062
 5063    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5064        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5065            original_indent_columns: Vec::new(),
 5066        });
 5067        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5068    }
 5069
 5070    fn insert_with_autoindent_mode(
 5071        &mut self,
 5072        text: &str,
 5073        autoindent_mode: Option<AutoindentMode>,
 5074        window: &mut Window,
 5075        cx: &mut Context<Self>,
 5076    ) {
 5077        if self.read_only(cx) {
 5078            return;
 5079        }
 5080
 5081        let text: Arc<str> = text.into();
 5082        self.transact(window, cx, |this, window, cx| {
 5083            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5084            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5085                let anchors = {
 5086                    let snapshot = buffer.read(cx);
 5087                    old_selections
 5088                        .iter()
 5089                        .map(|s| {
 5090                            let anchor = snapshot.anchor_after(s.head());
 5091                            s.map(|_| anchor)
 5092                        })
 5093                        .collect::<Vec<_>>()
 5094                };
 5095                buffer.edit(
 5096                    old_selections
 5097                        .iter()
 5098                        .map(|s| (s.start..s.end, text.clone())),
 5099                    autoindent_mode,
 5100                    cx,
 5101                );
 5102                anchors
 5103            });
 5104
 5105            this.change_selections(Default::default(), window, cx, |s| {
 5106                s.select_anchors(selection_anchors);
 5107            });
 5108
 5109            cx.notify();
 5110        });
 5111    }
 5112
 5113    fn trigger_completion_on_input(
 5114        &mut self,
 5115        text: &str,
 5116        trigger_in_words: bool,
 5117        window: &mut Window,
 5118        cx: &mut Context<Self>,
 5119    ) {
 5120        let completions_source = self
 5121            .context_menu
 5122            .borrow()
 5123            .as_ref()
 5124            .and_then(|menu| match menu {
 5125                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5126                CodeContextMenu::CodeActions(_) => None,
 5127            });
 5128
 5129        match completions_source {
 5130            Some(CompletionsMenuSource::Words { .. }) => {
 5131                self.open_or_update_completions_menu(
 5132                    Some(CompletionsMenuSource::Words {
 5133                        ignore_threshold: false,
 5134                    }),
 5135                    None,
 5136                    trigger_in_words,
 5137                    window,
 5138                    cx,
 5139                );
 5140            }
 5141            _ => self.open_or_update_completions_menu(
 5142                None,
 5143                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5144                true,
 5145                window,
 5146                cx,
 5147            ),
 5148        }
 5149    }
 5150
 5151    /// If any empty selections is touching the start of its innermost containing autoclose
 5152    /// region, expand it to select the brackets.
 5153    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5154        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5155        let buffer = self.buffer.read(cx).read(cx);
 5156        let new_selections = self
 5157            .selections_with_autoclose_regions(selections, &buffer)
 5158            .map(|(mut selection, region)| {
 5159                if !selection.is_empty() {
 5160                    return selection;
 5161                }
 5162
 5163                if let Some(region) = region {
 5164                    let mut range = region.range.to_offset(&buffer);
 5165                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5166                        range.start -= region.pair.start.len();
 5167                        if buffer.contains_str_at(range.start, &region.pair.start)
 5168                            && buffer.contains_str_at(range.end, &region.pair.end)
 5169                        {
 5170                            range.end += region.pair.end.len();
 5171                            selection.start = range.start;
 5172                            selection.end = range.end;
 5173
 5174                            return selection;
 5175                        }
 5176                    }
 5177                }
 5178
 5179                let always_treat_brackets_as_autoclosed = buffer
 5180                    .language_settings_at(selection.start, cx)
 5181                    .always_treat_brackets_as_autoclosed;
 5182
 5183                if !always_treat_brackets_as_autoclosed {
 5184                    return selection;
 5185                }
 5186
 5187                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5188                    for (pair, enabled) in scope.brackets() {
 5189                        if !enabled || !pair.close {
 5190                            continue;
 5191                        }
 5192
 5193                        if buffer.contains_str_at(selection.start, &pair.end) {
 5194                            let pair_start_len = pair.start.len();
 5195                            if buffer.contains_str_at(
 5196                                selection.start.saturating_sub(pair_start_len),
 5197                                &pair.start,
 5198                            ) {
 5199                                selection.start -= pair_start_len;
 5200                                selection.end += pair.end.len();
 5201
 5202                                return selection;
 5203                            }
 5204                        }
 5205                    }
 5206                }
 5207
 5208                selection
 5209            })
 5210            .collect();
 5211
 5212        drop(buffer);
 5213        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5214            selections.select(new_selections)
 5215        });
 5216    }
 5217
 5218    /// Iterate the given selections, and for each one, find the smallest surrounding
 5219    /// autoclose region. This uses the ordering of the selections and the autoclose
 5220    /// regions to avoid repeated comparisons.
 5221    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5222        &'a self,
 5223        selections: impl IntoIterator<Item = Selection<D>>,
 5224        buffer: &'a MultiBufferSnapshot,
 5225    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5226        let mut i = 0;
 5227        let mut regions = self.autoclose_regions.as_slice();
 5228        selections.into_iter().map(move |selection| {
 5229            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5230
 5231            let mut enclosing = None;
 5232            while let Some(pair_state) = regions.get(i) {
 5233                if pair_state.range.end.to_offset(buffer) < range.start {
 5234                    regions = &regions[i + 1..];
 5235                    i = 0;
 5236                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5237                    break;
 5238                } else {
 5239                    if pair_state.selection_id == selection.id {
 5240                        enclosing = Some(pair_state);
 5241                    }
 5242                    i += 1;
 5243                }
 5244            }
 5245
 5246            (selection, enclosing)
 5247        })
 5248    }
 5249
 5250    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5251    fn invalidate_autoclose_regions(
 5252        &mut self,
 5253        mut selections: &[Selection<Anchor>],
 5254        buffer: &MultiBufferSnapshot,
 5255    ) {
 5256        self.autoclose_regions.retain(|state| {
 5257            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5258                return false;
 5259            }
 5260
 5261            let mut i = 0;
 5262            while let Some(selection) = selections.get(i) {
 5263                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5264                    selections = &selections[1..];
 5265                    continue;
 5266                }
 5267                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5268                    break;
 5269                }
 5270                if selection.id == state.selection_id {
 5271                    return true;
 5272                } else {
 5273                    i += 1;
 5274                }
 5275            }
 5276            false
 5277        });
 5278    }
 5279
 5280    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5281        let offset = position.to_offset(buffer);
 5282        let (word_range, kind) =
 5283            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5284        if offset > word_range.start && kind == Some(CharKind::Word) {
 5285            Some(
 5286                buffer
 5287                    .text_for_range(word_range.start..offset)
 5288                    .collect::<String>(),
 5289            )
 5290        } else {
 5291            None
 5292        }
 5293    }
 5294
 5295    pub fn visible_excerpts(
 5296        &self,
 5297        cx: &mut Context<Editor>,
 5298    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5299        let Some(project) = self.project() else {
 5300            return HashMap::default();
 5301        };
 5302        let project = project.read(cx);
 5303        let multi_buffer = self.buffer().read(cx);
 5304        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5305        let multi_buffer_visible_start = self
 5306            .scroll_manager
 5307            .anchor()
 5308            .anchor
 5309            .to_point(&multi_buffer_snapshot);
 5310        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5311            multi_buffer_visible_start
 5312                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5313            Bias::Left,
 5314        );
 5315        multi_buffer_snapshot
 5316            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5317            .into_iter()
 5318            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5319            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5320                let buffer_file = project::File::from_dyn(buffer.file())?;
 5321                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5322                let worktree_entry = buffer_worktree
 5323                    .read(cx)
 5324                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5325                if worktree_entry.is_ignored {
 5326                    None
 5327                } else {
 5328                    Some((
 5329                        excerpt_id,
 5330                        (
 5331                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5332                            buffer.version().clone(),
 5333                            excerpt_visible_range,
 5334                        ),
 5335                    ))
 5336                }
 5337            })
 5338            .collect()
 5339    }
 5340
 5341    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5342        TextLayoutDetails {
 5343            text_system: window.text_system().clone(),
 5344            editor_style: self.style.clone().unwrap(),
 5345            rem_size: window.rem_size(),
 5346            scroll_anchor: self.scroll_manager.anchor(),
 5347            visible_rows: self.visible_line_count(),
 5348            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5349        }
 5350    }
 5351
 5352    fn trigger_on_type_formatting(
 5353        &self,
 5354        input: String,
 5355        window: &mut Window,
 5356        cx: &mut Context<Self>,
 5357    ) -> Option<Task<Result<()>>> {
 5358        if input.len() != 1 {
 5359            return None;
 5360        }
 5361
 5362        let project = self.project()?;
 5363        let position = self.selections.newest_anchor().head();
 5364        let (buffer, buffer_position) = self
 5365            .buffer
 5366            .read(cx)
 5367            .text_anchor_for_position(position, cx)?;
 5368
 5369        let settings = language_settings::language_settings(
 5370            buffer
 5371                .read(cx)
 5372                .language_at(buffer_position)
 5373                .map(|l| l.name()),
 5374            buffer.read(cx).file(),
 5375            cx,
 5376        );
 5377        if !settings.use_on_type_format {
 5378            return None;
 5379        }
 5380
 5381        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5382        // hence we do LSP request & edit on host side only — add formats to host's history.
 5383        let push_to_lsp_host_history = true;
 5384        // If this is not the host, append its history with new edits.
 5385        let push_to_client_history = project.read(cx).is_via_collab();
 5386
 5387        let on_type_formatting = project.update(cx, |project, cx| {
 5388            project.on_type_format(
 5389                buffer.clone(),
 5390                buffer_position,
 5391                input,
 5392                push_to_lsp_host_history,
 5393                cx,
 5394            )
 5395        });
 5396        Some(cx.spawn_in(window, async move |editor, cx| {
 5397            if let Some(transaction) = on_type_formatting.await? {
 5398                if push_to_client_history {
 5399                    buffer
 5400                        .update(cx, |buffer, _| {
 5401                            buffer.push_transaction(transaction, Instant::now());
 5402                            buffer.finalize_last_transaction();
 5403                        })
 5404                        .ok();
 5405                }
 5406                editor.update(cx, |editor, cx| {
 5407                    editor.refresh_document_highlights(cx);
 5408                })?;
 5409            }
 5410            Ok(())
 5411        }))
 5412    }
 5413
 5414    pub fn show_word_completions(
 5415        &mut self,
 5416        _: &ShowWordCompletions,
 5417        window: &mut Window,
 5418        cx: &mut Context<Self>,
 5419    ) {
 5420        self.open_or_update_completions_menu(
 5421            Some(CompletionsMenuSource::Words {
 5422                ignore_threshold: true,
 5423            }),
 5424            None,
 5425            false,
 5426            window,
 5427            cx,
 5428        );
 5429    }
 5430
 5431    pub fn show_completions(
 5432        &mut self,
 5433        _: &ShowCompletions,
 5434        window: &mut Window,
 5435        cx: &mut Context<Self>,
 5436    ) {
 5437        self.open_or_update_completions_menu(None, None, false, window, cx);
 5438    }
 5439
 5440    fn open_or_update_completions_menu(
 5441        &mut self,
 5442        requested_source: Option<CompletionsMenuSource>,
 5443        trigger: Option<String>,
 5444        trigger_in_words: bool,
 5445        window: &mut Window,
 5446        cx: &mut Context<Self>,
 5447    ) {
 5448        if self.pending_rename.is_some() {
 5449            return;
 5450        }
 5451
 5452        let completions_source = self
 5453            .context_menu
 5454            .borrow()
 5455            .as_ref()
 5456            .and_then(|menu| match menu {
 5457                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5458                CodeContextMenu::CodeActions(_) => None,
 5459            });
 5460
 5461        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5462
 5463        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5464        // inserted and selected. To handle that case, the start of the selection is used so that
 5465        // the menu starts with all choices.
 5466        let position = self
 5467            .selections
 5468            .newest_anchor()
 5469            .start
 5470            .bias_right(&multibuffer_snapshot);
 5471        if position.diff_base_anchor.is_some() {
 5472            return;
 5473        }
 5474        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5475        let Some(buffer) = buffer_position
 5476            .buffer_id
 5477            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5478        else {
 5479            return;
 5480        };
 5481        let buffer_snapshot = buffer.read(cx).snapshot();
 5482
 5483        let query: Option<Arc<String>> =
 5484            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5485                .map(|query| query.into());
 5486
 5487        drop(multibuffer_snapshot);
 5488
 5489        // Hide the current completions menu when query is empty. Without this, cached
 5490        // completions from before the trigger char may be reused (#32774).
 5491        if query.is_none() {
 5492            let menu_is_open = matches!(
 5493                self.context_menu.borrow().as_ref(),
 5494                Some(CodeContextMenu::Completions(_))
 5495            );
 5496            if menu_is_open {
 5497                self.hide_context_menu(window, cx);
 5498            }
 5499        }
 5500
 5501        let mut ignore_word_threshold = false;
 5502        let provider = match requested_source {
 5503            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5504            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5505                ignore_word_threshold = ignore_threshold;
 5506                None
 5507            }
 5508            Some(CompletionsMenuSource::SnippetChoices)
 5509            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5510                log::error!("bug: SnippetChoices requested_source is not handled");
 5511                None
 5512            }
 5513        };
 5514
 5515        let sort_completions = provider
 5516            .as_ref()
 5517            .is_some_and(|provider| provider.sort_completions());
 5518
 5519        let filter_completions = provider
 5520            .as_ref()
 5521            .is_none_or(|provider| provider.filter_completions());
 5522
 5523        let was_snippets_only = matches!(
 5524            completions_source,
 5525            Some(CompletionsMenuSource::SnippetsOnly)
 5526        );
 5527
 5528        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5529            if filter_completions {
 5530                menu.filter(
 5531                    query.clone().unwrap_or_default(),
 5532                    buffer_position.text_anchor,
 5533                    &buffer,
 5534                    provider.clone(),
 5535                    window,
 5536                    cx,
 5537                );
 5538            }
 5539            // When `is_incomplete` is false, no need to re-query completions when the current query
 5540            // is a suffix of the initial query.
 5541            let was_complete = !menu.is_incomplete;
 5542            if was_complete && !was_snippets_only {
 5543                // If the new query is a suffix of the old query (typing more characters) and
 5544                // the previous result was complete, the existing completions can be filtered.
 5545                //
 5546                // Note that snippet completions are always complete.
 5547                let query_matches = match (&menu.initial_query, &query) {
 5548                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5549                    (None, _) => true,
 5550                    _ => false,
 5551                };
 5552                if query_matches {
 5553                    let position_matches = if menu.initial_position == position {
 5554                        true
 5555                    } else {
 5556                        let snapshot = self.buffer.read(cx).read(cx);
 5557                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5558                    };
 5559                    if position_matches {
 5560                        return;
 5561                    }
 5562                }
 5563            }
 5564        };
 5565
 5566        let Anchor {
 5567            excerpt_id: buffer_excerpt_id,
 5568            text_anchor: buffer_position,
 5569            ..
 5570        } = buffer_position;
 5571
 5572        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5573            buffer_snapshot.surrounding_word(buffer_position, None)
 5574        {
 5575            let word_to_exclude = buffer_snapshot
 5576                .text_for_range(word_range.clone())
 5577                .collect::<String>();
 5578            (
 5579                buffer_snapshot.anchor_before(word_range.start)
 5580                    ..buffer_snapshot.anchor_after(buffer_position),
 5581                Some(word_to_exclude),
 5582            )
 5583        } else {
 5584            (buffer_position..buffer_position, None)
 5585        };
 5586
 5587        let language = buffer_snapshot
 5588            .language_at(buffer_position)
 5589            .map(|language| language.name());
 5590
 5591        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5592            .completions
 5593            .clone();
 5594
 5595        let show_completion_documentation = buffer_snapshot
 5596            .settings_at(buffer_position, cx)
 5597            .show_completion_documentation;
 5598
 5599        // The document can be large, so stay in reasonable bounds when searching for words,
 5600        // otherwise completion pop-up might be slow to appear.
 5601        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5602        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5603        let min_word_search = buffer_snapshot.clip_point(
 5604            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5605            Bias::Left,
 5606        );
 5607        let max_word_search = buffer_snapshot.clip_point(
 5608            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5609            Bias::Right,
 5610        );
 5611        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5612            ..buffer_snapshot.point_to_offset(max_word_search);
 5613
 5614        let skip_digits = query
 5615            .as_ref()
 5616            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5617
 5618        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5619            trigger.as_ref().is_none_or(|trigger| {
 5620                provider.is_completion_trigger(
 5621                    &buffer,
 5622                    position.text_anchor,
 5623                    trigger,
 5624                    trigger_in_words,
 5625                    completions_source.is_some(),
 5626                    cx,
 5627                )
 5628            })
 5629        });
 5630
 5631        let provider_responses = if let Some(provider) = &provider
 5632            && load_provider_completions
 5633        {
 5634            let trigger_character =
 5635                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5636            let completion_context = CompletionContext {
 5637                trigger_kind: match &trigger_character {
 5638                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5639                    None => CompletionTriggerKind::INVOKED,
 5640                },
 5641                trigger_character,
 5642            };
 5643
 5644            provider.completions(
 5645                buffer_excerpt_id,
 5646                &buffer,
 5647                buffer_position,
 5648                completion_context,
 5649                window,
 5650                cx,
 5651            )
 5652        } else {
 5653            Task::ready(Ok(Vec::new()))
 5654        };
 5655
 5656        let load_word_completions = if !self.word_completions_enabled {
 5657            false
 5658        } else if requested_source
 5659            == Some(CompletionsMenuSource::Words {
 5660                ignore_threshold: true,
 5661            })
 5662        {
 5663            true
 5664        } else {
 5665            load_provider_completions
 5666                && completion_settings.words != WordsCompletionMode::Disabled
 5667                && (ignore_word_threshold || {
 5668                    let words_min_length = completion_settings.words_min_length;
 5669                    // check whether word has at least `words_min_length` characters
 5670                    let query_chars = query.iter().flat_map(|q| q.chars());
 5671                    query_chars.take(words_min_length).count() == words_min_length
 5672                })
 5673        };
 5674
 5675        let mut words = if load_word_completions {
 5676            cx.background_spawn({
 5677                let buffer_snapshot = buffer_snapshot.clone();
 5678                async move {
 5679                    buffer_snapshot.words_in_range(WordsQuery {
 5680                        fuzzy_contents: None,
 5681                        range: word_search_range,
 5682                        skip_digits,
 5683                    })
 5684                }
 5685            })
 5686        } else {
 5687            Task::ready(BTreeMap::default())
 5688        };
 5689
 5690        let snippets = if let Some(provider) = &provider
 5691            && provider.show_snippets()
 5692            && let Some(project) = self.project()
 5693        {
 5694            let char_classifier = buffer_snapshot
 5695                .char_classifier_at(buffer_position)
 5696                .scope_context(Some(CharScopeContext::Completion));
 5697            project.update(cx, |project, cx| {
 5698                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5699            })
 5700        } else {
 5701            Task::ready(Ok(CompletionResponse {
 5702                completions: Vec::new(),
 5703                display_options: Default::default(),
 5704                is_incomplete: false,
 5705            }))
 5706        };
 5707
 5708        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5709
 5710        let id = post_inc(&mut self.next_completion_id);
 5711        let task = cx.spawn_in(window, async move |editor, cx| {
 5712            let Ok(()) = editor.update(cx, |this, _| {
 5713                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5714            }) else {
 5715                return;
 5716            };
 5717
 5718            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5719            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5720            let mut completions = Vec::new();
 5721            let mut is_incomplete = false;
 5722            let mut display_options: Option<CompletionDisplayOptions> = None;
 5723            if let Some(provider_responses) = provider_responses.await.log_err()
 5724                && !provider_responses.is_empty()
 5725            {
 5726                for response in provider_responses {
 5727                    completions.extend(response.completions);
 5728                    is_incomplete = is_incomplete || response.is_incomplete;
 5729                    match display_options.as_mut() {
 5730                        None => {
 5731                            display_options = Some(response.display_options);
 5732                        }
 5733                        Some(options) => options.merge(&response.display_options),
 5734                    }
 5735                }
 5736                if completion_settings.words == WordsCompletionMode::Fallback {
 5737                    words = Task::ready(BTreeMap::default());
 5738                }
 5739            }
 5740            let display_options = display_options.unwrap_or_default();
 5741
 5742            let mut words = words.await;
 5743            if let Some(word_to_exclude) = &word_to_exclude {
 5744                words.remove(word_to_exclude);
 5745            }
 5746            for lsp_completion in &completions {
 5747                words.remove(&lsp_completion.new_text);
 5748            }
 5749            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5750                replace_range: word_replace_range.clone(),
 5751                new_text: word.clone(),
 5752                label: CodeLabel::plain(word, None),
 5753                match_start: None,
 5754                snippet_deduplication_key: None,
 5755                icon_path: None,
 5756                documentation: None,
 5757                source: CompletionSource::BufferWord {
 5758                    word_range,
 5759                    resolved: false,
 5760                },
 5761                insert_text_mode: Some(InsertTextMode::AS_IS),
 5762                confirm: None,
 5763            }));
 5764
 5765            completions.extend(
 5766                snippets
 5767                    .await
 5768                    .into_iter()
 5769                    .flat_map(|response| response.completions),
 5770            );
 5771
 5772            let menu = if completions.is_empty() {
 5773                None
 5774            } else {
 5775                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5776                    let languages = editor
 5777                        .workspace
 5778                        .as_ref()
 5779                        .and_then(|(workspace, _)| workspace.upgrade())
 5780                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5781                    let menu = CompletionsMenu::new(
 5782                        id,
 5783                        requested_source.unwrap_or(if load_provider_completions {
 5784                            CompletionsMenuSource::Normal
 5785                        } else {
 5786                            CompletionsMenuSource::SnippetsOnly
 5787                        }),
 5788                        sort_completions,
 5789                        show_completion_documentation,
 5790                        position,
 5791                        query.clone(),
 5792                        is_incomplete,
 5793                        buffer.clone(),
 5794                        completions.into(),
 5795                        display_options,
 5796                        snippet_sort_order,
 5797                        languages,
 5798                        language,
 5799                        cx,
 5800                    );
 5801
 5802                    let query = if filter_completions { query } else { None };
 5803                    let matches_task = menu.do_async_filtering(
 5804                        query.unwrap_or_default(),
 5805                        buffer_position,
 5806                        &buffer,
 5807                        cx,
 5808                    );
 5809                    (menu, matches_task)
 5810                }) else {
 5811                    return;
 5812                };
 5813
 5814                let matches = matches_task.await;
 5815
 5816                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5817                    // Newer menu already set, so exit.
 5818                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5819                        editor.context_menu.borrow().as_ref()
 5820                        && prev_menu.id > id
 5821                    {
 5822                        return;
 5823                    };
 5824
 5825                    // Only valid to take prev_menu because either the new menu is immediately set
 5826                    // below, or the menu is hidden.
 5827                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5828                        editor.context_menu.borrow_mut().take()
 5829                    {
 5830                        let position_matches =
 5831                            if prev_menu.initial_position == menu.initial_position {
 5832                                true
 5833                            } else {
 5834                                let snapshot = editor.buffer.read(cx).read(cx);
 5835                                prev_menu.initial_position.to_offset(&snapshot)
 5836                                    == menu.initial_position.to_offset(&snapshot)
 5837                            };
 5838                        if position_matches {
 5839                            // Preserve markdown cache before `set_filter_results` because it will
 5840                            // try to populate the documentation cache.
 5841                            menu.preserve_markdown_cache(prev_menu);
 5842                        }
 5843                    };
 5844
 5845                    menu.set_filter_results(matches, provider, window, cx);
 5846                }) else {
 5847                    return;
 5848                };
 5849
 5850                menu.visible().then_some(menu)
 5851            };
 5852
 5853            editor
 5854                .update_in(cx, |editor, window, cx| {
 5855                    if editor.focus_handle.is_focused(window)
 5856                        && let Some(menu) = menu
 5857                    {
 5858                        *editor.context_menu.borrow_mut() =
 5859                            Some(CodeContextMenu::Completions(menu));
 5860
 5861                        crate::hover_popover::hide_hover(editor, cx);
 5862                        if editor.show_edit_predictions_in_menu() {
 5863                            editor.update_visible_edit_prediction(window, cx);
 5864                        } else {
 5865                            editor.discard_edit_prediction(false, cx);
 5866                        }
 5867
 5868                        cx.notify();
 5869                        return;
 5870                    }
 5871
 5872                    if editor.completion_tasks.len() <= 1 {
 5873                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5874                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5875                        // If it was already hidden and we don't show edit predictions in the menu,
 5876                        // we should also show the edit prediction when available.
 5877                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5878                            editor.update_visible_edit_prediction(window, cx);
 5879                        }
 5880                    }
 5881                })
 5882                .ok();
 5883        });
 5884
 5885        self.completion_tasks.push((id, task));
 5886    }
 5887
 5888    #[cfg(feature = "test-support")]
 5889    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5890        let menu = self.context_menu.borrow();
 5891        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5892            let completions = menu.completions.borrow();
 5893            Some(completions.to_vec())
 5894        } else {
 5895            None
 5896        }
 5897    }
 5898
 5899    pub fn with_completions_menu_matching_id<R>(
 5900        &self,
 5901        id: CompletionId,
 5902        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5903    ) -> R {
 5904        let mut context_menu = self.context_menu.borrow_mut();
 5905        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5906            return f(None);
 5907        };
 5908        if completions_menu.id != id {
 5909            return f(None);
 5910        }
 5911        f(Some(completions_menu))
 5912    }
 5913
 5914    pub fn confirm_completion(
 5915        &mut self,
 5916        action: &ConfirmCompletion,
 5917        window: &mut Window,
 5918        cx: &mut Context<Self>,
 5919    ) -> Option<Task<Result<()>>> {
 5920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5921        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5922    }
 5923
 5924    pub fn confirm_completion_insert(
 5925        &mut self,
 5926        _: &ConfirmCompletionInsert,
 5927        window: &mut Window,
 5928        cx: &mut Context<Self>,
 5929    ) -> Option<Task<Result<()>>> {
 5930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5931        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5932    }
 5933
 5934    pub fn confirm_completion_replace(
 5935        &mut self,
 5936        _: &ConfirmCompletionReplace,
 5937        window: &mut Window,
 5938        cx: &mut Context<Self>,
 5939    ) -> Option<Task<Result<()>>> {
 5940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5941        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5942    }
 5943
 5944    pub fn compose_completion(
 5945        &mut self,
 5946        action: &ComposeCompletion,
 5947        window: &mut Window,
 5948        cx: &mut Context<Self>,
 5949    ) -> Option<Task<Result<()>>> {
 5950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5951        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5952    }
 5953
 5954    fn do_completion(
 5955        &mut self,
 5956        item_ix: Option<usize>,
 5957        intent: CompletionIntent,
 5958        window: &mut Window,
 5959        cx: &mut Context<Editor>,
 5960    ) -> Option<Task<Result<()>>> {
 5961        use language::ToOffset as _;
 5962
 5963        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5964        else {
 5965            return None;
 5966        };
 5967
 5968        let candidate_id = {
 5969            let entries = completions_menu.entries.borrow();
 5970            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5971            if self.show_edit_predictions_in_menu() {
 5972                self.discard_edit_prediction(true, cx);
 5973            }
 5974            mat.candidate_id
 5975        };
 5976
 5977        let completion = completions_menu
 5978            .completions
 5979            .borrow()
 5980            .get(candidate_id)?
 5981            .clone();
 5982        cx.stop_propagation();
 5983
 5984        let buffer_handle = completions_menu.buffer.clone();
 5985
 5986        let CompletionEdit {
 5987            new_text,
 5988            snippet,
 5989            replace_range,
 5990        } = process_completion_for_edit(
 5991            &completion,
 5992            intent,
 5993            &buffer_handle,
 5994            &completions_menu.initial_position.text_anchor,
 5995            cx,
 5996        );
 5997
 5998        let buffer = buffer_handle.read(cx);
 5999        let snapshot = self.buffer.read(cx).snapshot(cx);
 6000        let newest_anchor = self.selections.newest_anchor();
 6001        let replace_range_multibuffer = {
 6002            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6003            excerpt.map_range_from_buffer(replace_range.clone())
 6004        };
 6005        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6006            return None;
 6007        }
 6008
 6009        let old_text = buffer
 6010            .text_for_range(replace_range.clone())
 6011            .collect::<String>();
 6012        let lookbehind = newest_anchor
 6013            .start
 6014            .text_anchor
 6015            .to_offset(buffer)
 6016            .saturating_sub(replace_range.start);
 6017        let lookahead = replace_range
 6018            .end
 6019            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6020        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6021        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6022
 6023        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6024        let mut ranges = Vec::new();
 6025        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6026
 6027        for selection in &selections {
 6028            let range = if selection.id == newest_anchor.id {
 6029                replace_range_multibuffer.clone()
 6030            } else {
 6031                let mut range = selection.range();
 6032
 6033                // if prefix is present, don't duplicate it
 6034                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6035                    range.start = range.start.saturating_sub(lookbehind);
 6036
 6037                    // if suffix is also present, mimic the newest cursor and replace it
 6038                    if selection.id != newest_anchor.id
 6039                        && snapshot.contains_str_at(range.end, suffix)
 6040                    {
 6041                        range.end += lookahead;
 6042                    }
 6043                }
 6044                range
 6045            };
 6046
 6047            ranges.push(range.clone());
 6048
 6049            if !self.linked_edit_ranges.is_empty() {
 6050                let start_anchor = snapshot.anchor_before(range.start);
 6051                let end_anchor = snapshot.anchor_after(range.end);
 6052                if let Some(ranges) = self
 6053                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6054                {
 6055                    for (buffer, edits) in ranges {
 6056                        linked_edits
 6057                            .entry(buffer.clone())
 6058                            .or_default()
 6059                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6060                    }
 6061                }
 6062            }
 6063        }
 6064
 6065        let common_prefix_len = old_text
 6066            .chars()
 6067            .zip(new_text.chars())
 6068            .take_while(|(a, b)| a == b)
 6069            .map(|(a, _)| a.len_utf8())
 6070            .sum::<usize>();
 6071
 6072        cx.emit(EditorEvent::InputHandled {
 6073            utf16_range_to_replace: None,
 6074            text: new_text[common_prefix_len..].into(),
 6075        });
 6076
 6077        self.transact(window, cx, |editor, window, cx| {
 6078            if let Some(mut snippet) = snippet {
 6079                snippet.text = new_text.to_string();
 6080                editor
 6081                    .insert_snippet(&ranges, snippet, window, cx)
 6082                    .log_err();
 6083            } else {
 6084                editor.buffer.update(cx, |multi_buffer, cx| {
 6085                    let auto_indent = match completion.insert_text_mode {
 6086                        Some(InsertTextMode::AS_IS) => None,
 6087                        _ => editor.autoindent_mode.clone(),
 6088                    };
 6089                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6090                    multi_buffer.edit(edits, auto_indent, cx);
 6091                });
 6092            }
 6093            for (buffer, edits) in linked_edits {
 6094                buffer.update(cx, |buffer, cx| {
 6095                    let snapshot = buffer.snapshot();
 6096                    let edits = edits
 6097                        .into_iter()
 6098                        .map(|(range, text)| {
 6099                            use text::ToPoint as TP;
 6100                            let end_point = TP::to_point(&range.end, &snapshot);
 6101                            let start_point = TP::to_point(&range.start, &snapshot);
 6102                            (start_point..end_point, text)
 6103                        })
 6104                        .sorted_by_key(|(range, _)| range.start);
 6105                    buffer.edit(edits, None, cx);
 6106                })
 6107            }
 6108
 6109            editor.refresh_edit_prediction(true, false, window, cx);
 6110        });
 6111        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6112
 6113        let show_new_completions_on_confirm = completion
 6114            .confirm
 6115            .as_ref()
 6116            .is_some_and(|confirm| confirm(intent, window, cx));
 6117        if show_new_completions_on_confirm {
 6118            self.open_or_update_completions_menu(None, None, false, window, cx);
 6119        }
 6120
 6121        let provider = self.completion_provider.as_ref()?;
 6122        drop(completion);
 6123        let apply_edits = provider.apply_additional_edits_for_completion(
 6124            buffer_handle,
 6125            completions_menu.completions.clone(),
 6126            candidate_id,
 6127            true,
 6128            cx,
 6129        );
 6130
 6131        let editor_settings = EditorSettings::get_global(cx);
 6132        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6133            // After the code completion is finished, users often want to know what signatures are needed.
 6134            // so we should automatically call signature_help
 6135            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6136        }
 6137
 6138        Some(cx.foreground_executor().spawn(async move {
 6139            apply_edits.await?;
 6140            Ok(())
 6141        }))
 6142    }
 6143
 6144    pub fn toggle_code_actions(
 6145        &mut self,
 6146        action: &ToggleCodeActions,
 6147        window: &mut Window,
 6148        cx: &mut Context<Self>,
 6149    ) {
 6150        let quick_launch = action.quick_launch;
 6151        let mut context_menu = self.context_menu.borrow_mut();
 6152        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6153            if code_actions.deployed_from == action.deployed_from {
 6154                // Toggle if we're selecting the same one
 6155                *context_menu = None;
 6156                cx.notify();
 6157                return;
 6158            } else {
 6159                // Otherwise, clear it and start a new one
 6160                *context_menu = None;
 6161                cx.notify();
 6162            }
 6163        }
 6164        drop(context_menu);
 6165        let snapshot = self.snapshot(window, cx);
 6166        let deployed_from = action.deployed_from.clone();
 6167        let action = action.clone();
 6168        self.completion_tasks.clear();
 6169        self.discard_edit_prediction(false, cx);
 6170
 6171        let multibuffer_point = match &action.deployed_from {
 6172            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6173                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6174            }
 6175            _ => self
 6176                .selections
 6177                .newest::<Point>(&snapshot.display_snapshot)
 6178                .head(),
 6179        };
 6180        let Some((buffer, buffer_row)) = snapshot
 6181            .buffer_snapshot()
 6182            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6183            .and_then(|(buffer_snapshot, range)| {
 6184                self.buffer()
 6185                    .read(cx)
 6186                    .buffer(buffer_snapshot.remote_id())
 6187                    .map(|buffer| (buffer, range.start.row))
 6188            })
 6189        else {
 6190            return;
 6191        };
 6192        let buffer_id = buffer.read(cx).remote_id();
 6193        let tasks = self
 6194            .tasks
 6195            .get(&(buffer_id, buffer_row))
 6196            .map(|t| Arc::new(t.to_owned()));
 6197
 6198        if !self.focus_handle.is_focused(window) {
 6199            return;
 6200        }
 6201        let project = self.project.clone();
 6202
 6203        let code_actions_task = match deployed_from {
 6204            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6205            _ => self.code_actions(buffer_row, window, cx),
 6206        };
 6207
 6208        let runnable_task = match deployed_from {
 6209            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6210            _ => {
 6211                let mut task_context_task = Task::ready(None);
 6212                if let Some(tasks) = &tasks
 6213                    && let Some(project) = project
 6214                {
 6215                    task_context_task =
 6216                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6217                }
 6218
 6219                cx.spawn_in(window, {
 6220                    let buffer = buffer.clone();
 6221                    async move |editor, cx| {
 6222                        let task_context = task_context_task.await;
 6223
 6224                        let resolved_tasks =
 6225                            tasks
 6226                                .zip(task_context.clone())
 6227                                .map(|(tasks, task_context)| ResolvedTasks {
 6228                                    templates: tasks.resolve(&task_context).collect(),
 6229                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6230                                        multibuffer_point.row,
 6231                                        tasks.column,
 6232                                    )),
 6233                                });
 6234                        let debug_scenarios = editor
 6235                            .update(cx, |editor, cx| {
 6236                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6237                            })?
 6238                            .await;
 6239                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6240                    }
 6241                })
 6242            }
 6243        };
 6244
 6245        cx.spawn_in(window, async move |editor, cx| {
 6246            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6247            let code_actions = code_actions_task.await;
 6248            let spawn_straight_away = quick_launch
 6249                && resolved_tasks
 6250                    .as_ref()
 6251                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6252                && code_actions
 6253                    .as_ref()
 6254                    .is_none_or(|actions| actions.is_empty())
 6255                && debug_scenarios.is_empty();
 6256
 6257            editor.update_in(cx, |editor, window, cx| {
 6258                crate::hover_popover::hide_hover(editor, cx);
 6259                let actions = CodeActionContents::new(
 6260                    resolved_tasks,
 6261                    code_actions,
 6262                    debug_scenarios,
 6263                    task_context.unwrap_or_default(),
 6264                );
 6265
 6266                // Don't show the menu if there are no actions available
 6267                if actions.is_empty() {
 6268                    cx.notify();
 6269                    return Task::ready(Ok(()));
 6270                }
 6271
 6272                *editor.context_menu.borrow_mut() =
 6273                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6274                        buffer,
 6275                        actions,
 6276                        selected_item: Default::default(),
 6277                        scroll_handle: UniformListScrollHandle::default(),
 6278                        deployed_from,
 6279                    }));
 6280                cx.notify();
 6281                if spawn_straight_away
 6282                    && let Some(task) = editor.confirm_code_action(
 6283                        &ConfirmCodeAction { item_ix: Some(0) },
 6284                        window,
 6285                        cx,
 6286                    )
 6287                {
 6288                    return task;
 6289                }
 6290
 6291                Task::ready(Ok(()))
 6292            })
 6293        })
 6294        .detach_and_log_err(cx);
 6295    }
 6296
 6297    fn debug_scenarios(
 6298        &mut self,
 6299        resolved_tasks: &Option<ResolvedTasks>,
 6300        buffer: &Entity<Buffer>,
 6301        cx: &mut App,
 6302    ) -> Task<Vec<task::DebugScenario>> {
 6303        maybe!({
 6304            let project = self.project()?;
 6305            let dap_store = project.read(cx).dap_store();
 6306            let mut scenarios = vec![];
 6307            let resolved_tasks = resolved_tasks.as_ref()?;
 6308            let buffer = buffer.read(cx);
 6309            let language = buffer.language()?;
 6310            let file = buffer.file();
 6311            let debug_adapter = language_settings(language.name().into(), file, cx)
 6312                .debuggers
 6313                .first()
 6314                .map(SharedString::from)
 6315                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6316
 6317            dap_store.update(cx, |dap_store, cx| {
 6318                for (_, task) in &resolved_tasks.templates {
 6319                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6320                        task.original_task().clone(),
 6321                        debug_adapter.clone().into(),
 6322                        task.display_label().to_owned().into(),
 6323                        cx,
 6324                    );
 6325                    scenarios.push(maybe_scenario);
 6326                }
 6327            });
 6328            Some(cx.background_spawn(async move {
 6329                futures::future::join_all(scenarios)
 6330                    .await
 6331                    .into_iter()
 6332                    .flatten()
 6333                    .collect::<Vec<_>>()
 6334            }))
 6335        })
 6336        .unwrap_or_else(|| Task::ready(vec![]))
 6337    }
 6338
 6339    fn code_actions(
 6340        &mut self,
 6341        buffer_row: u32,
 6342        window: &mut Window,
 6343        cx: &mut Context<Self>,
 6344    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6345        let mut task = self.code_actions_task.take();
 6346        cx.spawn_in(window, async move |editor, cx| {
 6347            while let Some(prev_task) = task {
 6348                prev_task.await.log_err();
 6349                task = editor
 6350                    .update(cx, |this, _| this.code_actions_task.take())
 6351                    .ok()?;
 6352            }
 6353
 6354            editor
 6355                .update(cx, |editor, cx| {
 6356                    editor
 6357                        .available_code_actions
 6358                        .clone()
 6359                        .and_then(|(location, code_actions)| {
 6360                            let snapshot = location.buffer.read(cx).snapshot();
 6361                            let point_range = location.range.to_point(&snapshot);
 6362                            let point_range = point_range.start.row..=point_range.end.row;
 6363                            if point_range.contains(&buffer_row) {
 6364                                Some(code_actions)
 6365                            } else {
 6366                                None
 6367                            }
 6368                        })
 6369                })
 6370                .ok()
 6371                .flatten()
 6372        })
 6373    }
 6374
 6375    pub fn confirm_code_action(
 6376        &mut self,
 6377        action: &ConfirmCodeAction,
 6378        window: &mut Window,
 6379        cx: &mut Context<Self>,
 6380    ) -> Option<Task<Result<()>>> {
 6381        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6382
 6383        let actions_menu =
 6384            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6385                menu
 6386            } else {
 6387                return None;
 6388            };
 6389
 6390        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6391        let action = actions_menu.actions.get(action_ix)?;
 6392        let title = action.label();
 6393        let buffer = actions_menu.buffer;
 6394        let workspace = self.workspace()?;
 6395
 6396        match action {
 6397            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6398                workspace.update(cx, |workspace, cx| {
 6399                    workspace.schedule_resolved_task(
 6400                        task_source_kind,
 6401                        resolved_task,
 6402                        false,
 6403                        window,
 6404                        cx,
 6405                    );
 6406
 6407                    Some(Task::ready(Ok(())))
 6408                })
 6409            }
 6410            CodeActionsItem::CodeAction {
 6411                excerpt_id,
 6412                action,
 6413                provider,
 6414            } => {
 6415                let apply_code_action =
 6416                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6417                let workspace = workspace.downgrade();
 6418                Some(cx.spawn_in(window, async move |editor, cx| {
 6419                    let project_transaction = apply_code_action.await?;
 6420                    Self::open_project_transaction(
 6421                        &editor,
 6422                        workspace,
 6423                        project_transaction,
 6424                        title,
 6425                        cx,
 6426                    )
 6427                    .await
 6428                }))
 6429            }
 6430            CodeActionsItem::DebugScenario(scenario) => {
 6431                let context = actions_menu.actions.context;
 6432
 6433                workspace.update(cx, |workspace, cx| {
 6434                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6435                    workspace.start_debug_session(
 6436                        scenario,
 6437                        context,
 6438                        Some(buffer),
 6439                        None,
 6440                        window,
 6441                        cx,
 6442                    );
 6443                });
 6444                Some(Task::ready(Ok(())))
 6445            }
 6446        }
 6447    }
 6448
 6449    pub async fn open_project_transaction(
 6450        editor: &WeakEntity<Editor>,
 6451        workspace: WeakEntity<Workspace>,
 6452        transaction: ProjectTransaction,
 6453        title: String,
 6454        cx: &mut AsyncWindowContext,
 6455    ) -> Result<()> {
 6456        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6457        cx.update(|_, cx| {
 6458            entries.sort_unstable_by_key(|(buffer, _)| {
 6459                buffer.read(cx).file().map(|f| f.path().clone())
 6460            });
 6461        })?;
 6462        if entries.is_empty() {
 6463            return Ok(());
 6464        }
 6465
 6466        // If the project transaction's edits are all contained within this editor, then
 6467        // avoid opening a new editor to display them.
 6468
 6469        if let [(buffer, transaction)] = &*entries {
 6470            let excerpt = editor.update(cx, |editor, cx| {
 6471                editor
 6472                    .buffer()
 6473                    .read(cx)
 6474                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6475            })?;
 6476            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6477                && excerpted_buffer == *buffer
 6478            {
 6479                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6480                    let excerpt_range = excerpt_range.to_offset(buffer);
 6481                    buffer
 6482                        .edited_ranges_for_transaction::<usize>(transaction)
 6483                        .all(|range| {
 6484                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6485                        })
 6486                })?;
 6487
 6488                if all_edits_within_excerpt {
 6489                    return Ok(());
 6490                }
 6491            }
 6492        }
 6493
 6494        let mut ranges_to_highlight = Vec::new();
 6495        let excerpt_buffer = cx.new(|cx| {
 6496            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6497            for (buffer_handle, transaction) in &entries {
 6498                let edited_ranges = buffer_handle
 6499                    .read(cx)
 6500                    .edited_ranges_for_transaction::<Point>(transaction)
 6501                    .collect::<Vec<_>>();
 6502                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6503                    PathKey::for_buffer(buffer_handle, cx),
 6504                    buffer_handle.clone(),
 6505                    edited_ranges,
 6506                    multibuffer_context_lines(cx),
 6507                    cx,
 6508                );
 6509
 6510                ranges_to_highlight.extend(ranges);
 6511            }
 6512            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6513            multibuffer
 6514        })?;
 6515
 6516        workspace.update_in(cx, |workspace, window, cx| {
 6517            let project = workspace.project().clone();
 6518            let editor =
 6519                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6520            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6521            editor.update(cx, |editor, cx| {
 6522                editor.highlight_background::<Self>(
 6523                    &ranges_to_highlight,
 6524                    |theme| theme.colors().editor_highlighted_line_background,
 6525                    cx,
 6526                );
 6527            });
 6528        })?;
 6529
 6530        Ok(())
 6531    }
 6532
 6533    pub fn clear_code_action_providers(&mut self) {
 6534        self.code_action_providers.clear();
 6535        self.available_code_actions.take();
 6536    }
 6537
 6538    pub fn add_code_action_provider(
 6539        &mut self,
 6540        provider: Rc<dyn CodeActionProvider>,
 6541        window: &mut Window,
 6542        cx: &mut Context<Self>,
 6543    ) {
 6544        if self
 6545            .code_action_providers
 6546            .iter()
 6547            .any(|existing_provider| existing_provider.id() == provider.id())
 6548        {
 6549            return;
 6550        }
 6551
 6552        self.code_action_providers.push(provider);
 6553        self.refresh_code_actions(window, cx);
 6554    }
 6555
 6556    pub fn remove_code_action_provider(
 6557        &mut self,
 6558        id: Arc<str>,
 6559        window: &mut Window,
 6560        cx: &mut Context<Self>,
 6561    ) {
 6562        self.code_action_providers
 6563            .retain(|provider| provider.id() != id);
 6564        self.refresh_code_actions(window, cx);
 6565    }
 6566
 6567    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6568        !self.code_action_providers.is_empty()
 6569            && EditorSettings::get_global(cx).toolbar.code_actions
 6570    }
 6571
 6572    pub fn has_available_code_actions(&self) -> bool {
 6573        self.available_code_actions
 6574            .as_ref()
 6575            .is_some_and(|(_, actions)| !actions.is_empty())
 6576    }
 6577
 6578    fn render_inline_code_actions(
 6579        &self,
 6580        icon_size: ui::IconSize,
 6581        display_row: DisplayRow,
 6582        is_active: bool,
 6583        cx: &mut Context<Self>,
 6584    ) -> AnyElement {
 6585        let show_tooltip = !self.context_menu_visible();
 6586        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6587            .icon_size(icon_size)
 6588            .shape(ui::IconButtonShape::Square)
 6589            .icon_color(ui::Color::Hidden)
 6590            .toggle_state(is_active)
 6591            .when(show_tooltip, |this| {
 6592                this.tooltip({
 6593                    let focus_handle = self.focus_handle.clone();
 6594                    move |_window, cx| {
 6595                        Tooltip::for_action_in(
 6596                            "Toggle Code Actions",
 6597                            &ToggleCodeActions {
 6598                                deployed_from: None,
 6599                                quick_launch: false,
 6600                            },
 6601                            &focus_handle,
 6602                            cx,
 6603                        )
 6604                    }
 6605                })
 6606            })
 6607            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6608                window.focus(&editor.focus_handle(cx));
 6609                editor.toggle_code_actions(
 6610                    &crate::actions::ToggleCodeActions {
 6611                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6612                            display_row,
 6613                        )),
 6614                        quick_launch: false,
 6615                    },
 6616                    window,
 6617                    cx,
 6618                );
 6619            }))
 6620            .into_any_element()
 6621    }
 6622
 6623    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6624        &self.context_menu
 6625    }
 6626
 6627    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6628        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6629            cx.background_executor()
 6630                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6631                .await;
 6632
 6633            let (start_buffer, start, _, end, newest_selection) = this
 6634                .update(cx, |this, cx| {
 6635                    let newest_selection = this.selections.newest_anchor().clone();
 6636                    if newest_selection.head().diff_base_anchor.is_some() {
 6637                        return None;
 6638                    }
 6639                    let display_snapshot = this.display_snapshot(cx);
 6640                    let newest_selection_adjusted =
 6641                        this.selections.newest_adjusted(&display_snapshot);
 6642                    let buffer = this.buffer.read(cx);
 6643
 6644                    let (start_buffer, start) =
 6645                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6646                    let (end_buffer, end) =
 6647                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6648
 6649                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6650                })?
 6651                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6652                .context(
 6653                    "Expected selection to lie in a single buffer when refreshing code actions",
 6654                )?;
 6655            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6656                let providers = this.code_action_providers.clone();
 6657                let tasks = this
 6658                    .code_action_providers
 6659                    .iter()
 6660                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6661                    .collect::<Vec<_>>();
 6662                (providers, tasks)
 6663            })?;
 6664
 6665            let mut actions = Vec::new();
 6666            for (provider, provider_actions) in
 6667                providers.into_iter().zip(future::join_all(tasks).await)
 6668            {
 6669                if let Some(provider_actions) = provider_actions.log_err() {
 6670                    actions.extend(provider_actions.into_iter().map(|action| {
 6671                        AvailableCodeAction {
 6672                            excerpt_id: newest_selection.start.excerpt_id,
 6673                            action,
 6674                            provider: provider.clone(),
 6675                        }
 6676                    }));
 6677                }
 6678            }
 6679
 6680            this.update(cx, |this, cx| {
 6681                this.available_code_actions = if actions.is_empty() {
 6682                    None
 6683                } else {
 6684                    Some((
 6685                        Location {
 6686                            buffer: start_buffer,
 6687                            range: start..end,
 6688                        },
 6689                        actions.into(),
 6690                    ))
 6691                };
 6692                cx.notify();
 6693            })
 6694        }));
 6695    }
 6696
 6697    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6698        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6699            self.show_git_blame_inline = false;
 6700
 6701            self.show_git_blame_inline_delay_task =
 6702                Some(cx.spawn_in(window, async move |this, cx| {
 6703                    cx.background_executor().timer(delay).await;
 6704
 6705                    this.update(cx, |this, cx| {
 6706                        this.show_git_blame_inline = true;
 6707                        cx.notify();
 6708                    })
 6709                    .log_err();
 6710                }));
 6711        }
 6712    }
 6713
 6714    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6715        let snapshot = self.snapshot(window, cx);
 6716        let cursor = self
 6717            .selections
 6718            .newest::<Point>(&snapshot.display_snapshot)
 6719            .head();
 6720        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6721        else {
 6722            return;
 6723        };
 6724
 6725        let Some(blame) = self.blame.as_ref() else {
 6726            return;
 6727        };
 6728
 6729        let row_info = RowInfo {
 6730            buffer_id: Some(buffer.remote_id()),
 6731            buffer_row: Some(point.row),
 6732            ..Default::default()
 6733        };
 6734        let Some((buffer, blame_entry)) = blame
 6735            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6736            .flatten()
 6737        else {
 6738            return;
 6739        };
 6740
 6741        let anchor = self.selections.newest_anchor().head();
 6742        let position = self.to_pixel_point(anchor, &snapshot, window);
 6743        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6744            self.show_blame_popover(
 6745                buffer,
 6746                &blame_entry,
 6747                position + last_bounds.origin,
 6748                true,
 6749                cx,
 6750            );
 6751        };
 6752    }
 6753
 6754    fn show_blame_popover(
 6755        &mut self,
 6756        buffer: BufferId,
 6757        blame_entry: &BlameEntry,
 6758        position: gpui::Point<Pixels>,
 6759        ignore_timeout: bool,
 6760        cx: &mut Context<Self>,
 6761    ) {
 6762        if let Some(state) = &mut self.inline_blame_popover {
 6763            state.hide_task.take();
 6764        } else {
 6765            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6766            let blame_entry = blame_entry.clone();
 6767            let show_task = cx.spawn(async move |editor, cx| {
 6768                if !ignore_timeout {
 6769                    cx.background_executor()
 6770                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6771                        .await;
 6772                }
 6773                editor
 6774                    .update(cx, |editor, cx| {
 6775                        editor.inline_blame_popover_show_task.take();
 6776                        let Some(blame) = editor.blame.as_ref() else {
 6777                            return;
 6778                        };
 6779                        let blame = blame.read(cx);
 6780                        let details = blame.details_for_entry(buffer, &blame_entry);
 6781                        let markdown = cx.new(|cx| {
 6782                            Markdown::new(
 6783                                details
 6784                                    .as_ref()
 6785                                    .map(|message| message.message.clone())
 6786                                    .unwrap_or_default(),
 6787                                None,
 6788                                None,
 6789                                cx,
 6790                            )
 6791                        });
 6792                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6793                            position,
 6794                            hide_task: None,
 6795                            popover_bounds: None,
 6796                            popover_state: InlineBlamePopoverState {
 6797                                scroll_handle: ScrollHandle::new(),
 6798                                commit_message: details,
 6799                                markdown,
 6800                            },
 6801                            keyboard_grace: ignore_timeout,
 6802                        });
 6803                        cx.notify();
 6804                    })
 6805                    .ok();
 6806            });
 6807            self.inline_blame_popover_show_task = Some(show_task);
 6808        }
 6809    }
 6810
 6811    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6812        self.inline_blame_popover_show_task.take();
 6813        if let Some(state) = &mut self.inline_blame_popover {
 6814            let hide_task = cx.spawn(async move |editor, cx| {
 6815                if !ignore_timeout {
 6816                    cx.background_executor()
 6817                        .timer(std::time::Duration::from_millis(100))
 6818                        .await;
 6819                }
 6820                editor
 6821                    .update(cx, |editor, cx| {
 6822                        editor.inline_blame_popover.take();
 6823                        cx.notify();
 6824                    })
 6825                    .ok();
 6826            });
 6827            state.hide_task = Some(hide_task);
 6828            true
 6829        } else {
 6830            false
 6831        }
 6832    }
 6833
 6834    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6835        if self.pending_rename.is_some() {
 6836            return None;
 6837        }
 6838
 6839        let provider = self.semantics_provider.clone()?;
 6840        let buffer = self.buffer.read(cx);
 6841        let newest_selection = self.selections.newest_anchor().clone();
 6842        let cursor_position = newest_selection.head();
 6843        let (cursor_buffer, cursor_buffer_position) =
 6844            buffer.text_anchor_for_position(cursor_position, cx)?;
 6845        let (tail_buffer, tail_buffer_position) =
 6846            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6847        if cursor_buffer != tail_buffer {
 6848            return None;
 6849        }
 6850
 6851        let snapshot = cursor_buffer.read(cx).snapshot();
 6852        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6853        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6854        if start_word_range != end_word_range {
 6855            self.document_highlights_task.take();
 6856            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6857            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6858            return None;
 6859        }
 6860
 6861        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6862        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6863            cx.background_executor()
 6864                .timer(Duration::from_millis(debounce))
 6865                .await;
 6866
 6867            let highlights = if let Some(highlights) = cx
 6868                .update(|cx| {
 6869                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6870                })
 6871                .ok()
 6872                .flatten()
 6873            {
 6874                highlights.await.log_err()
 6875            } else {
 6876                None
 6877            };
 6878
 6879            if let Some(highlights) = highlights {
 6880                this.update(cx, |this, cx| {
 6881                    if this.pending_rename.is_some() {
 6882                        return;
 6883                    }
 6884
 6885                    let buffer = this.buffer.read(cx);
 6886                    if buffer
 6887                        .text_anchor_for_position(cursor_position, cx)
 6888                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6889                    {
 6890                        return;
 6891                    }
 6892
 6893                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6894                    let mut write_ranges = Vec::new();
 6895                    let mut read_ranges = Vec::new();
 6896                    for highlight in highlights {
 6897                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6898                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6899                        {
 6900                            let start = highlight
 6901                                .range
 6902                                .start
 6903                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6904                            let end = highlight
 6905                                .range
 6906                                .end
 6907                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6908                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6909                                continue;
 6910                            }
 6911
 6912                            let range =
 6913                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6914                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6915                                write_ranges.push(range);
 6916                            } else {
 6917                                read_ranges.push(range);
 6918                            }
 6919                        }
 6920                    }
 6921
 6922                    this.highlight_background::<DocumentHighlightRead>(
 6923                        &read_ranges,
 6924                        |theme| theme.colors().editor_document_highlight_read_background,
 6925                        cx,
 6926                    );
 6927                    this.highlight_background::<DocumentHighlightWrite>(
 6928                        &write_ranges,
 6929                        |theme| theme.colors().editor_document_highlight_write_background,
 6930                        cx,
 6931                    );
 6932                    cx.notify();
 6933                })
 6934                .log_err();
 6935            }
 6936        }));
 6937        None
 6938    }
 6939
 6940    fn prepare_highlight_query_from_selection(
 6941        &mut self,
 6942        window: &Window,
 6943        cx: &mut Context<Editor>,
 6944    ) -> Option<(String, Range<Anchor>)> {
 6945        if matches!(self.mode, EditorMode::SingleLine) {
 6946            return None;
 6947        }
 6948        if !EditorSettings::get_global(cx).selection_highlight {
 6949            return None;
 6950        }
 6951        if self.selections.count() != 1 || self.selections.line_mode() {
 6952            return None;
 6953        }
 6954        let snapshot = self.snapshot(window, cx);
 6955        let selection = self.selections.newest::<Point>(&snapshot);
 6956        // If the selection spans multiple rows OR it is empty
 6957        if selection.start.row != selection.end.row
 6958            || selection.start.column == selection.end.column
 6959        {
 6960            return None;
 6961        }
 6962        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6963        let query = snapshot
 6964            .buffer_snapshot()
 6965            .text_for_range(selection_anchor_range.clone())
 6966            .collect::<String>();
 6967        if query.trim().is_empty() {
 6968            return None;
 6969        }
 6970        Some((query, selection_anchor_range))
 6971    }
 6972
 6973    fn update_selection_occurrence_highlights(
 6974        &mut self,
 6975        query_text: String,
 6976        query_range: Range<Anchor>,
 6977        multi_buffer_range_to_query: Range<Point>,
 6978        use_debounce: bool,
 6979        window: &mut Window,
 6980        cx: &mut Context<Editor>,
 6981    ) -> Task<()> {
 6982        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6983        cx.spawn_in(window, async move |editor, cx| {
 6984            if use_debounce {
 6985                cx.background_executor()
 6986                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6987                    .await;
 6988            }
 6989            let match_task = cx.background_spawn(async move {
 6990                let buffer_ranges = multi_buffer_snapshot
 6991                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6992                    .into_iter()
 6993                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6994                let mut match_ranges = Vec::new();
 6995                let Ok(regex) = project::search::SearchQuery::text(
 6996                    query_text.clone(),
 6997                    false,
 6998                    false,
 6999                    false,
 7000                    Default::default(),
 7001                    Default::default(),
 7002                    false,
 7003                    None,
 7004                ) else {
 7005                    return Vec::default();
 7006                };
 7007                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7008                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7009                    match_ranges.extend(
 7010                        regex
 7011                            .search(buffer_snapshot, Some(search_range.clone()))
 7012                            .await
 7013                            .into_iter()
 7014                            .filter_map(|match_range| {
 7015                                let match_start = buffer_snapshot
 7016                                    .anchor_after(search_range.start + match_range.start);
 7017                                let match_end = buffer_snapshot
 7018                                    .anchor_before(search_range.start + match_range.end);
 7019                                let match_anchor_range = Anchor::range_in_buffer(
 7020                                    excerpt_id,
 7021                                    buffer_snapshot.remote_id(),
 7022                                    match_start..match_end,
 7023                                );
 7024                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7025                            }),
 7026                    );
 7027                }
 7028                match_ranges
 7029            });
 7030            let match_ranges = match_task.await;
 7031            editor
 7032                .update_in(cx, |editor, _, cx| {
 7033                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7034                    if !match_ranges.is_empty() {
 7035                        editor.highlight_background::<SelectedTextHighlight>(
 7036                            &match_ranges,
 7037                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7038                            cx,
 7039                        )
 7040                    }
 7041                })
 7042                .log_err();
 7043        })
 7044    }
 7045
 7046    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7047        struct NewlineFold;
 7048        let type_id = std::any::TypeId::of::<NewlineFold>();
 7049        if !self.mode.is_single_line() {
 7050            return;
 7051        }
 7052        let snapshot = self.snapshot(window, cx);
 7053        if snapshot.buffer_snapshot().max_point().row == 0 {
 7054            return;
 7055        }
 7056        let task = cx.background_spawn(async move {
 7057            let new_newlines = snapshot
 7058                .buffer_chars_at(0)
 7059                .filter_map(|(c, i)| {
 7060                    if c == '\n' {
 7061                        Some(
 7062                            snapshot.buffer_snapshot().anchor_after(i)
 7063                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7064                        )
 7065                    } else {
 7066                        None
 7067                    }
 7068                })
 7069                .collect::<Vec<_>>();
 7070            let existing_newlines = snapshot
 7071                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7072                .filter_map(|fold| {
 7073                    if fold.placeholder.type_tag == Some(type_id) {
 7074                        Some(fold.range.start..fold.range.end)
 7075                    } else {
 7076                        None
 7077                    }
 7078                })
 7079                .collect::<Vec<_>>();
 7080
 7081            (new_newlines, existing_newlines)
 7082        });
 7083        self.folding_newlines = cx.spawn(async move |this, cx| {
 7084            let (new_newlines, existing_newlines) = task.await;
 7085            if new_newlines == existing_newlines {
 7086                return;
 7087            }
 7088            let placeholder = FoldPlaceholder {
 7089                render: Arc::new(move |_, _, cx| {
 7090                    div()
 7091                        .bg(cx.theme().status().hint_background)
 7092                        .border_b_1()
 7093                        .size_full()
 7094                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7095                        .border_color(cx.theme().status().hint)
 7096                        .child("\\n")
 7097                        .into_any()
 7098                }),
 7099                constrain_width: false,
 7100                merge_adjacent: false,
 7101                type_tag: Some(type_id),
 7102            };
 7103            let creases = new_newlines
 7104                .into_iter()
 7105                .map(|range| Crease::simple(range, placeholder.clone()))
 7106                .collect();
 7107            this.update(cx, |this, cx| {
 7108                this.display_map.update(cx, |display_map, cx| {
 7109                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7110                    display_map.fold(creases, cx);
 7111                });
 7112            })
 7113            .ok();
 7114        });
 7115    }
 7116
 7117    fn refresh_selected_text_highlights(
 7118        &mut self,
 7119        on_buffer_edit: bool,
 7120        window: &mut Window,
 7121        cx: &mut Context<Editor>,
 7122    ) {
 7123        let Some((query_text, query_range)) =
 7124            self.prepare_highlight_query_from_selection(window, cx)
 7125        else {
 7126            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7127            self.quick_selection_highlight_task.take();
 7128            self.debounced_selection_highlight_task.take();
 7129            return;
 7130        };
 7131        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7132        if on_buffer_edit
 7133            || self
 7134                .quick_selection_highlight_task
 7135                .as_ref()
 7136                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7137        {
 7138            let multi_buffer_visible_start = self
 7139                .scroll_manager
 7140                .anchor()
 7141                .anchor
 7142                .to_point(&multi_buffer_snapshot);
 7143            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7144                multi_buffer_visible_start
 7145                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7146                Bias::Left,
 7147            );
 7148            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7149            self.quick_selection_highlight_task = Some((
 7150                query_range.clone(),
 7151                self.update_selection_occurrence_highlights(
 7152                    query_text.clone(),
 7153                    query_range.clone(),
 7154                    multi_buffer_visible_range,
 7155                    false,
 7156                    window,
 7157                    cx,
 7158                ),
 7159            ));
 7160        }
 7161        if on_buffer_edit
 7162            || self
 7163                .debounced_selection_highlight_task
 7164                .as_ref()
 7165                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7166        {
 7167            let multi_buffer_start = multi_buffer_snapshot
 7168                .anchor_before(0)
 7169                .to_point(&multi_buffer_snapshot);
 7170            let multi_buffer_end = multi_buffer_snapshot
 7171                .anchor_after(multi_buffer_snapshot.len())
 7172                .to_point(&multi_buffer_snapshot);
 7173            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7174            self.debounced_selection_highlight_task = Some((
 7175                query_range.clone(),
 7176                self.update_selection_occurrence_highlights(
 7177                    query_text,
 7178                    query_range,
 7179                    multi_buffer_full_range,
 7180                    true,
 7181                    window,
 7182                    cx,
 7183                ),
 7184            ));
 7185        }
 7186    }
 7187
 7188    pub fn refresh_edit_prediction(
 7189        &mut self,
 7190        debounce: bool,
 7191        user_requested: bool,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) -> Option<()> {
 7195        if DisableAiSettings::get_global(cx).disable_ai {
 7196            return None;
 7197        }
 7198
 7199        let provider = self.edit_prediction_provider()?;
 7200        let cursor = self.selections.newest_anchor().head();
 7201        let (buffer, cursor_buffer_position) =
 7202            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7203
 7204        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7205            self.discard_edit_prediction(false, cx);
 7206            return None;
 7207        }
 7208
 7209        self.update_visible_edit_prediction(window, cx);
 7210
 7211        if !user_requested
 7212            && (!self.should_show_edit_predictions()
 7213                || !self.is_focused(window)
 7214                || buffer.read(cx).is_empty())
 7215        {
 7216            self.discard_edit_prediction(false, cx);
 7217            return None;
 7218        }
 7219
 7220        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7221        Some(())
 7222    }
 7223
 7224    fn show_edit_predictions_in_menu(&self) -> bool {
 7225        match self.edit_prediction_settings {
 7226            EditPredictionSettings::Disabled => false,
 7227            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7228        }
 7229    }
 7230
 7231    pub fn edit_predictions_enabled(&self) -> bool {
 7232        match self.edit_prediction_settings {
 7233            EditPredictionSettings::Disabled => false,
 7234            EditPredictionSettings::Enabled { .. } => true,
 7235        }
 7236    }
 7237
 7238    fn edit_prediction_requires_modifier(&self) -> bool {
 7239        match self.edit_prediction_settings {
 7240            EditPredictionSettings::Disabled => false,
 7241            EditPredictionSettings::Enabled {
 7242                preview_requires_modifier,
 7243                ..
 7244            } => preview_requires_modifier,
 7245        }
 7246    }
 7247
 7248    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7249        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7250            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7251            self.discard_edit_prediction(false, cx);
 7252        } else {
 7253            let selection = self.selections.newest_anchor();
 7254            let cursor = selection.head();
 7255
 7256            if let Some((buffer, cursor_buffer_position)) =
 7257                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7258            {
 7259                self.edit_prediction_settings =
 7260                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7261            }
 7262        }
 7263    }
 7264
 7265    fn edit_prediction_settings_at_position(
 7266        &self,
 7267        buffer: &Entity<Buffer>,
 7268        buffer_position: language::Anchor,
 7269        cx: &App,
 7270    ) -> EditPredictionSettings {
 7271        if !self.mode.is_full()
 7272            || !self.show_edit_predictions_override.unwrap_or(true)
 7273            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7274        {
 7275            return EditPredictionSettings::Disabled;
 7276        }
 7277
 7278        let buffer = buffer.read(cx);
 7279
 7280        let file = buffer.file();
 7281
 7282        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7283            return EditPredictionSettings::Disabled;
 7284        };
 7285
 7286        let by_provider = matches!(
 7287            self.menu_edit_predictions_policy,
 7288            MenuEditPredictionsPolicy::ByProvider
 7289        );
 7290
 7291        let show_in_menu = by_provider
 7292            && self
 7293                .edit_prediction_provider
 7294                .as_ref()
 7295                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7296
 7297        let preview_requires_modifier =
 7298            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7299
 7300        EditPredictionSettings::Enabled {
 7301            show_in_menu,
 7302            preview_requires_modifier,
 7303        }
 7304    }
 7305
 7306    fn should_show_edit_predictions(&self) -> bool {
 7307        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7308    }
 7309
 7310    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7311        matches!(
 7312            self.edit_prediction_preview,
 7313            EditPredictionPreview::Active { .. }
 7314        )
 7315    }
 7316
 7317    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7318        let cursor = self.selections.newest_anchor().head();
 7319        if let Some((buffer, cursor_position)) =
 7320            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7321        {
 7322            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7323        } else {
 7324            false
 7325        }
 7326    }
 7327
 7328    pub fn supports_minimap(&self, cx: &App) -> bool {
 7329        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7330    }
 7331
 7332    fn edit_predictions_enabled_in_buffer(
 7333        &self,
 7334        buffer: &Entity<Buffer>,
 7335        buffer_position: language::Anchor,
 7336        cx: &App,
 7337    ) -> bool {
 7338        maybe!({
 7339            if self.read_only(cx) {
 7340                return Some(false);
 7341            }
 7342            let provider = self.edit_prediction_provider()?;
 7343            if !provider.is_enabled(buffer, buffer_position, cx) {
 7344                return Some(false);
 7345            }
 7346            let buffer = buffer.read(cx);
 7347            let Some(file) = buffer.file() else {
 7348                return Some(true);
 7349            };
 7350            let settings = all_language_settings(Some(file), cx);
 7351            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7352        })
 7353        .unwrap_or(false)
 7354    }
 7355
 7356    fn cycle_edit_prediction(
 7357        &mut self,
 7358        direction: Direction,
 7359        window: &mut Window,
 7360        cx: &mut Context<Self>,
 7361    ) -> Option<()> {
 7362        let provider = self.edit_prediction_provider()?;
 7363        let cursor = self.selections.newest_anchor().head();
 7364        let (buffer, cursor_buffer_position) =
 7365            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7366        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7367            return None;
 7368        }
 7369
 7370        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7371        self.update_visible_edit_prediction(window, cx);
 7372
 7373        Some(())
 7374    }
 7375
 7376    pub fn show_edit_prediction(
 7377        &mut self,
 7378        _: &ShowEditPrediction,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) {
 7382        if !self.has_active_edit_prediction() {
 7383            self.refresh_edit_prediction(false, true, window, cx);
 7384            return;
 7385        }
 7386
 7387        self.update_visible_edit_prediction(window, cx);
 7388    }
 7389
 7390    pub fn display_cursor_names(
 7391        &mut self,
 7392        _: &DisplayCursorNames,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) {
 7396        self.show_cursor_names(window, cx);
 7397    }
 7398
 7399    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7400        self.show_cursor_names = true;
 7401        cx.notify();
 7402        cx.spawn_in(window, async move |this, cx| {
 7403            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7404            this.update(cx, |this, cx| {
 7405                this.show_cursor_names = false;
 7406                cx.notify()
 7407            })
 7408            .ok()
 7409        })
 7410        .detach();
 7411    }
 7412
 7413    pub fn next_edit_prediction(
 7414        &mut self,
 7415        _: &NextEditPrediction,
 7416        window: &mut Window,
 7417        cx: &mut Context<Self>,
 7418    ) {
 7419        if self.has_active_edit_prediction() {
 7420            self.cycle_edit_prediction(Direction::Next, window, cx);
 7421        } else {
 7422            let is_copilot_disabled = self
 7423                .refresh_edit_prediction(false, true, window, cx)
 7424                .is_none();
 7425            if is_copilot_disabled {
 7426                cx.propagate();
 7427            }
 7428        }
 7429    }
 7430
 7431    pub fn previous_edit_prediction(
 7432        &mut self,
 7433        _: &PreviousEditPrediction,
 7434        window: &mut Window,
 7435        cx: &mut Context<Self>,
 7436    ) {
 7437        if self.has_active_edit_prediction() {
 7438            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7439        } else {
 7440            let is_copilot_disabled = self
 7441                .refresh_edit_prediction(false, true, window, cx)
 7442                .is_none();
 7443            if is_copilot_disabled {
 7444                cx.propagate();
 7445            }
 7446        }
 7447    }
 7448
 7449    pub fn accept_edit_prediction(
 7450        &mut self,
 7451        _: &AcceptEditPrediction,
 7452        window: &mut Window,
 7453        cx: &mut Context<Self>,
 7454    ) {
 7455        if self.show_edit_predictions_in_menu() {
 7456            self.hide_context_menu(window, cx);
 7457        }
 7458
 7459        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7460            return;
 7461        };
 7462
 7463        match &active_edit_prediction.completion {
 7464            EditPrediction::MoveWithin { target, .. } => {
 7465                let target = *target;
 7466
 7467                if let Some(position_map) = &self.last_position_map {
 7468                    if position_map
 7469                        .visible_row_range
 7470                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7471                        || !self.edit_prediction_requires_modifier()
 7472                    {
 7473                        self.unfold_ranges(&[target..target], true, false, cx);
 7474                        // Note that this is also done in vim's handler of the Tab action.
 7475                        self.change_selections(
 7476                            SelectionEffects::scroll(Autoscroll::newest()),
 7477                            window,
 7478                            cx,
 7479                            |selections| {
 7480                                selections.select_anchor_ranges([target..target]);
 7481                            },
 7482                        );
 7483                        self.clear_row_highlights::<EditPredictionPreview>();
 7484
 7485                        self.edit_prediction_preview
 7486                            .set_previous_scroll_position(None);
 7487                    } else {
 7488                        self.edit_prediction_preview
 7489                            .set_previous_scroll_position(Some(
 7490                                position_map.snapshot.scroll_anchor,
 7491                            ));
 7492
 7493                        self.highlight_rows::<EditPredictionPreview>(
 7494                            target..target,
 7495                            cx.theme().colors().editor_highlighted_line_background,
 7496                            RowHighlightOptions {
 7497                                autoscroll: true,
 7498                                ..Default::default()
 7499                            },
 7500                            cx,
 7501                        );
 7502                        self.request_autoscroll(Autoscroll::fit(), cx);
 7503                    }
 7504                }
 7505            }
 7506            EditPrediction::MoveOutside { snapshot, target } => {
 7507                if let Some(workspace) = self.workspace() {
 7508                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7509                        .detach_and_log_err(cx);
 7510                }
 7511            }
 7512            EditPrediction::Edit { edits, .. } => {
 7513                self.report_edit_prediction_event(
 7514                    active_edit_prediction.completion_id.clone(),
 7515                    true,
 7516                    cx,
 7517                );
 7518
 7519                if let Some(provider) = self.edit_prediction_provider() {
 7520                    provider.accept(cx);
 7521                }
 7522
 7523                // Store the transaction ID and selections before applying the edit
 7524                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7525
 7526                let snapshot = self.buffer.read(cx).snapshot(cx);
 7527                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7528
 7529                self.buffer.update(cx, |buffer, cx| {
 7530                    buffer.edit(edits.iter().cloned(), None, cx)
 7531                });
 7532
 7533                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7534                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7535                });
 7536
 7537                let selections = self.selections.disjoint_anchors_arc();
 7538                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7539                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7540                    if has_new_transaction {
 7541                        self.selection_history
 7542                            .insert_transaction(transaction_id_now, selections);
 7543                    }
 7544                }
 7545
 7546                self.update_visible_edit_prediction(window, cx);
 7547                if self.active_edit_prediction.is_none() {
 7548                    self.refresh_edit_prediction(true, true, window, cx);
 7549                }
 7550
 7551                cx.notify();
 7552            }
 7553        }
 7554
 7555        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7556    }
 7557
 7558    pub fn accept_partial_edit_prediction(
 7559        &mut self,
 7560        _: &AcceptPartialEditPrediction,
 7561        window: &mut Window,
 7562        cx: &mut Context<Self>,
 7563    ) {
 7564        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7565            return;
 7566        };
 7567        if self.selections.count() != 1 {
 7568            return;
 7569        }
 7570
 7571        match &active_edit_prediction.completion {
 7572            EditPrediction::MoveWithin { target, .. } => {
 7573                let target = *target;
 7574                self.change_selections(
 7575                    SelectionEffects::scroll(Autoscroll::newest()),
 7576                    window,
 7577                    cx,
 7578                    |selections| {
 7579                        selections.select_anchor_ranges([target..target]);
 7580                    },
 7581                );
 7582            }
 7583            EditPrediction::MoveOutside { snapshot, target } => {
 7584                if let Some(workspace) = self.workspace() {
 7585                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7586                        .detach_and_log_err(cx);
 7587                }
 7588            }
 7589            EditPrediction::Edit { edits, .. } => {
 7590                self.report_edit_prediction_event(
 7591                    active_edit_prediction.completion_id.clone(),
 7592                    true,
 7593                    cx,
 7594                );
 7595
 7596                // Find an insertion that starts at the cursor position.
 7597                let snapshot = self.buffer.read(cx).snapshot(cx);
 7598                let cursor_offset = self
 7599                    .selections
 7600                    .newest::<usize>(&self.display_snapshot(cx))
 7601                    .head();
 7602                let insertion = edits.iter().find_map(|(range, text)| {
 7603                    let range = range.to_offset(&snapshot);
 7604                    if range.is_empty() && range.start == cursor_offset {
 7605                        Some(text)
 7606                    } else {
 7607                        None
 7608                    }
 7609                });
 7610
 7611                if let Some(text) = insertion {
 7612                    let mut partial_completion = text
 7613                        .chars()
 7614                        .by_ref()
 7615                        .take_while(|c| c.is_alphabetic())
 7616                        .collect::<String>();
 7617                    if partial_completion.is_empty() {
 7618                        partial_completion = text
 7619                            .chars()
 7620                            .by_ref()
 7621                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7622                            .collect::<String>();
 7623                    }
 7624
 7625                    cx.emit(EditorEvent::InputHandled {
 7626                        utf16_range_to_replace: None,
 7627                        text: partial_completion.clone().into(),
 7628                    });
 7629
 7630                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7631
 7632                    self.refresh_edit_prediction(true, true, window, cx);
 7633                    cx.notify();
 7634                } else {
 7635                    self.accept_edit_prediction(&Default::default(), window, cx);
 7636                }
 7637            }
 7638        }
 7639    }
 7640
 7641    fn discard_edit_prediction(
 7642        &mut self,
 7643        should_report_edit_prediction_event: bool,
 7644        cx: &mut Context<Self>,
 7645    ) -> bool {
 7646        if should_report_edit_prediction_event {
 7647            let completion_id = self
 7648                .active_edit_prediction
 7649                .as_ref()
 7650                .and_then(|active_completion| active_completion.completion_id.clone());
 7651
 7652            self.report_edit_prediction_event(completion_id, false, cx);
 7653        }
 7654
 7655        if let Some(provider) = self.edit_prediction_provider() {
 7656            provider.discard(cx);
 7657        }
 7658
 7659        self.take_active_edit_prediction(cx)
 7660    }
 7661
 7662    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7663        let Some(provider) = self.edit_prediction_provider() else {
 7664            return;
 7665        };
 7666
 7667        let Some((_, buffer, _)) = self
 7668            .buffer
 7669            .read(cx)
 7670            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7671        else {
 7672            return;
 7673        };
 7674
 7675        let extension = buffer
 7676            .read(cx)
 7677            .file()
 7678            .and_then(|file| Some(file.path().extension()?.to_string()));
 7679
 7680        let event_type = match accepted {
 7681            true => "Edit Prediction Accepted",
 7682            false => "Edit Prediction Discarded",
 7683        };
 7684        telemetry::event!(
 7685            event_type,
 7686            provider = provider.name(),
 7687            prediction_id = id,
 7688            suggestion_accepted = accepted,
 7689            file_extension = extension,
 7690        );
 7691    }
 7692
 7693    fn open_editor_at_anchor(
 7694        snapshot: &language::BufferSnapshot,
 7695        target: language::Anchor,
 7696        workspace: &Entity<Workspace>,
 7697        window: &mut Window,
 7698        cx: &mut App,
 7699    ) -> Task<Result<()>> {
 7700        workspace.update(cx, |workspace, cx| {
 7701            let path = snapshot.file().map(|file| file.full_path(cx));
 7702            let Some(path) =
 7703                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7704            else {
 7705                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7706            };
 7707            let target = text::ToPoint::to_point(&target, snapshot);
 7708            let item = workspace.open_path(path, None, true, window, cx);
 7709            window.spawn(cx, async move |cx| {
 7710                let Some(editor) = item.await?.downcast::<Editor>() else {
 7711                    return Ok(());
 7712                };
 7713                editor
 7714                    .update_in(cx, |editor, window, cx| {
 7715                        editor.go_to_singleton_buffer_point(target, window, cx);
 7716                    })
 7717                    .ok();
 7718                anyhow::Ok(())
 7719            })
 7720        })
 7721    }
 7722
 7723    pub fn has_active_edit_prediction(&self) -> bool {
 7724        self.active_edit_prediction.is_some()
 7725    }
 7726
 7727    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7728        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7729            return false;
 7730        };
 7731
 7732        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7733        self.clear_highlights::<EditPredictionHighlight>(cx);
 7734        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7735        true
 7736    }
 7737
 7738    /// Returns true when we're displaying the edit prediction popover below the cursor
 7739    /// like we are not previewing and the LSP autocomplete menu is visible
 7740    /// or we are in `when_holding_modifier` mode.
 7741    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7742        if self.edit_prediction_preview_is_active()
 7743            || !self.show_edit_predictions_in_menu()
 7744            || !self.edit_predictions_enabled()
 7745        {
 7746            return false;
 7747        }
 7748
 7749        if self.has_visible_completions_menu() {
 7750            return true;
 7751        }
 7752
 7753        has_completion && self.edit_prediction_requires_modifier()
 7754    }
 7755
 7756    fn handle_modifiers_changed(
 7757        &mut self,
 7758        modifiers: Modifiers,
 7759        position_map: &PositionMap,
 7760        window: &mut Window,
 7761        cx: &mut Context<Self>,
 7762    ) {
 7763        // Ensure that the edit prediction preview is updated, even when not
 7764        // enabled, if there's an active edit prediction preview.
 7765        if self.show_edit_predictions_in_menu()
 7766            || matches!(
 7767                self.edit_prediction_preview,
 7768                EditPredictionPreview::Active { .. }
 7769            )
 7770        {
 7771            self.update_edit_prediction_preview(&modifiers, window, cx);
 7772        }
 7773
 7774        self.update_selection_mode(&modifiers, position_map, window, cx);
 7775
 7776        let mouse_position = window.mouse_position();
 7777        if !position_map.text_hitbox.is_hovered(window) {
 7778            return;
 7779        }
 7780
 7781        self.update_hovered_link(
 7782            position_map.point_for_position(mouse_position),
 7783            &position_map.snapshot,
 7784            modifiers,
 7785            window,
 7786            cx,
 7787        )
 7788    }
 7789
 7790    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7791        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7792            MultiCursorModifier::Alt => modifiers.secondary(),
 7793            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7794        }
 7795    }
 7796
 7797    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7798        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7799            MultiCursorModifier::Alt => modifiers.alt,
 7800            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7801        }
 7802    }
 7803
 7804    fn columnar_selection_mode(
 7805        modifiers: &Modifiers,
 7806        cx: &mut Context<Self>,
 7807    ) -> Option<ColumnarMode> {
 7808        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7809            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7810                Some(ColumnarMode::FromMouse)
 7811            } else if Self::is_alt_pressed(modifiers, cx) {
 7812                Some(ColumnarMode::FromSelection)
 7813            } else {
 7814                None
 7815            }
 7816        } else {
 7817            None
 7818        }
 7819    }
 7820
 7821    fn update_selection_mode(
 7822        &mut self,
 7823        modifiers: &Modifiers,
 7824        position_map: &PositionMap,
 7825        window: &mut Window,
 7826        cx: &mut Context<Self>,
 7827    ) {
 7828        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7829            return;
 7830        };
 7831        if self.selections.pending_anchor().is_none() {
 7832            return;
 7833        }
 7834
 7835        let mouse_position = window.mouse_position();
 7836        let point_for_position = position_map.point_for_position(mouse_position);
 7837        let position = point_for_position.previous_valid;
 7838
 7839        self.select(
 7840            SelectPhase::BeginColumnar {
 7841                position,
 7842                reset: false,
 7843                mode,
 7844                goal_column: point_for_position.exact_unclipped.column(),
 7845            },
 7846            window,
 7847            cx,
 7848        );
 7849    }
 7850
 7851    fn update_edit_prediction_preview(
 7852        &mut self,
 7853        modifiers: &Modifiers,
 7854        window: &mut Window,
 7855        cx: &mut Context<Self>,
 7856    ) {
 7857        let mut modifiers_held = false;
 7858        if let Some(accept_keystroke) = self
 7859            .accept_edit_prediction_keybind(false, window, cx)
 7860            .keystroke()
 7861        {
 7862            modifiers_held = modifiers_held
 7863                || (accept_keystroke.modifiers() == modifiers
 7864                    && accept_keystroke.modifiers().modified());
 7865        };
 7866        if let Some(accept_partial_keystroke) = self
 7867            .accept_edit_prediction_keybind(true, window, cx)
 7868            .keystroke()
 7869        {
 7870            modifiers_held = modifiers_held
 7871                || (accept_partial_keystroke.modifiers() == modifiers
 7872                    && accept_partial_keystroke.modifiers().modified());
 7873        }
 7874
 7875        if modifiers_held {
 7876            if matches!(
 7877                self.edit_prediction_preview,
 7878                EditPredictionPreview::Inactive { .. }
 7879            ) {
 7880                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7881                    provider.provider.did_show(cx)
 7882                }
 7883
 7884                self.edit_prediction_preview = EditPredictionPreview::Active {
 7885                    previous_scroll_position: None,
 7886                    since: Instant::now(),
 7887                };
 7888
 7889                self.update_visible_edit_prediction(window, cx);
 7890                cx.notify();
 7891            }
 7892        } else if let EditPredictionPreview::Active {
 7893            previous_scroll_position,
 7894            since,
 7895        } = self.edit_prediction_preview
 7896        {
 7897            if let (Some(previous_scroll_position), Some(position_map)) =
 7898                (previous_scroll_position, self.last_position_map.as_ref())
 7899            {
 7900                self.set_scroll_position(
 7901                    previous_scroll_position
 7902                        .scroll_position(&position_map.snapshot.display_snapshot),
 7903                    window,
 7904                    cx,
 7905                );
 7906            }
 7907
 7908            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7909                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7910            };
 7911            self.clear_row_highlights::<EditPredictionPreview>();
 7912            self.update_visible_edit_prediction(window, cx);
 7913            cx.notify();
 7914        }
 7915    }
 7916
 7917    fn update_visible_edit_prediction(
 7918        &mut self,
 7919        _window: &mut Window,
 7920        cx: &mut Context<Self>,
 7921    ) -> Option<()> {
 7922        if DisableAiSettings::get_global(cx).disable_ai {
 7923            return None;
 7924        }
 7925
 7926        if self.ime_transaction.is_some() {
 7927            self.discard_edit_prediction(false, cx);
 7928            return None;
 7929        }
 7930
 7931        let selection = self.selections.newest_anchor();
 7932        let cursor = selection.head();
 7933        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7934        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7935        let excerpt_id = cursor.excerpt_id;
 7936
 7937        let show_in_menu = self.show_edit_predictions_in_menu();
 7938        let completions_menu_has_precedence = !show_in_menu
 7939            && (self.context_menu.borrow().is_some()
 7940                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7941
 7942        if completions_menu_has_precedence
 7943            || !offset_selection.is_empty()
 7944            || self
 7945                .active_edit_prediction
 7946                .as_ref()
 7947                .is_some_and(|completion| {
 7948                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7949                        return false;
 7950                    };
 7951                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7952                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7953                    !invalidation_range.contains(&offset_selection.head())
 7954                })
 7955        {
 7956            self.discard_edit_prediction(false, cx);
 7957            return None;
 7958        }
 7959
 7960        self.take_active_edit_prediction(cx);
 7961        let Some(provider) = self.edit_prediction_provider() else {
 7962            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7963            return None;
 7964        };
 7965
 7966        let (buffer, cursor_buffer_position) =
 7967            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7968
 7969        self.edit_prediction_settings =
 7970            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7971
 7972        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7973
 7974        if self.edit_prediction_indent_conflict {
 7975            let cursor_point = cursor.to_point(&multibuffer);
 7976
 7977            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7978
 7979            if let Some((_, indent)) = indents.iter().next()
 7980                && indent.len == cursor_point.column
 7981            {
 7982                self.edit_prediction_indent_conflict = false;
 7983            }
 7984        }
 7985
 7986        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7987
 7988        let (completion_id, edits, edit_preview) = match edit_prediction {
 7989            edit_prediction::EditPrediction::Local {
 7990                id,
 7991                edits,
 7992                edit_preview,
 7993            } => (id, edits, edit_preview),
 7994            edit_prediction::EditPrediction::Jump {
 7995                id,
 7996                snapshot,
 7997                target,
 7998            } => {
 7999                self.stale_edit_prediction_in_menu = None;
 8000                self.active_edit_prediction = Some(EditPredictionState {
 8001                    inlay_ids: vec![],
 8002                    completion: EditPrediction::MoveOutside { snapshot, target },
 8003                    completion_id: id,
 8004                    invalidation_range: None,
 8005                });
 8006                cx.notify();
 8007                return Some(());
 8008            }
 8009        };
 8010
 8011        let edits = edits
 8012            .into_iter()
 8013            .flat_map(|(range, new_text)| {
 8014                Some((
 8015                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8016                    new_text,
 8017                ))
 8018            })
 8019            .collect::<Vec<_>>();
 8020        if edits.is_empty() {
 8021            return None;
 8022        }
 8023
 8024        let first_edit_start = edits.first().unwrap().0.start;
 8025        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8026        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8027
 8028        let last_edit_end = edits.last().unwrap().0.end;
 8029        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8030        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8031
 8032        let cursor_row = cursor.to_point(&multibuffer).row;
 8033
 8034        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8035
 8036        let mut inlay_ids = Vec::new();
 8037        let invalidation_row_range;
 8038        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8039            Some(cursor_row..edit_end_row)
 8040        } else if cursor_row > edit_end_row {
 8041            Some(edit_start_row..cursor_row)
 8042        } else {
 8043            None
 8044        };
 8045        let supports_jump = self
 8046            .edit_prediction_provider
 8047            .as_ref()
 8048            .map(|provider| provider.provider.supports_jump_to_edit())
 8049            .unwrap_or(true);
 8050
 8051        let is_move = supports_jump
 8052            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8053        let completion = if is_move {
 8054            invalidation_row_range =
 8055                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8056            let target = first_edit_start;
 8057            EditPrediction::MoveWithin { target, snapshot }
 8058        } else {
 8059            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8060                && !self.edit_predictions_hidden_for_vim_mode;
 8061
 8062            if show_completions_in_buffer {
 8063                if let Some(provider) = &self.edit_prediction_provider {
 8064                    provider.provider.did_show(cx);
 8065                }
 8066                if edits
 8067                    .iter()
 8068                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8069                {
 8070                    let mut inlays = Vec::new();
 8071                    for (range, new_text) in &edits {
 8072                        let inlay = Inlay::edit_prediction(
 8073                            post_inc(&mut self.next_inlay_id),
 8074                            range.start,
 8075                            new_text.as_ref(),
 8076                        );
 8077                        inlay_ids.push(inlay.id);
 8078                        inlays.push(inlay);
 8079                    }
 8080
 8081                    self.splice_inlays(&[], inlays, cx);
 8082                } else {
 8083                    let background_color = cx.theme().status().deleted_background;
 8084                    self.highlight_text::<EditPredictionHighlight>(
 8085                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8086                        HighlightStyle {
 8087                            background_color: Some(background_color),
 8088                            ..Default::default()
 8089                        },
 8090                        cx,
 8091                    );
 8092                }
 8093            }
 8094
 8095            invalidation_row_range = edit_start_row..edit_end_row;
 8096
 8097            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8098                if provider.show_tab_accept_marker() {
 8099                    EditDisplayMode::TabAccept
 8100                } else {
 8101                    EditDisplayMode::Inline
 8102                }
 8103            } else {
 8104                EditDisplayMode::DiffPopover
 8105            };
 8106
 8107            EditPrediction::Edit {
 8108                edits,
 8109                edit_preview,
 8110                display_mode,
 8111                snapshot,
 8112            }
 8113        };
 8114
 8115        let invalidation_range = multibuffer
 8116            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8117            ..multibuffer.anchor_after(Point::new(
 8118                invalidation_row_range.end,
 8119                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8120            ));
 8121
 8122        self.stale_edit_prediction_in_menu = None;
 8123        self.active_edit_prediction = Some(EditPredictionState {
 8124            inlay_ids,
 8125            completion,
 8126            completion_id,
 8127            invalidation_range: Some(invalidation_range),
 8128        });
 8129
 8130        cx.notify();
 8131
 8132        Some(())
 8133    }
 8134
 8135    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8136        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8137    }
 8138
 8139    fn clear_tasks(&mut self) {
 8140        self.tasks.clear()
 8141    }
 8142
 8143    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8144        if self.tasks.insert(key, value).is_some() {
 8145            // This case should hopefully be rare, but just in case...
 8146            log::error!(
 8147                "multiple different run targets found on a single line, only the last target will be rendered"
 8148            )
 8149        }
 8150    }
 8151
 8152    /// Get all display points of breakpoints that will be rendered within editor
 8153    ///
 8154    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8155    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8156    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8157    fn active_breakpoints(
 8158        &self,
 8159        range: Range<DisplayRow>,
 8160        window: &mut Window,
 8161        cx: &mut Context<Self>,
 8162    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8163        let mut breakpoint_display_points = HashMap::default();
 8164
 8165        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8166            return breakpoint_display_points;
 8167        };
 8168
 8169        let snapshot = self.snapshot(window, cx);
 8170
 8171        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8172        let Some(project) = self.project() else {
 8173            return breakpoint_display_points;
 8174        };
 8175
 8176        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8177            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8178
 8179        for (buffer_snapshot, range, excerpt_id) in
 8180            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8181        {
 8182            let Some(buffer) = project
 8183                .read(cx)
 8184                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8185            else {
 8186                continue;
 8187            };
 8188            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8189                &buffer,
 8190                Some(
 8191                    buffer_snapshot.anchor_before(range.start)
 8192                        ..buffer_snapshot.anchor_after(range.end),
 8193                ),
 8194                buffer_snapshot,
 8195                cx,
 8196            );
 8197            for (breakpoint, state) in breakpoints {
 8198                let multi_buffer_anchor =
 8199                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8200                let position = multi_buffer_anchor
 8201                    .to_point(&multi_buffer_snapshot)
 8202                    .to_display_point(&snapshot);
 8203
 8204                breakpoint_display_points.insert(
 8205                    position.row(),
 8206                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8207                );
 8208            }
 8209        }
 8210
 8211        breakpoint_display_points
 8212    }
 8213
 8214    fn breakpoint_context_menu(
 8215        &self,
 8216        anchor: Anchor,
 8217        window: &mut Window,
 8218        cx: &mut Context<Self>,
 8219    ) -> Entity<ui::ContextMenu> {
 8220        let weak_editor = cx.weak_entity();
 8221        let focus_handle = self.focus_handle(cx);
 8222
 8223        let row = self
 8224            .buffer
 8225            .read(cx)
 8226            .snapshot(cx)
 8227            .summary_for_anchor::<Point>(&anchor)
 8228            .row;
 8229
 8230        let breakpoint = self
 8231            .breakpoint_at_row(row, window, cx)
 8232            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8233
 8234        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8235            "Edit Log Breakpoint"
 8236        } else {
 8237            "Set Log Breakpoint"
 8238        };
 8239
 8240        let condition_breakpoint_msg = if breakpoint
 8241            .as_ref()
 8242            .is_some_and(|bp| bp.1.condition.is_some())
 8243        {
 8244            "Edit Condition Breakpoint"
 8245        } else {
 8246            "Set Condition Breakpoint"
 8247        };
 8248
 8249        let hit_condition_breakpoint_msg = if breakpoint
 8250            .as_ref()
 8251            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8252        {
 8253            "Edit Hit Condition Breakpoint"
 8254        } else {
 8255            "Set Hit Condition Breakpoint"
 8256        };
 8257
 8258        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8259            "Unset Breakpoint"
 8260        } else {
 8261            "Set Breakpoint"
 8262        };
 8263
 8264        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8265
 8266        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8267            BreakpointState::Enabled => Some("Disable"),
 8268            BreakpointState::Disabled => Some("Enable"),
 8269        });
 8270
 8271        let (anchor, breakpoint) =
 8272            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8273
 8274        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8275            menu.on_blur_subscription(Subscription::new(|| {}))
 8276                .context(focus_handle)
 8277                .when(run_to_cursor, |this| {
 8278                    let weak_editor = weak_editor.clone();
 8279                    this.entry("Run to cursor", None, move |window, cx| {
 8280                        weak_editor
 8281                            .update(cx, |editor, cx| {
 8282                                editor.change_selections(
 8283                                    SelectionEffects::no_scroll(),
 8284                                    window,
 8285                                    cx,
 8286                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8287                                );
 8288                            })
 8289                            .ok();
 8290
 8291                        window.dispatch_action(Box::new(RunToCursor), cx);
 8292                    })
 8293                    .separator()
 8294                })
 8295                .when_some(toggle_state_msg, |this, msg| {
 8296                    this.entry(msg, None, {
 8297                        let weak_editor = weak_editor.clone();
 8298                        let breakpoint = breakpoint.clone();
 8299                        move |_window, cx| {
 8300                            weak_editor
 8301                                .update(cx, |this, cx| {
 8302                                    this.edit_breakpoint_at_anchor(
 8303                                        anchor,
 8304                                        breakpoint.as_ref().clone(),
 8305                                        BreakpointEditAction::InvertState,
 8306                                        cx,
 8307                                    );
 8308                                })
 8309                                .log_err();
 8310                        }
 8311                    })
 8312                })
 8313                .entry(set_breakpoint_msg, None, {
 8314                    let weak_editor = weak_editor.clone();
 8315                    let breakpoint = breakpoint.clone();
 8316                    move |_window, cx| {
 8317                        weak_editor
 8318                            .update(cx, |this, cx| {
 8319                                this.edit_breakpoint_at_anchor(
 8320                                    anchor,
 8321                                    breakpoint.as_ref().clone(),
 8322                                    BreakpointEditAction::Toggle,
 8323                                    cx,
 8324                                );
 8325                            })
 8326                            .log_err();
 8327                    }
 8328                })
 8329                .entry(log_breakpoint_msg, None, {
 8330                    let breakpoint = breakpoint.clone();
 8331                    let weak_editor = weak_editor.clone();
 8332                    move |window, cx| {
 8333                        weak_editor
 8334                            .update(cx, |this, cx| {
 8335                                this.add_edit_breakpoint_block(
 8336                                    anchor,
 8337                                    breakpoint.as_ref(),
 8338                                    BreakpointPromptEditAction::Log,
 8339                                    window,
 8340                                    cx,
 8341                                );
 8342                            })
 8343                            .log_err();
 8344                    }
 8345                })
 8346                .entry(condition_breakpoint_msg, None, {
 8347                    let breakpoint = breakpoint.clone();
 8348                    let weak_editor = weak_editor.clone();
 8349                    move |window, cx| {
 8350                        weak_editor
 8351                            .update(cx, |this, cx| {
 8352                                this.add_edit_breakpoint_block(
 8353                                    anchor,
 8354                                    breakpoint.as_ref(),
 8355                                    BreakpointPromptEditAction::Condition,
 8356                                    window,
 8357                                    cx,
 8358                                );
 8359                            })
 8360                            .log_err();
 8361                    }
 8362                })
 8363                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8364                    weak_editor
 8365                        .update(cx, |this, cx| {
 8366                            this.add_edit_breakpoint_block(
 8367                                anchor,
 8368                                breakpoint.as_ref(),
 8369                                BreakpointPromptEditAction::HitCondition,
 8370                                window,
 8371                                cx,
 8372                            );
 8373                        })
 8374                        .log_err();
 8375                })
 8376        })
 8377    }
 8378
 8379    fn render_breakpoint(
 8380        &self,
 8381        position: Anchor,
 8382        row: DisplayRow,
 8383        breakpoint: &Breakpoint,
 8384        state: Option<BreakpointSessionState>,
 8385        cx: &mut Context<Self>,
 8386    ) -> IconButton {
 8387        let is_rejected = state.is_some_and(|s| !s.verified);
 8388        // Is it a breakpoint that shows up when hovering over gutter?
 8389        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8390            (false, false),
 8391            |PhantomBreakpointIndicator {
 8392                 is_active,
 8393                 display_row,
 8394                 collides_with_existing_breakpoint,
 8395             }| {
 8396                (
 8397                    is_active && display_row == row,
 8398                    collides_with_existing_breakpoint,
 8399                )
 8400            },
 8401        );
 8402
 8403        let (color, icon) = {
 8404            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8405                (false, false) => ui::IconName::DebugBreakpoint,
 8406                (true, false) => ui::IconName::DebugLogBreakpoint,
 8407                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8408                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8409            };
 8410
 8411            let color = if is_phantom {
 8412                Color::Hint
 8413            } else if is_rejected {
 8414                Color::Disabled
 8415            } else {
 8416                Color::Debugger
 8417            };
 8418
 8419            (color, icon)
 8420        };
 8421
 8422        let breakpoint = Arc::from(breakpoint.clone());
 8423
 8424        let alt_as_text = gpui::Keystroke {
 8425            modifiers: Modifiers::secondary_key(),
 8426            ..Default::default()
 8427        };
 8428        let primary_action_text = if breakpoint.is_disabled() {
 8429            "Enable breakpoint"
 8430        } else if is_phantom && !collides_with_existing {
 8431            "Set breakpoint"
 8432        } else {
 8433            "Unset breakpoint"
 8434        };
 8435        let focus_handle = self.focus_handle.clone();
 8436
 8437        let meta = if is_rejected {
 8438            SharedString::from("No executable code is associated with this line.")
 8439        } else if collides_with_existing && !breakpoint.is_disabled() {
 8440            SharedString::from(format!(
 8441                "{alt_as_text}-click to disable,\nright-click for more options."
 8442            ))
 8443        } else {
 8444            SharedString::from("Right-click for more options.")
 8445        };
 8446        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8447            .icon_size(IconSize::XSmall)
 8448            .size(ui::ButtonSize::None)
 8449            .when(is_rejected, |this| {
 8450                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8451            })
 8452            .icon_color(color)
 8453            .style(ButtonStyle::Transparent)
 8454            .on_click(cx.listener({
 8455                move |editor, event: &ClickEvent, window, cx| {
 8456                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8457                        BreakpointEditAction::InvertState
 8458                    } else {
 8459                        BreakpointEditAction::Toggle
 8460                    };
 8461
 8462                    window.focus(&editor.focus_handle(cx));
 8463                    editor.edit_breakpoint_at_anchor(
 8464                        position,
 8465                        breakpoint.as_ref().clone(),
 8466                        edit_action,
 8467                        cx,
 8468                    );
 8469                }
 8470            }))
 8471            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8472                editor.set_breakpoint_context_menu(
 8473                    row,
 8474                    Some(position),
 8475                    event.position(),
 8476                    window,
 8477                    cx,
 8478                );
 8479            }))
 8480            .tooltip(move |_window, cx| {
 8481                Tooltip::with_meta_in(
 8482                    primary_action_text,
 8483                    Some(&ToggleBreakpoint),
 8484                    meta.clone(),
 8485                    &focus_handle,
 8486                    cx,
 8487                )
 8488            })
 8489    }
 8490
 8491    fn build_tasks_context(
 8492        project: &Entity<Project>,
 8493        buffer: &Entity<Buffer>,
 8494        buffer_row: u32,
 8495        tasks: &Arc<RunnableTasks>,
 8496        cx: &mut Context<Self>,
 8497    ) -> Task<Option<task::TaskContext>> {
 8498        let position = Point::new(buffer_row, tasks.column);
 8499        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8500        let location = Location {
 8501            buffer: buffer.clone(),
 8502            range: range_start..range_start,
 8503        };
 8504        // Fill in the environmental variables from the tree-sitter captures
 8505        let mut captured_task_variables = TaskVariables::default();
 8506        for (capture_name, value) in tasks.extra_variables.clone() {
 8507            captured_task_variables.insert(
 8508                task::VariableName::Custom(capture_name.into()),
 8509                value.clone(),
 8510            );
 8511        }
 8512        project.update(cx, |project, cx| {
 8513            project.task_store().update(cx, |task_store, cx| {
 8514                task_store.task_context_for_location(captured_task_variables, location, cx)
 8515            })
 8516        })
 8517    }
 8518
 8519    pub fn spawn_nearest_task(
 8520        &mut self,
 8521        action: &SpawnNearestTask,
 8522        window: &mut Window,
 8523        cx: &mut Context<Self>,
 8524    ) {
 8525        let Some((workspace, _)) = self.workspace.clone() else {
 8526            return;
 8527        };
 8528        let Some(project) = self.project.clone() else {
 8529            return;
 8530        };
 8531
 8532        // Try to find a closest, enclosing node using tree-sitter that has a task
 8533        let Some((buffer, buffer_row, tasks)) = self
 8534            .find_enclosing_node_task(cx)
 8535            // Or find the task that's closest in row-distance.
 8536            .or_else(|| self.find_closest_task(cx))
 8537        else {
 8538            return;
 8539        };
 8540
 8541        let reveal_strategy = action.reveal;
 8542        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8543        cx.spawn_in(window, async move |_, cx| {
 8544            let context = task_context.await?;
 8545            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8546
 8547            let resolved = &mut resolved_task.resolved;
 8548            resolved.reveal = reveal_strategy;
 8549
 8550            workspace
 8551                .update_in(cx, |workspace, window, cx| {
 8552                    workspace.schedule_resolved_task(
 8553                        task_source_kind,
 8554                        resolved_task,
 8555                        false,
 8556                        window,
 8557                        cx,
 8558                    );
 8559                })
 8560                .ok()
 8561        })
 8562        .detach();
 8563    }
 8564
 8565    fn find_closest_task(
 8566        &mut self,
 8567        cx: &mut Context<Self>,
 8568    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8569        let cursor_row = self
 8570            .selections
 8571            .newest_adjusted(&self.display_snapshot(cx))
 8572            .head()
 8573            .row;
 8574
 8575        let ((buffer_id, row), tasks) = self
 8576            .tasks
 8577            .iter()
 8578            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8579
 8580        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8581        let tasks = Arc::new(tasks.to_owned());
 8582        Some((buffer, *row, tasks))
 8583    }
 8584
 8585    fn find_enclosing_node_task(
 8586        &mut self,
 8587        cx: &mut Context<Self>,
 8588    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8589        let snapshot = self.buffer.read(cx).snapshot(cx);
 8590        let offset = self
 8591            .selections
 8592            .newest::<usize>(&self.display_snapshot(cx))
 8593            .head();
 8594        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8595        let buffer_id = excerpt.buffer().remote_id();
 8596
 8597        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8598        let mut cursor = layer.node().walk();
 8599
 8600        while cursor.goto_first_child_for_byte(offset).is_some() {
 8601            if cursor.node().end_byte() == offset {
 8602                cursor.goto_next_sibling();
 8603            }
 8604        }
 8605
 8606        // Ascend to the smallest ancestor that contains the range and has a task.
 8607        loop {
 8608            let node = cursor.node();
 8609            let node_range = node.byte_range();
 8610            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8611
 8612            // Check if this node contains our offset
 8613            if node_range.start <= offset && node_range.end >= offset {
 8614                // If it contains offset, check for task
 8615                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8616                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8617                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8618                }
 8619            }
 8620
 8621            if !cursor.goto_parent() {
 8622                break;
 8623            }
 8624        }
 8625        None
 8626    }
 8627
 8628    fn render_run_indicator(
 8629        &self,
 8630        _style: &EditorStyle,
 8631        is_active: bool,
 8632        row: DisplayRow,
 8633        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8634        cx: &mut Context<Self>,
 8635    ) -> IconButton {
 8636        let color = Color::Muted;
 8637        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8638
 8639        IconButton::new(
 8640            ("run_indicator", row.0 as usize),
 8641            ui::IconName::PlayOutlined,
 8642        )
 8643        .shape(ui::IconButtonShape::Square)
 8644        .icon_size(IconSize::XSmall)
 8645        .icon_color(color)
 8646        .toggle_state(is_active)
 8647        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8648            let quick_launch = match e {
 8649                ClickEvent::Keyboard(_) => true,
 8650                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8651            };
 8652
 8653            window.focus(&editor.focus_handle(cx));
 8654            editor.toggle_code_actions(
 8655                &ToggleCodeActions {
 8656                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8657                    quick_launch,
 8658                },
 8659                window,
 8660                cx,
 8661            );
 8662        }))
 8663        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8664            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8665        }))
 8666    }
 8667
 8668    pub fn context_menu_visible(&self) -> bool {
 8669        !self.edit_prediction_preview_is_active()
 8670            && self
 8671                .context_menu
 8672                .borrow()
 8673                .as_ref()
 8674                .is_some_and(|menu| menu.visible())
 8675    }
 8676
 8677    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8678        self.context_menu
 8679            .borrow()
 8680            .as_ref()
 8681            .map(|menu| menu.origin())
 8682    }
 8683
 8684    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8685        self.context_menu_options = Some(options);
 8686    }
 8687
 8688    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8689    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8690
 8691    fn render_edit_prediction_popover(
 8692        &mut self,
 8693        text_bounds: &Bounds<Pixels>,
 8694        content_origin: gpui::Point<Pixels>,
 8695        right_margin: Pixels,
 8696        editor_snapshot: &EditorSnapshot,
 8697        visible_row_range: Range<DisplayRow>,
 8698        scroll_top: ScrollOffset,
 8699        scroll_bottom: ScrollOffset,
 8700        line_layouts: &[LineWithInvisibles],
 8701        line_height: Pixels,
 8702        scroll_position: gpui::Point<ScrollOffset>,
 8703        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8704        newest_selection_head: Option<DisplayPoint>,
 8705        editor_width: Pixels,
 8706        style: &EditorStyle,
 8707        window: &mut Window,
 8708        cx: &mut App,
 8709    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8710        if self.mode().is_minimap() {
 8711            return None;
 8712        }
 8713        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8714
 8715        if self.edit_prediction_visible_in_cursor_popover(true) {
 8716            return None;
 8717        }
 8718
 8719        match &active_edit_prediction.completion {
 8720            EditPrediction::MoveWithin { target, .. } => {
 8721                let target_display_point = target.to_display_point(editor_snapshot);
 8722
 8723                if self.edit_prediction_requires_modifier() {
 8724                    if !self.edit_prediction_preview_is_active() {
 8725                        return None;
 8726                    }
 8727
 8728                    self.render_edit_prediction_modifier_jump_popover(
 8729                        text_bounds,
 8730                        content_origin,
 8731                        visible_row_range,
 8732                        line_layouts,
 8733                        line_height,
 8734                        scroll_pixel_position,
 8735                        newest_selection_head,
 8736                        target_display_point,
 8737                        window,
 8738                        cx,
 8739                    )
 8740                } else {
 8741                    self.render_edit_prediction_eager_jump_popover(
 8742                        text_bounds,
 8743                        content_origin,
 8744                        editor_snapshot,
 8745                        visible_row_range,
 8746                        scroll_top,
 8747                        scroll_bottom,
 8748                        line_height,
 8749                        scroll_pixel_position,
 8750                        target_display_point,
 8751                        editor_width,
 8752                        window,
 8753                        cx,
 8754                    )
 8755                }
 8756            }
 8757            EditPrediction::Edit {
 8758                display_mode: EditDisplayMode::Inline,
 8759                ..
 8760            } => None,
 8761            EditPrediction::Edit {
 8762                display_mode: EditDisplayMode::TabAccept,
 8763                edits,
 8764                ..
 8765            } => {
 8766                let range = &edits.first()?.0;
 8767                let target_display_point = range.end.to_display_point(editor_snapshot);
 8768
 8769                self.render_edit_prediction_end_of_line_popover(
 8770                    "Accept",
 8771                    editor_snapshot,
 8772                    visible_row_range,
 8773                    target_display_point,
 8774                    line_height,
 8775                    scroll_pixel_position,
 8776                    content_origin,
 8777                    editor_width,
 8778                    window,
 8779                    cx,
 8780                )
 8781            }
 8782            EditPrediction::Edit {
 8783                edits,
 8784                edit_preview,
 8785                display_mode: EditDisplayMode::DiffPopover,
 8786                snapshot,
 8787            } => self.render_edit_prediction_diff_popover(
 8788                text_bounds,
 8789                content_origin,
 8790                right_margin,
 8791                editor_snapshot,
 8792                visible_row_range,
 8793                line_layouts,
 8794                line_height,
 8795                scroll_position,
 8796                scroll_pixel_position,
 8797                newest_selection_head,
 8798                editor_width,
 8799                style,
 8800                edits,
 8801                edit_preview,
 8802                snapshot,
 8803                window,
 8804                cx,
 8805            ),
 8806            EditPrediction::MoveOutside { snapshot, .. } => {
 8807                let file_name = snapshot
 8808                    .file()
 8809                    .map(|file| file.file_name(cx))
 8810                    .unwrap_or("untitled");
 8811                let mut element = self
 8812                    .render_edit_prediction_line_popover(
 8813                        format!("Jump to {file_name}"),
 8814                        Some(IconName::ZedPredict),
 8815                        window,
 8816                        cx,
 8817                    )
 8818                    .into_any();
 8819
 8820                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8821                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8822                let origin_y = text_bounds.size.height - size.height - px(30.);
 8823                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8824                element.prepaint_at(origin, window, cx);
 8825
 8826                Some((element, origin))
 8827            }
 8828        }
 8829    }
 8830
 8831    fn render_edit_prediction_modifier_jump_popover(
 8832        &mut self,
 8833        text_bounds: &Bounds<Pixels>,
 8834        content_origin: gpui::Point<Pixels>,
 8835        visible_row_range: Range<DisplayRow>,
 8836        line_layouts: &[LineWithInvisibles],
 8837        line_height: Pixels,
 8838        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8839        newest_selection_head: Option<DisplayPoint>,
 8840        target_display_point: DisplayPoint,
 8841        window: &mut Window,
 8842        cx: &mut App,
 8843    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8844        let scrolled_content_origin =
 8845            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8846
 8847        const SCROLL_PADDING_Y: Pixels = px(12.);
 8848
 8849        if target_display_point.row() < visible_row_range.start {
 8850            return self.render_edit_prediction_scroll_popover(
 8851                |_| SCROLL_PADDING_Y,
 8852                IconName::ArrowUp,
 8853                visible_row_range,
 8854                line_layouts,
 8855                newest_selection_head,
 8856                scrolled_content_origin,
 8857                window,
 8858                cx,
 8859            );
 8860        } else if target_display_point.row() >= visible_row_range.end {
 8861            return self.render_edit_prediction_scroll_popover(
 8862                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8863                IconName::ArrowDown,
 8864                visible_row_range,
 8865                line_layouts,
 8866                newest_selection_head,
 8867                scrolled_content_origin,
 8868                window,
 8869                cx,
 8870            );
 8871        }
 8872
 8873        const POLE_WIDTH: Pixels = px(2.);
 8874
 8875        let line_layout =
 8876            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8877        let target_column = target_display_point.column() as usize;
 8878
 8879        let target_x = line_layout.x_for_index(target_column);
 8880        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8881            - scroll_pixel_position.y;
 8882
 8883        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8884
 8885        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8886        border_color.l += 0.001;
 8887
 8888        let mut element = v_flex()
 8889            .items_end()
 8890            .when(flag_on_right, |el| el.items_start())
 8891            .child(if flag_on_right {
 8892                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8893                    .rounded_bl(px(0.))
 8894                    .rounded_tl(px(0.))
 8895                    .border_l_2()
 8896                    .border_color(border_color)
 8897            } else {
 8898                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8899                    .rounded_br(px(0.))
 8900                    .rounded_tr(px(0.))
 8901                    .border_r_2()
 8902                    .border_color(border_color)
 8903            })
 8904            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8905            .into_any();
 8906
 8907        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8908
 8909        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8910            - point(
 8911                if flag_on_right {
 8912                    POLE_WIDTH
 8913                } else {
 8914                    size.width - POLE_WIDTH
 8915                },
 8916                size.height - line_height,
 8917            );
 8918
 8919        origin.x = origin.x.max(content_origin.x);
 8920
 8921        element.prepaint_at(origin, window, cx);
 8922
 8923        Some((element, origin))
 8924    }
 8925
 8926    fn render_edit_prediction_scroll_popover(
 8927        &mut self,
 8928        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8929        scroll_icon: IconName,
 8930        visible_row_range: Range<DisplayRow>,
 8931        line_layouts: &[LineWithInvisibles],
 8932        newest_selection_head: Option<DisplayPoint>,
 8933        scrolled_content_origin: gpui::Point<Pixels>,
 8934        window: &mut Window,
 8935        cx: &mut App,
 8936    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8937        let mut element = self
 8938            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8939            .into_any();
 8940
 8941        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8942
 8943        let cursor = newest_selection_head?;
 8944        let cursor_row_layout =
 8945            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8946        let cursor_column = cursor.column() as usize;
 8947
 8948        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8949
 8950        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8951
 8952        element.prepaint_at(origin, window, cx);
 8953        Some((element, origin))
 8954    }
 8955
 8956    fn render_edit_prediction_eager_jump_popover(
 8957        &mut self,
 8958        text_bounds: &Bounds<Pixels>,
 8959        content_origin: gpui::Point<Pixels>,
 8960        editor_snapshot: &EditorSnapshot,
 8961        visible_row_range: Range<DisplayRow>,
 8962        scroll_top: ScrollOffset,
 8963        scroll_bottom: ScrollOffset,
 8964        line_height: Pixels,
 8965        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8966        target_display_point: DisplayPoint,
 8967        editor_width: Pixels,
 8968        window: &mut Window,
 8969        cx: &mut App,
 8970    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8971        if target_display_point.row().as_f64() < scroll_top {
 8972            let mut element = self
 8973                .render_edit_prediction_line_popover(
 8974                    "Jump to Edit",
 8975                    Some(IconName::ArrowUp),
 8976                    window,
 8977                    cx,
 8978                )
 8979                .into_any();
 8980
 8981            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8982            let offset = point(
 8983                (text_bounds.size.width - size.width) / 2.,
 8984                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8985            );
 8986
 8987            let origin = text_bounds.origin + offset;
 8988            element.prepaint_at(origin, window, cx);
 8989            Some((element, origin))
 8990        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8991            let mut element = self
 8992                .render_edit_prediction_line_popover(
 8993                    "Jump to Edit",
 8994                    Some(IconName::ArrowDown),
 8995                    window,
 8996                    cx,
 8997                )
 8998                .into_any();
 8999
 9000            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9001            let offset = point(
 9002                (text_bounds.size.width - size.width) / 2.,
 9003                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9004            );
 9005
 9006            let origin = text_bounds.origin + offset;
 9007            element.prepaint_at(origin, window, cx);
 9008            Some((element, origin))
 9009        } else {
 9010            self.render_edit_prediction_end_of_line_popover(
 9011                "Jump to Edit",
 9012                editor_snapshot,
 9013                visible_row_range,
 9014                target_display_point,
 9015                line_height,
 9016                scroll_pixel_position,
 9017                content_origin,
 9018                editor_width,
 9019                window,
 9020                cx,
 9021            )
 9022        }
 9023    }
 9024
 9025    fn render_edit_prediction_end_of_line_popover(
 9026        self: &mut Editor,
 9027        label: &'static str,
 9028        editor_snapshot: &EditorSnapshot,
 9029        visible_row_range: Range<DisplayRow>,
 9030        target_display_point: DisplayPoint,
 9031        line_height: Pixels,
 9032        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9033        content_origin: gpui::Point<Pixels>,
 9034        editor_width: Pixels,
 9035        window: &mut Window,
 9036        cx: &mut App,
 9037    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9038        let target_line_end = DisplayPoint::new(
 9039            target_display_point.row(),
 9040            editor_snapshot.line_len(target_display_point.row()),
 9041        );
 9042
 9043        let mut element = self
 9044            .render_edit_prediction_line_popover(label, None, window, cx)
 9045            .into_any();
 9046
 9047        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9048
 9049        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9050
 9051        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9052        let mut origin = start_point
 9053            + line_origin
 9054            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9055        origin.x = origin.x.max(content_origin.x);
 9056
 9057        let max_x = content_origin.x + editor_width - size.width;
 9058
 9059        if origin.x > max_x {
 9060            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9061
 9062            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9063                origin.y += offset;
 9064                IconName::ArrowUp
 9065            } else {
 9066                origin.y -= offset;
 9067                IconName::ArrowDown
 9068            };
 9069
 9070            element = self
 9071                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9072                .into_any();
 9073
 9074            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9075
 9076            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9077        }
 9078
 9079        element.prepaint_at(origin, window, cx);
 9080        Some((element, origin))
 9081    }
 9082
 9083    fn render_edit_prediction_diff_popover(
 9084        self: &Editor,
 9085        text_bounds: &Bounds<Pixels>,
 9086        content_origin: gpui::Point<Pixels>,
 9087        right_margin: Pixels,
 9088        editor_snapshot: &EditorSnapshot,
 9089        visible_row_range: Range<DisplayRow>,
 9090        line_layouts: &[LineWithInvisibles],
 9091        line_height: Pixels,
 9092        scroll_position: gpui::Point<ScrollOffset>,
 9093        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9094        newest_selection_head: Option<DisplayPoint>,
 9095        editor_width: Pixels,
 9096        style: &EditorStyle,
 9097        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9098        edit_preview: &Option<language::EditPreview>,
 9099        snapshot: &language::BufferSnapshot,
 9100        window: &mut Window,
 9101        cx: &mut App,
 9102    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9103        let edit_start = edits
 9104            .first()
 9105            .unwrap()
 9106            .0
 9107            .start
 9108            .to_display_point(editor_snapshot);
 9109        let edit_end = edits
 9110            .last()
 9111            .unwrap()
 9112            .0
 9113            .end
 9114            .to_display_point(editor_snapshot);
 9115
 9116        let is_visible = visible_row_range.contains(&edit_start.row())
 9117            || visible_row_range.contains(&edit_end.row());
 9118        if !is_visible {
 9119            return None;
 9120        }
 9121
 9122        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9123            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9124        } else {
 9125            // Fallback for providers without edit_preview
 9126            crate::edit_prediction_fallback_text(edits, cx)
 9127        };
 9128
 9129        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9130        let line_count = highlighted_edits.text.lines().count();
 9131
 9132        const BORDER_WIDTH: Pixels = px(1.);
 9133
 9134        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9135        let has_keybind = keybind.is_some();
 9136
 9137        let mut element = h_flex()
 9138            .items_start()
 9139            .child(
 9140                h_flex()
 9141                    .bg(cx.theme().colors().editor_background)
 9142                    .border(BORDER_WIDTH)
 9143                    .shadow_xs()
 9144                    .border_color(cx.theme().colors().border)
 9145                    .rounded_l_lg()
 9146                    .when(line_count > 1, |el| el.rounded_br_lg())
 9147                    .pr_1()
 9148                    .child(styled_text),
 9149            )
 9150            .child(
 9151                h_flex()
 9152                    .h(line_height + BORDER_WIDTH * 2.)
 9153                    .px_1p5()
 9154                    .gap_1()
 9155                    // Workaround: For some reason, there's a gap if we don't do this
 9156                    .ml(-BORDER_WIDTH)
 9157                    .shadow(vec![gpui::BoxShadow {
 9158                        color: gpui::black().opacity(0.05),
 9159                        offset: point(px(1.), px(1.)),
 9160                        blur_radius: px(2.),
 9161                        spread_radius: px(0.),
 9162                    }])
 9163                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9164                    .border(BORDER_WIDTH)
 9165                    .border_color(cx.theme().colors().border)
 9166                    .rounded_r_lg()
 9167                    .id("edit_prediction_diff_popover_keybind")
 9168                    .when(!has_keybind, |el| {
 9169                        let status_colors = cx.theme().status();
 9170
 9171                        el.bg(status_colors.error_background)
 9172                            .border_color(status_colors.error.opacity(0.6))
 9173                            .child(Icon::new(IconName::Info).color(Color::Error))
 9174                            .cursor_default()
 9175                            .hoverable_tooltip(move |_window, cx| {
 9176                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9177                            })
 9178                    })
 9179                    .children(keybind),
 9180            )
 9181            .into_any();
 9182
 9183        let longest_row =
 9184            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9185        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9186            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9187        } else {
 9188            layout_line(
 9189                longest_row,
 9190                editor_snapshot,
 9191                style,
 9192                editor_width,
 9193                |_| false,
 9194                window,
 9195                cx,
 9196            )
 9197            .width
 9198        };
 9199
 9200        let viewport_bounds =
 9201            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9202                right: -right_margin,
 9203                ..Default::default()
 9204            });
 9205
 9206        let x_after_longest = Pixels::from(
 9207            ScrollPixelOffset::from(
 9208                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9209            ) - scroll_pixel_position.x,
 9210        );
 9211
 9212        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9213
 9214        // Fully visible if it can be displayed within the window (allow overlapping other
 9215        // panes). However, this is only allowed if the popover starts within text_bounds.
 9216        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9217            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9218
 9219        let mut origin = if can_position_to_the_right {
 9220            point(
 9221                x_after_longest,
 9222                text_bounds.origin.y
 9223                    + Pixels::from(
 9224                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9225                            - scroll_pixel_position.y,
 9226                    ),
 9227            )
 9228        } else {
 9229            let cursor_row = newest_selection_head.map(|head| head.row());
 9230            let above_edit = edit_start
 9231                .row()
 9232                .0
 9233                .checked_sub(line_count as u32)
 9234                .map(DisplayRow);
 9235            let below_edit = Some(edit_end.row() + 1);
 9236            let above_cursor =
 9237                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9238            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9239
 9240            // Place the edit popover adjacent to the edit if there is a location
 9241            // available that is onscreen and does not obscure the cursor. Otherwise,
 9242            // place it adjacent to the cursor.
 9243            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9244                .into_iter()
 9245                .flatten()
 9246                .find(|&start_row| {
 9247                    let end_row = start_row + line_count as u32;
 9248                    visible_row_range.contains(&start_row)
 9249                        && visible_row_range.contains(&end_row)
 9250                        && cursor_row
 9251                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9252                })?;
 9253
 9254            content_origin
 9255                + point(
 9256                    Pixels::from(-scroll_pixel_position.x),
 9257                    Pixels::from(
 9258                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9259                    ),
 9260                )
 9261        };
 9262
 9263        origin.x -= BORDER_WIDTH;
 9264
 9265        window.defer_draw(element, origin, 1);
 9266
 9267        // Do not return an element, since it will already be drawn due to defer_draw.
 9268        None
 9269    }
 9270
 9271    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9272        px(30.)
 9273    }
 9274
 9275    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9276        if self.read_only(cx) {
 9277            cx.theme().players().read_only()
 9278        } else {
 9279            self.style.as_ref().unwrap().local_player
 9280        }
 9281    }
 9282
 9283    fn render_edit_prediction_accept_keybind(
 9284        &self,
 9285        window: &mut Window,
 9286        cx: &mut App,
 9287    ) -> Option<AnyElement> {
 9288        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9289        let accept_keystroke = accept_binding.keystroke()?;
 9290
 9291        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9292
 9293        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9294            Color::Accent
 9295        } else {
 9296            Color::Muted
 9297        };
 9298
 9299        h_flex()
 9300            .px_0p5()
 9301            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9302            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9303            .text_size(TextSize::XSmall.rems(cx))
 9304            .child(h_flex().children(ui::render_modifiers(
 9305                accept_keystroke.modifiers(),
 9306                PlatformStyle::platform(),
 9307                Some(modifiers_color),
 9308                Some(IconSize::XSmall.rems().into()),
 9309                true,
 9310            )))
 9311            .when(is_platform_style_mac, |parent| {
 9312                parent.child(accept_keystroke.key().to_string())
 9313            })
 9314            .when(!is_platform_style_mac, |parent| {
 9315                parent.child(
 9316                    Key::new(
 9317                        util::capitalize(accept_keystroke.key()),
 9318                        Some(Color::Default),
 9319                    )
 9320                    .size(Some(IconSize::XSmall.rems().into())),
 9321                )
 9322            })
 9323            .into_any()
 9324            .into()
 9325    }
 9326
 9327    fn render_edit_prediction_line_popover(
 9328        &self,
 9329        label: impl Into<SharedString>,
 9330        icon: Option<IconName>,
 9331        window: &mut Window,
 9332        cx: &mut App,
 9333    ) -> Stateful<Div> {
 9334        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9335
 9336        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9337        let has_keybind = keybind.is_some();
 9338
 9339        h_flex()
 9340            .id("ep-line-popover")
 9341            .py_0p5()
 9342            .pl_1()
 9343            .pr(padding_right)
 9344            .gap_1()
 9345            .rounded_md()
 9346            .border_1()
 9347            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9348            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9349            .shadow_xs()
 9350            .when(!has_keybind, |el| {
 9351                let status_colors = cx.theme().status();
 9352
 9353                el.bg(status_colors.error_background)
 9354                    .border_color(status_colors.error.opacity(0.6))
 9355                    .pl_2()
 9356                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9357                    .cursor_default()
 9358                    .hoverable_tooltip(move |_window, cx| {
 9359                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9360                    })
 9361            })
 9362            .children(keybind)
 9363            .child(
 9364                Label::new(label)
 9365                    .size(LabelSize::Small)
 9366                    .when(!has_keybind, |el| {
 9367                        el.color(cx.theme().status().error.into()).strikethrough()
 9368                    }),
 9369            )
 9370            .when(!has_keybind, |el| {
 9371                el.child(
 9372                    h_flex().ml_1().child(
 9373                        Icon::new(IconName::Info)
 9374                            .size(IconSize::Small)
 9375                            .color(cx.theme().status().error.into()),
 9376                    ),
 9377                )
 9378            })
 9379            .when_some(icon, |element, icon| {
 9380                element.child(
 9381                    div()
 9382                        .mt(px(1.5))
 9383                        .child(Icon::new(icon).size(IconSize::Small)),
 9384                )
 9385            })
 9386    }
 9387
 9388    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9389        let accent_color = cx.theme().colors().text_accent;
 9390        let editor_bg_color = cx.theme().colors().editor_background;
 9391        editor_bg_color.blend(accent_color.opacity(0.1))
 9392    }
 9393
 9394    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9395        let accent_color = cx.theme().colors().text_accent;
 9396        let editor_bg_color = cx.theme().colors().editor_background;
 9397        editor_bg_color.blend(accent_color.opacity(0.6))
 9398    }
 9399    fn get_prediction_provider_icon_name(
 9400        provider: &Option<RegisteredEditPredictionProvider>,
 9401    ) -> IconName {
 9402        match provider {
 9403            Some(provider) => match provider.provider.name() {
 9404                "copilot" => IconName::Copilot,
 9405                "supermaven" => IconName::Supermaven,
 9406                _ => IconName::ZedPredict,
 9407            },
 9408            None => IconName::ZedPredict,
 9409        }
 9410    }
 9411
 9412    fn render_edit_prediction_cursor_popover(
 9413        &self,
 9414        min_width: Pixels,
 9415        max_width: Pixels,
 9416        cursor_point: Point,
 9417        style: &EditorStyle,
 9418        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9419        _window: &Window,
 9420        cx: &mut Context<Editor>,
 9421    ) -> Option<AnyElement> {
 9422        let provider = self.edit_prediction_provider.as_ref()?;
 9423        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9424
 9425        let is_refreshing = provider.provider.is_refreshing(cx);
 9426
 9427        fn pending_completion_container(icon: IconName) -> Div {
 9428            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9429        }
 9430
 9431        let completion = match &self.active_edit_prediction {
 9432            Some(prediction) => {
 9433                if !self.has_visible_completions_menu() {
 9434                    const RADIUS: Pixels = px(6.);
 9435                    const BORDER_WIDTH: Pixels = px(1.);
 9436
 9437                    return Some(
 9438                        h_flex()
 9439                            .elevation_2(cx)
 9440                            .border(BORDER_WIDTH)
 9441                            .border_color(cx.theme().colors().border)
 9442                            .when(accept_keystroke.is_none(), |el| {
 9443                                el.border_color(cx.theme().status().error)
 9444                            })
 9445                            .rounded(RADIUS)
 9446                            .rounded_tl(px(0.))
 9447                            .overflow_hidden()
 9448                            .child(div().px_1p5().child(match &prediction.completion {
 9449                                EditPrediction::MoveWithin { target, snapshot } => {
 9450                                    use text::ToPoint as _;
 9451                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9452                                    {
 9453                                        Icon::new(IconName::ZedPredictDown)
 9454                                    } else {
 9455                                        Icon::new(IconName::ZedPredictUp)
 9456                                    }
 9457                                }
 9458                                EditPrediction::MoveOutside { .. } => {
 9459                                    // TODO [zeta2] custom icon for external jump?
 9460                                    Icon::new(provider_icon)
 9461                                }
 9462                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9463                            }))
 9464                            .child(
 9465                                h_flex()
 9466                                    .gap_1()
 9467                                    .py_1()
 9468                                    .px_2()
 9469                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9470                                    .border_l_1()
 9471                                    .border_color(cx.theme().colors().border)
 9472                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9473                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9474                                        el.child(
 9475                                            Label::new("Hold")
 9476                                                .size(LabelSize::Small)
 9477                                                .when(accept_keystroke.is_none(), |el| {
 9478                                                    el.strikethrough()
 9479                                                })
 9480                                                .line_height_style(LineHeightStyle::UiLabel),
 9481                                        )
 9482                                    })
 9483                                    .id("edit_prediction_cursor_popover_keybind")
 9484                                    .when(accept_keystroke.is_none(), |el| {
 9485                                        let status_colors = cx.theme().status();
 9486
 9487                                        el.bg(status_colors.error_background)
 9488                                            .border_color(status_colors.error.opacity(0.6))
 9489                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9490                                            .cursor_default()
 9491                                            .hoverable_tooltip(move |_window, cx| {
 9492                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9493                                                    .into()
 9494                                            })
 9495                                    })
 9496                                    .when_some(
 9497                                        accept_keystroke.as_ref(),
 9498                                        |el, accept_keystroke| {
 9499                                            el.child(h_flex().children(ui::render_modifiers(
 9500                                                accept_keystroke.modifiers(),
 9501                                                PlatformStyle::platform(),
 9502                                                Some(Color::Default),
 9503                                                Some(IconSize::XSmall.rems().into()),
 9504                                                false,
 9505                                            )))
 9506                                        },
 9507                                    ),
 9508                            )
 9509                            .into_any(),
 9510                    );
 9511                }
 9512
 9513                self.render_edit_prediction_cursor_popover_preview(
 9514                    prediction,
 9515                    cursor_point,
 9516                    style,
 9517                    cx,
 9518                )?
 9519            }
 9520
 9521            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9522                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9523                    stale_completion,
 9524                    cursor_point,
 9525                    style,
 9526                    cx,
 9527                )?,
 9528
 9529                None => pending_completion_container(provider_icon)
 9530                    .child(Label::new("...").size(LabelSize::Small)),
 9531            },
 9532
 9533            None => pending_completion_container(provider_icon)
 9534                .child(Label::new("...").size(LabelSize::Small)),
 9535        };
 9536
 9537        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9538            completion
 9539                .with_animation(
 9540                    "loading-completion",
 9541                    Animation::new(Duration::from_secs(2))
 9542                        .repeat()
 9543                        .with_easing(pulsating_between(0.4, 0.8)),
 9544                    |label, delta| label.opacity(delta),
 9545                )
 9546                .into_any_element()
 9547        } else {
 9548            completion.into_any_element()
 9549        };
 9550
 9551        let has_completion = self.active_edit_prediction.is_some();
 9552
 9553        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9554        Some(
 9555            h_flex()
 9556                .min_w(min_width)
 9557                .max_w(max_width)
 9558                .flex_1()
 9559                .elevation_2(cx)
 9560                .border_color(cx.theme().colors().border)
 9561                .child(
 9562                    div()
 9563                        .flex_1()
 9564                        .py_1()
 9565                        .px_2()
 9566                        .overflow_hidden()
 9567                        .child(completion),
 9568                )
 9569                .when_some(accept_keystroke, |el, accept_keystroke| {
 9570                    if !accept_keystroke.modifiers().modified() {
 9571                        return el;
 9572                    }
 9573
 9574                    el.child(
 9575                        h_flex()
 9576                            .h_full()
 9577                            .border_l_1()
 9578                            .rounded_r_lg()
 9579                            .border_color(cx.theme().colors().border)
 9580                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9581                            .gap_1()
 9582                            .py_1()
 9583                            .px_2()
 9584                            .child(
 9585                                h_flex()
 9586                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9587                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9588                                    .child(h_flex().children(ui::render_modifiers(
 9589                                        accept_keystroke.modifiers(),
 9590                                        PlatformStyle::platform(),
 9591                                        Some(if !has_completion {
 9592                                            Color::Muted
 9593                                        } else {
 9594                                            Color::Default
 9595                                        }),
 9596                                        None,
 9597                                        false,
 9598                                    ))),
 9599                            )
 9600                            .child(Label::new("Preview").into_any_element())
 9601                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9602                    )
 9603                })
 9604                .into_any(),
 9605        )
 9606    }
 9607
 9608    fn render_edit_prediction_cursor_popover_preview(
 9609        &self,
 9610        completion: &EditPredictionState,
 9611        cursor_point: Point,
 9612        style: &EditorStyle,
 9613        cx: &mut Context<Editor>,
 9614    ) -> Option<Div> {
 9615        use text::ToPoint as _;
 9616
 9617        fn render_relative_row_jump(
 9618            prefix: impl Into<String>,
 9619            current_row: u32,
 9620            target_row: u32,
 9621        ) -> Div {
 9622            let (row_diff, arrow) = if target_row < current_row {
 9623                (current_row - target_row, IconName::ArrowUp)
 9624            } else {
 9625                (target_row - current_row, IconName::ArrowDown)
 9626            };
 9627
 9628            h_flex()
 9629                .child(
 9630                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9631                        .color(Color::Muted)
 9632                        .size(LabelSize::Small),
 9633                )
 9634                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9635        }
 9636
 9637        let supports_jump = self
 9638            .edit_prediction_provider
 9639            .as_ref()
 9640            .map(|provider| provider.provider.supports_jump_to_edit())
 9641            .unwrap_or(true);
 9642
 9643        match &completion.completion {
 9644            EditPrediction::MoveWithin {
 9645                target, snapshot, ..
 9646            } => {
 9647                if !supports_jump {
 9648                    return None;
 9649                }
 9650
 9651                Some(
 9652                    h_flex()
 9653                        .px_2()
 9654                        .gap_2()
 9655                        .flex_1()
 9656                        .child(
 9657                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9658                                Icon::new(IconName::ZedPredictDown)
 9659                            } else {
 9660                                Icon::new(IconName::ZedPredictUp)
 9661                            },
 9662                        )
 9663                        .child(Label::new("Jump to Edit")),
 9664                )
 9665            }
 9666            EditPrediction::MoveOutside { snapshot, .. } => {
 9667                let file_name = snapshot
 9668                    .file()
 9669                    .map(|file| file.file_name(cx))
 9670                    .unwrap_or("untitled");
 9671                Some(
 9672                    h_flex()
 9673                        .px_2()
 9674                        .gap_2()
 9675                        .flex_1()
 9676                        .child(Icon::new(IconName::ZedPredict))
 9677                        .child(Label::new(format!("Jump to {file_name}"))),
 9678                )
 9679            }
 9680            EditPrediction::Edit {
 9681                edits,
 9682                edit_preview,
 9683                snapshot,
 9684                display_mode: _,
 9685            } => {
 9686                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9687
 9688                let (highlighted_edits, has_more_lines) =
 9689                    if let Some(edit_preview) = edit_preview.as_ref() {
 9690                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9691                            .first_line_preview()
 9692                    } else {
 9693                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9694                    };
 9695
 9696                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9697                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9698
 9699                let preview = h_flex()
 9700                    .gap_1()
 9701                    .min_w_16()
 9702                    .child(styled_text)
 9703                    .when(has_more_lines, |parent| parent.child(""));
 9704
 9705                let left = if supports_jump && first_edit_row != cursor_point.row {
 9706                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9707                        .into_any_element()
 9708                } else {
 9709                    let icon_name =
 9710                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9711                    Icon::new(icon_name).into_any_element()
 9712                };
 9713
 9714                Some(
 9715                    h_flex()
 9716                        .h_full()
 9717                        .flex_1()
 9718                        .gap_2()
 9719                        .pr_1()
 9720                        .overflow_x_hidden()
 9721                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9722                        .child(left)
 9723                        .child(preview),
 9724                )
 9725            }
 9726        }
 9727    }
 9728
 9729    pub fn render_context_menu(
 9730        &self,
 9731        style: &EditorStyle,
 9732        max_height_in_lines: u32,
 9733        window: &mut Window,
 9734        cx: &mut Context<Editor>,
 9735    ) -> Option<AnyElement> {
 9736        let menu = self.context_menu.borrow();
 9737        let menu = menu.as_ref()?;
 9738        if !menu.visible() {
 9739            return None;
 9740        };
 9741        Some(menu.render(style, max_height_in_lines, window, cx))
 9742    }
 9743
 9744    fn render_context_menu_aside(
 9745        &mut self,
 9746        max_size: Size<Pixels>,
 9747        window: &mut Window,
 9748        cx: &mut Context<Editor>,
 9749    ) -> Option<AnyElement> {
 9750        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9751            if menu.visible() {
 9752                menu.render_aside(max_size, window, cx)
 9753            } else {
 9754                None
 9755            }
 9756        })
 9757    }
 9758
 9759    fn hide_context_menu(
 9760        &mut self,
 9761        window: &mut Window,
 9762        cx: &mut Context<Self>,
 9763    ) -> Option<CodeContextMenu> {
 9764        cx.notify();
 9765        self.completion_tasks.clear();
 9766        let context_menu = self.context_menu.borrow_mut().take();
 9767        self.stale_edit_prediction_in_menu.take();
 9768        self.update_visible_edit_prediction(window, cx);
 9769        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9770            && let Some(completion_provider) = &self.completion_provider
 9771        {
 9772            completion_provider.selection_changed(None, window, cx);
 9773        }
 9774        context_menu
 9775    }
 9776
 9777    fn show_snippet_choices(
 9778        &mut self,
 9779        choices: &Vec<String>,
 9780        selection: Range<Anchor>,
 9781        cx: &mut Context<Self>,
 9782    ) {
 9783        let Some((_, buffer, _)) = self
 9784            .buffer()
 9785            .read(cx)
 9786            .excerpt_containing(selection.start, cx)
 9787        else {
 9788            return;
 9789        };
 9790        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9791        else {
 9792            return;
 9793        };
 9794        if buffer != end_buffer {
 9795            log::error!("expected anchor range to have matching buffer IDs");
 9796            return;
 9797        }
 9798
 9799        let id = post_inc(&mut self.next_completion_id);
 9800        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9801        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9802            CompletionsMenu::new_snippet_choices(
 9803                id,
 9804                true,
 9805                choices,
 9806                selection,
 9807                buffer,
 9808                snippet_sort_order,
 9809            ),
 9810        ));
 9811    }
 9812
 9813    pub fn insert_snippet(
 9814        &mut self,
 9815        insertion_ranges: &[Range<usize>],
 9816        snippet: Snippet,
 9817        window: &mut Window,
 9818        cx: &mut Context<Self>,
 9819    ) -> Result<()> {
 9820        struct Tabstop<T> {
 9821            is_end_tabstop: bool,
 9822            ranges: Vec<Range<T>>,
 9823            choices: Option<Vec<String>>,
 9824        }
 9825
 9826        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9827            let snippet_text: Arc<str> = snippet.text.clone().into();
 9828            let edits = insertion_ranges
 9829                .iter()
 9830                .cloned()
 9831                .map(|range| (range, snippet_text.clone()));
 9832            let autoindent_mode = AutoindentMode::Block {
 9833                original_indent_columns: Vec::new(),
 9834            };
 9835            buffer.edit(edits, Some(autoindent_mode), cx);
 9836
 9837            let snapshot = &*buffer.read(cx);
 9838            let snippet = &snippet;
 9839            snippet
 9840                .tabstops
 9841                .iter()
 9842                .map(|tabstop| {
 9843                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9844                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9845                    });
 9846                    let mut tabstop_ranges = tabstop
 9847                        .ranges
 9848                        .iter()
 9849                        .flat_map(|tabstop_range| {
 9850                            let mut delta = 0_isize;
 9851                            insertion_ranges.iter().map(move |insertion_range| {
 9852                                let insertion_start = insertion_range.start as isize + delta;
 9853                                delta +=
 9854                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9855
 9856                                let start = ((insertion_start + tabstop_range.start) as usize)
 9857                                    .min(snapshot.len());
 9858                                let end = ((insertion_start + tabstop_range.end) as usize)
 9859                                    .min(snapshot.len());
 9860                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9861                            })
 9862                        })
 9863                        .collect::<Vec<_>>();
 9864                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9865
 9866                    Tabstop {
 9867                        is_end_tabstop,
 9868                        ranges: tabstop_ranges,
 9869                        choices: tabstop.choices.clone(),
 9870                    }
 9871                })
 9872                .collect::<Vec<_>>()
 9873        });
 9874        if let Some(tabstop) = tabstops.first() {
 9875            self.change_selections(Default::default(), window, cx, |s| {
 9876                // Reverse order so that the first range is the newest created selection.
 9877                // Completions will use it and autoscroll will prioritize it.
 9878                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9879            });
 9880
 9881            if let Some(choices) = &tabstop.choices
 9882                && let Some(selection) = tabstop.ranges.first()
 9883            {
 9884                self.show_snippet_choices(choices, selection.clone(), cx)
 9885            }
 9886
 9887            // If we're already at the last tabstop and it's at the end of the snippet,
 9888            // we're done, we don't need to keep the state around.
 9889            if !tabstop.is_end_tabstop {
 9890                let choices = tabstops
 9891                    .iter()
 9892                    .map(|tabstop| tabstop.choices.clone())
 9893                    .collect();
 9894
 9895                let ranges = tabstops
 9896                    .into_iter()
 9897                    .map(|tabstop| tabstop.ranges)
 9898                    .collect::<Vec<_>>();
 9899
 9900                self.snippet_stack.push(SnippetState {
 9901                    active_index: 0,
 9902                    ranges,
 9903                    choices,
 9904                });
 9905            }
 9906
 9907            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9908            if self.autoclose_regions.is_empty() {
 9909                let snapshot = self.buffer.read(cx).snapshot(cx);
 9910                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9911                    let selection_head = selection.head();
 9912                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9913                        continue;
 9914                    };
 9915
 9916                    let mut bracket_pair = None;
 9917                    let max_lookup_length = scope
 9918                        .brackets()
 9919                        .map(|(pair, _)| {
 9920                            pair.start
 9921                                .as_str()
 9922                                .chars()
 9923                                .count()
 9924                                .max(pair.end.as_str().chars().count())
 9925                        })
 9926                        .max();
 9927                    if let Some(max_lookup_length) = max_lookup_length {
 9928                        let next_text = snapshot
 9929                            .chars_at(selection_head)
 9930                            .take(max_lookup_length)
 9931                            .collect::<String>();
 9932                        let prev_text = snapshot
 9933                            .reversed_chars_at(selection_head)
 9934                            .take(max_lookup_length)
 9935                            .collect::<String>();
 9936
 9937                        for (pair, enabled) in scope.brackets() {
 9938                            if enabled
 9939                                && pair.close
 9940                                && prev_text.starts_with(pair.start.as_str())
 9941                                && next_text.starts_with(pair.end.as_str())
 9942                            {
 9943                                bracket_pair = Some(pair.clone());
 9944                                break;
 9945                            }
 9946                        }
 9947                    }
 9948
 9949                    if let Some(pair) = bracket_pair {
 9950                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9951                        let autoclose_enabled =
 9952                            self.use_autoclose && snapshot_settings.use_autoclose;
 9953                        if autoclose_enabled {
 9954                            let start = snapshot.anchor_after(selection_head);
 9955                            let end = snapshot.anchor_after(selection_head);
 9956                            self.autoclose_regions.push(AutocloseRegion {
 9957                                selection_id: selection.id,
 9958                                range: start..end,
 9959                                pair,
 9960                            });
 9961                        }
 9962                    }
 9963                }
 9964            }
 9965        }
 9966        Ok(())
 9967    }
 9968
 9969    pub fn move_to_next_snippet_tabstop(
 9970        &mut self,
 9971        window: &mut Window,
 9972        cx: &mut Context<Self>,
 9973    ) -> bool {
 9974        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9975    }
 9976
 9977    pub fn move_to_prev_snippet_tabstop(
 9978        &mut self,
 9979        window: &mut Window,
 9980        cx: &mut Context<Self>,
 9981    ) -> bool {
 9982        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9983    }
 9984
 9985    pub fn move_to_snippet_tabstop(
 9986        &mut self,
 9987        bias: Bias,
 9988        window: &mut Window,
 9989        cx: &mut Context<Self>,
 9990    ) -> bool {
 9991        if let Some(mut snippet) = self.snippet_stack.pop() {
 9992            match bias {
 9993                Bias::Left => {
 9994                    if snippet.active_index > 0 {
 9995                        snippet.active_index -= 1;
 9996                    } else {
 9997                        self.snippet_stack.push(snippet);
 9998                        return false;
 9999                    }
10000                }
10001                Bias::Right => {
10002                    if snippet.active_index + 1 < snippet.ranges.len() {
10003                        snippet.active_index += 1;
10004                    } else {
10005                        self.snippet_stack.push(snippet);
10006                        return false;
10007                    }
10008                }
10009            }
10010            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10011                self.change_selections(Default::default(), window, cx, |s| {
10012                    // Reverse order so that the first range is the newest created selection.
10013                    // Completions will use it and autoscroll will prioritize it.
10014                    s.select_ranges(current_ranges.iter().rev().cloned())
10015                });
10016
10017                if let Some(choices) = &snippet.choices[snippet.active_index]
10018                    && let Some(selection) = current_ranges.first()
10019                {
10020                    self.show_snippet_choices(choices, selection.clone(), cx);
10021                }
10022
10023                // If snippet state is not at the last tabstop, push it back on the stack
10024                if snippet.active_index + 1 < snippet.ranges.len() {
10025                    self.snippet_stack.push(snippet);
10026                }
10027                return true;
10028            }
10029        }
10030
10031        false
10032    }
10033
10034    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10035        self.transact(window, cx, |this, window, cx| {
10036            this.select_all(&SelectAll, window, cx);
10037            this.insert("", window, cx);
10038        });
10039    }
10040
10041    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10042        if self.read_only(cx) {
10043            return;
10044        }
10045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10046        self.transact(window, cx, |this, window, cx| {
10047            this.select_autoclose_pair(window, cx);
10048
10049            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10050
10051            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10052            if !this.linked_edit_ranges.is_empty() {
10053                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10054                let snapshot = this.buffer.read(cx).snapshot(cx);
10055
10056                for selection in selections.iter() {
10057                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10058                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10059                    if selection_start.buffer_id != selection_end.buffer_id {
10060                        continue;
10061                    }
10062                    if let Some(ranges) =
10063                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10064                    {
10065                        for (buffer, entries) in ranges {
10066                            linked_ranges.entry(buffer).or_default().extend(entries);
10067                        }
10068                    }
10069                }
10070            }
10071
10072            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10073            for selection in &mut selections {
10074                if selection.is_empty() {
10075                    let old_head = selection.head();
10076                    let mut new_head =
10077                        movement::left(&display_map, old_head.to_display_point(&display_map))
10078                            .to_point(&display_map);
10079                    if let Some((buffer, line_buffer_range)) = display_map
10080                        .buffer_snapshot()
10081                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10082                    {
10083                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10084                        let indent_len = match indent_size.kind {
10085                            IndentKind::Space => {
10086                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10087                            }
10088                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10089                        };
10090                        if old_head.column <= indent_size.len && old_head.column > 0 {
10091                            let indent_len = indent_len.get();
10092                            new_head = cmp::min(
10093                                new_head,
10094                                MultiBufferPoint::new(
10095                                    old_head.row,
10096                                    ((old_head.column - 1) / indent_len) * indent_len,
10097                                ),
10098                            );
10099                        }
10100                    }
10101
10102                    selection.set_head(new_head, SelectionGoal::None);
10103                }
10104            }
10105
10106            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10107            this.insert("", window, cx);
10108            let empty_str: Arc<str> = Arc::from("");
10109            for (buffer, edits) in linked_ranges {
10110                let snapshot = buffer.read(cx).snapshot();
10111                use text::ToPoint as TP;
10112
10113                let edits = edits
10114                    .into_iter()
10115                    .map(|range| {
10116                        let end_point = TP::to_point(&range.end, &snapshot);
10117                        let mut start_point = TP::to_point(&range.start, &snapshot);
10118
10119                        if end_point == start_point {
10120                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10121                                .saturating_sub(1);
10122                            start_point =
10123                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10124                        };
10125
10126                        (start_point..end_point, empty_str.clone())
10127                    })
10128                    .sorted_by_key(|(range, _)| range.start)
10129                    .collect::<Vec<_>>();
10130                buffer.update(cx, |this, cx| {
10131                    this.edit(edits, None, cx);
10132                })
10133            }
10134            this.refresh_edit_prediction(true, false, window, cx);
10135            refresh_linked_ranges(this, window, cx);
10136        });
10137    }
10138
10139    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10140        if self.read_only(cx) {
10141            return;
10142        }
10143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10144        self.transact(window, cx, |this, window, cx| {
10145            this.change_selections(Default::default(), window, cx, |s| {
10146                s.move_with(|map, selection| {
10147                    if selection.is_empty() {
10148                        let cursor = movement::right(map, selection.head());
10149                        selection.end = cursor;
10150                        selection.reversed = true;
10151                        selection.goal = SelectionGoal::None;
10152                    }
10153                })
10154            });
10155            this.insert("", window, cx);
10156            this.refresh_edit_prediction(true, false, window, cx);
10157        });
10158    }
10159
10160    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10161        if self.mode.is_single_line() {
10162            cx.propagate();
10163            return;
10164        }
10165
10166        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10167        if self.move_to_prev_snippet_tabstop(window, cx) {
10168            return;
10169        }
10170        self.outdent(&Outdent, window, cx);
10171    }
10172
10173    pub fn next_snippet_tabstop(
10174        &mut self,
10175        _: &NextSnippetTabstop,
10176        window: &mut Window,
10177        cx: &mut Context<Self>,
10178    ) {
10179        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10180            cx.propagate();
10181            return;
10182        }
10183
10184        if self.move_to_next_snippet_tabstop(window, cx) {
10185            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10186            return;
10187        }
10188        cx.propagate();
10189    }
10190
10191    pub fn previous_snippet_tabstop(
10192        &mut self,
10193        _: &PreviousSnippetTabstop,
10194        window: &mut Window,
10195        cx: &mut Context<Self>,
10196    ) {
10197        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10198            cx.propagate();
10199            return;
10200        }
10201
10202        if self.move_to_prev_snippet_tabstop(window, cx) {
10203            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10204            return;
10205        }
10206        cx.propagate();
10207    }
10208
10209    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10210        if self.mode.is_single_line() {
10211            cx.propagate();
10212            return;
10213        }
10214
10215        if self.move_to_next_snippet_tabstop(window, cx) {
10216            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10217            return;
10218        }
10219        if self.read_only(cx) {
10220            return;
10221        }
10222        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10223        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10224        let buffer = self.buffer.read(cx);
10225        let snapshot = buffer.snapshot(cx);
10226        let rows_iter = selections.iter().map(|s| s.head().row);
10227        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10228
10229        let has_some_cursor_in_whitespace = selections
10230            .iter()
10231            .filter(|selection| selection.is_empty())
10232            .any(|selection| {
10233                let cursor = selection.head();
10234                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10235                cursor.column < current_indent.len
10236            });
10237
10238        let mut edits = Vec::new();
10239        let mut prev_edited_row = 0;
10240        let mut row_delta = 0;
10241        for selection in &mut selections {
10242            if selection.start.row != prev_edited_row {
10243                row_delta = 0;
10244            }
10245            prev_edited_row = selection.end.row;
10246
10247            // If the selection is non-empty, then increase the indentation of the selected lines.
10248            if !selection.is_empty() {
10249                row_delta =
10250                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10251                continue;
10252            }
10253
10254            let cursor = selection.head();
10255            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10256            if let Some(suggested_indent) =
10257                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10258            {
10259                // Don't do anything if already at suggested indent
10260                // and there is any other cursor which is not
10261                if has_some_cursor_in_whitespace
10262                    && cursor.column == current_indent.len
10263                    && current_indent.len == suggested_indent.len
10264                {
10265                    continue;
10266                }
10267
10268                // Adjust line and move cursor to suggested indent
10269                // if cursor is not at suggested indent
10270                if cursor.column < suggested_indent.len
10271                    && cursor.column <= current_indent.len
10272                    && current_indent.len <= suggested_indent.len
10273                {
10274                    selection.start = Point::new(cursor.row, suggested_indent.len);
10275                    selection.end = selection.start;
10276                    if row_delta == 0 {
10277                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10278                            cursor.row,
10279                            current_indent,
10280                            suggested_indent,
10281                        ));
10282                        row_delta = suggested_indent.len - current_indent.len;
10283                    }
10284                    continue;
10285                }
10286
10287                // If current indent is more than suggested indent
10288                // only move cursor to current indent and skip indent
10289                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10290                    selection.start = Point::new(cursor.row, current_indent.len);
10291                    selection.end = selection.start;
10292                    continue;
10293                }
10294            }
10295
10296            // Otherwise, insert a hard or soft tab.
10297            let settings = buffer.language_settings_at(cursor, cx);
10298            let tab_size = if settings.hard_tabs {
10299                IndentSize::tab()
10300            } else {
10301                let tab_size = settings.tab_size.get();
10302                let indent_remainder = snapshot
10303                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10304                    .flat_map(str::chars)
10305                    .fold(row_delta % tab_size, |counter: u32, c| {
10306                        if c == '\t' {
10307                            0
10308                        } else {
10309                            (counter + 1) % tab_size
10310                        }
10311                    });
10312
10313                let chars_to_next_tab_stop = tab_size - indent_remainder;
10314                IndentSize::spaces(chars_to_next_tab_stop)
10315            };
10316            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10317            selection.end = selection.start;
10318            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10319            row_delta += tab_size.len;
10320        }
10321
10322        self.transact(window, cx, |this, window, cx| {
10323            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10324            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10325            this.refresh_edit_prediction(true, false, window, cx);
10326        });
10327    }
10328
10329    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10330        if self.read_only(cx) {
10331            return;
10332        }
10333        if self.mode.is_single_line() {
10334            cx.propagate();
10335            return;
10336        }
10337
10338        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10339        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10340        let mut prev_edited_row = 0;
10341        let mut row_delta = 0;
10342        let mut edits = Vec::new();
10343        let buffer = self.buffer.read(cx);
10344        let snapshot = buffer.snapshot(cx);
10345        for selection in &mut selections {
10346            if selection.start.row != prev_edited_row {
10347                row_delta = 0;
10348            }
10349            prev_edited_row = selection.end.row;
10350
10351            row_delta =
10352                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10353        }
10354
10355        self.transact(window, cx, |this, window, cx| {
10356            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10357            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10358        });
10359    }
10360
10361    fn indent_selection(
10362        buffer: &MultiBuffer,
10363        snapshot: &MultiBufferSnapshot,
10364        selection: &mut Selection<Point>,
10365        edits: &mut Vec<(Range<Point>, String)>,
10366        delta_for_start_row: u32,
10367        cx: &App,
10368    ) -> u32 {
10369        let settings = buffer.language_settings_at(selection.start, cx);
10370        let tab_size = settings.tab_size.get();
10371        let indent_kind = if settings.hard_tabs {
10372            IndentKind::Tab
10373        } else {
10374            IndentKind::Space
10375        };
10376        let mut start_row = selection.start.row;
10377        let mut end_row = selection.end.row + 1;
10378
10379        // If a selection ends at the beginning of a line, don't indent
10380        // that last line.
10381        if selection.end.column == 0 && selection.end.row > selection.start.row {
10382            end_row -= 1;
10383        }
10384
10385        // Avoid re-indenting a row that has already been indented by a
10386        // previous selection, but still update this selection's column
10387        // to reflect that indentation.
10388        if delta_for_start_row > 0 {
10389            start_row += 1;
10390            selection.start.column += delta_for_start_row;
10391            if selection.end.row == selection.start.row {
10392                selection.end.column += delta_for_start_row;
10393            }
10394        }
10395
10396        let mut delta_for_end_row = 0;
10397        let has_multiple_rows = start_row + 1 != end_row;
10398        for row in start_row..end_row {
10399            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10400            let indent_delta = match (current_indent.kind, indent_kind) {
10401                (IndentKind::Space, IndentKind::Space) => {
10402                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10403                    IndentSize::spaces(columns_to_next_tab_stop)
10404                }
10405                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10406                (_, IndentKind::Tab) => IndentSize::tab(),
10407            };
10408
10409            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10410                0
10411            } else {
10412                selection.start.column
10413            };
10414            let row_start = Point::new(row, start);
10415            edits.push((
10416                row_start..row_start,
10417                indent_delta.chars().collect::<String>(),
10418            ));
10419
10420            // Update this selection's endpoints to reflect the indentation.
10421            if row == selection.start.row {
10422                selection.start.column += indent_delta.len;
10423            }
10424            if row == selection.end.row {
10425                selection.end.column += indent_delta.len;
10426                delta_for_end_row = indent_delta.len;
10427            }
10428        }
10429
10430        if selection.start.row == selection.end.row {
10431            delta_for_start_row + delta_for_end_row
10432        } else {
10433            delta_for_end_row
10434        }
10435    }
10436
10437    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10438        if self.read_only(cx) {
10439            return;
10440        }
10441        if self.mode.is_single_line() {
10442            cx.propagate();
10443            return;
10444        }
10445
10446        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10447        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10448        let selections = self.selections.all::<Point>(&display_map);
10449        let mut deletion_ranges = Vec::new();
10450        let mut last_outdent = None;
10451        {
10452            let buffer = self.buffer.read(cx);
10453            let snapshot = buffer.snapshot(cx);
10454            for selection in &selections {
10455                let settings = buffer.language_settings_at(selection.start, cx);
10456                let tab_size = settings.tab_size.get();
10457                let mut rows = selection.spanned_rows(false, &display_map);
10458
10459                // Avoid re-outdenting a row that has already been outdented by a
10460                // previous selection.
10461                if let Some(last_row) = last_outdent
10462                    && last_row == rows.start
10463                {
10464                    rows.start = rows.start.next_row();
10465                }
10466                let has_multiple_rows = rows.len() > 1;
10467                for row in rows.iter_rows() {
10468                    let indent_size = snapshot.indent_size_for_line(row);
10469                    if indent_size.len > 0 {
10470                        let deletion_len = match indent_size.kind {
10471                            IndentKind::Space => {
10472                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10473                                if columns_to_prev_tab_stop == 0 {
10474                                    tab_size
10475                                } else {
10476                                    columns_to_prev_tab_stop
10477                                }
10478                            }
10479                            IndentKind::Tab => 1,
10480                        };
10481                        let start = if has_multiple_rows
10482                            || deletion_len > selection.start.column
10483                            || indent_size.len < selection.start.column
10484                        {
10485                            0
10486                        } else {
10487                            selection.start.column - deletion_len
10488                        };
10489                        deletion_ranges.push(
10490                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10491                        );
10492                        last_outdent = Some(row);
10493                    }
10494                }
10495            }
10496        }
10497
10498        self.transact(window, cx, |this, window, cx| {
10499            this.buffer.update(cx, |buffer, cx| {
10500                let empty_str: Arc<str> = Arc::default();
10501                buffer.edit(
10502                    deletion_ranges
10503                        .into_iter()
10504                        .map(|range| (range, empty_str.clone())),
10505                    None,
10506                    cx,
10507                );
10508            });
10509            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10510            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10511        });
10512    }
10513
10514    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10515        if self.read_only(cx) {
10516            return;
10517        }
10518        if self.mode.is_single_line() {
10519            cx.propagate();
10520            return;
10521        }
10522
10523        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10524        let selections = self
10525            .selections
10526            .all::<usize>(&self.display_snapshot(cx))
10527            .into_iter()
10528            .map(|s| s.range());
10529
10530        self.transact(window, cx, |this, window, cx| {
10531            this.buffer.update(cx, |buffer, cx| {
10532                buffer.autoindent_ranges(selections, cx);
10533            });
10534            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10535            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10536        });
10537    }
10538
10539    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10541        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10542        let selections = self.selections.all::<Point>(&display_map);
10543
10544        let mut new_cursors = Vec::new();
10545        let mut edit_ranges = Vec::new();
10546        let mut selections = selections.iter().peekable();
10547        while let Some(selection) = selections.next() {
10548            let mut rows = selection.spanned_rows(false, &display_map);
10549
10550            // Accumulate contiguous regions of rows that we want to delete.
10551            while let Some(next_selection) = selections.peek() {
10552                let next_rows = next_selection.spanned_rows(false, &display_map);
10553                if next_rows.start <= rows.end {
10554                    rows.end = next_rows.end;
10555                    selections.next().unwrap();
10556                } else {
10557                    break;
10558                }
10559            }
10560
10561            let buffer = display_map.buffer_snapshot();
10562            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10563            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10564                // If there's a line after the range, delete the \n from the end of the row range
10565                (
10566                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10567                    rows.end,
10568                )
10569            } else {
10570                // If there isn't a line after the range, delete the \n from the line before the
10571                // start of the row range
10572                edit_start = edit_start.saturating_sub(1);
10573                (buffer.len(), rows.start.previous_row())
10574            };
10575
10576            let text_layout_details = self.text_layout_details(window);
10577            let x = display_map.x_for_display_point(
10578                selection.head().to_display_point(&display_map),
10579                &text_layout_details,
10580            );
10581            let row = Point::new(target_row.0, 0)
10582                .to_display_point(&display_map)
10583                .row();
10584            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10585
10586            new_cursors.push((
10587                selection.id,
10588                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10589                SelectionGoal::None,
10590            ));
10591            edit_ranges.push(edit_start..edit_end);
10592        }
10593
10594        self.transact(window, cx, |this, window, cx| {
10595            let buffer = this.buffer.update(cx, |buffer, cx| {
10596                let empty_str: Arc<str> = Arc::default();
10597                buffer.edit(
10598                    edit_ranges
10599                        .into_iter()
10600                        .map(|range| (range, empty_str.clone())),
10601                    None,
10602                    cx,
10603                );
10604                buffer.snapshot(cx)
10605            });
10606            let new_selections = new_cursors
10607                .into_iter()
10608                .map(|(id, cursor, goal)| {
10609                    let cursor = cursor.to_point(&buffer);
10610                    Selection {
10611                        id,
10612                        start: cursor,
10613                        end: cursor,
10614                        reversed: false,
10615                        goal,
10616                    }
10617                })
10618                .collect();
10619
10620            this.change_selections(Default::default(), window, cx, |s| {
10621                s.select(new_selections);
10622            });
10623        });
10624    }
10625
10626    pub fn join_lines_impl(
10627        &mut self,
10628        insert_whitespace: bool,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) {
10632        if self.read_only(cx) {
10633            return;
10634        }
10635        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10636        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10637            let start = MultiBufferRow(selection.start.row);
10638            // Treat single line selections as if they include the next line. Otherwise this action
10639            // would do nothing for single line selections individual cursors.
10640            let end = if selection.start.row == selection.end.row {
10641                MultiBufferRow(selection.start.row + 1)
10642            } else {
10643                MultiBufferRow(selection.end.row)
10644            };
10645
10646            if let Some(last_row_range) = row_ranges.last_mut()
10647                && start <= last_row_range.end
10648            {
10649                last_row_range.end = end;
10650                continue;
10651            }
10652            row_ranges.push(start..end);
10653        }
10654
10655        let snapshot = self.buffer.read(cx).snapshot(cx);
10656        let mut cursor_positions = Vec::new();
10657        for row_range in &row_ranges {
10658            let anchor = snapshot.anchor_before(Point::new(
10659                row_range.end.previous_row().0,
10660                snapshot.line_len(row_range.end.previous_row()),
10661            ));
10662            cursor_positions.push(anchor..anchor);
10663        }
10664
10665        self.transact(window, cx, |this, window, cx| {
10666            for row_range in row_ranges.into_iter().rev() {
10667                for row in row_range.iter_rows().rev() {
10668                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10669                    let next_line_row = row.next_row();
10670                    let indent = snapshot.indent_size_for_line(next_line_row);
10671                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10672
10673                    let replace =
10674                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10675                            " "
10676                        } else {
10677                            ""
10678                        };
10679
10680                    this.buffer.update(cx, |buffer, cx| {
10681                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10682                    });
10683                }
10684            }
10685
10686            this.change_selections(Default::default(), window, cx, |s| {
10687                s.select_anchor_ranges(cursor_positions)
10688            });
10689        });
10690    }
10691
10692    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10693        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10694        self.join_lines_impl(true, window, cx);
10695    }
10696
10697    pub fn sort_lines_case_sensitive(
10698        &mut self,
10699        _: &SortLinesCaseSensitive,
10700        window: &mut Window,
10701        cx: &mut Context<Self>,
10702    ) {
10703        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10704    }
10705
10706    pub fn sort_lines_by_length(
10707        &mut self,
10708        _: &SortLinesByLength,
10709        window: &mut Window,
10710        cx: &mut Context<Self>,
10711    ) {
10712        self.manipulate_immutable_lines(window, cx, |lines| {
10713            lines.sort_by_key(|&line| line.chars().count())
10714        })
10715    }
10716
10717    pub fn sort_lines_case_insensitive(
10718        &mut self,
10719        _: &SortLinesCaseInsensitive,
10720        window: &mut Window,
10721        cx: &mut Context<Self>,
10722    ) {
10723        self.manipulate_immutable_lines(window, cx, |lines| {
10724            lines.sort_by_key(|line| line.to_lowercase())
10725        })
10726    }
10727
10728    pub fn unique_lines_case_insensitive(
10729        &mut self,
10730        _: &UniqueLinesCaseInsensitive,
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.to_lowercase()));
10737        })
10738    }
10739
10740    pub fn unique_lines_case_sensitive(
10741        &mut self,
10742        _: &UniqueLinesCaseSensitive,
10743        window: &mut Window,
10744        cx: &mut Context<Self>,
10745    ) {
10746        self.manipulate_immutable_lines(window, cx, |lines| {
10747            let mut seen = HashSet::default();
10748            lines.retain(|line| seen.insert(*line));
10749        })
10750    }
10751
10752    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10753        let snapshot = self.buffer.read(cx).snapshot(cx);
10754        for selection in self.selections.disjoint_anchors_arc().iter() {
10755            if snapshot
10756                .language_at(selection.start)
10757                .and_then(|lang| lang.config().wrap_characters.as_ref())
10758                .is_some()
10759            {
10760                return true;
10761            }
10762        }
10763        false
10764    }
10765
10766    fn wrap_selections_in_tag(
10767        &mut self,
10768        _: &WrapSelectionsInTag,
10769        window: &mut Window,
10770        cx: &mut Context<Self>,
10771    ) {
10772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10773
10774        let snapshot = self.buffer.read(cx).snapshot(cx);
10775
10776        let mut edits = Vec::new();
10777        let mut boundaries = Vec::new();
10778
10779        for selection in self
10780            .selections
10781            .all_adjusted(&self.display_snapshot(cx))
10782            .iter()
10783        {
10784            let Some(wrap_config) = snapshot
10785                .language_at(selection.start)
10786                .and_then(|lang| lang.config().wrap_characters.clone())
10787            else {
10788                continue;
10789            };
10790
10791            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10792            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10793
10794            let start_before = snapshot.anchor_before(selection.start);
10795            let end_after = snapshot.anchor_after(selection.end);
10796
10797            edits.push((start_before..start_before, open_tag));
10798            edits.push((end_after..end_after, close_tag));
10799
10800            boundaries.push((
10801                start_before,
10802                end_after,
10803                wrap_config.start_prefix.len(),
10804                wrap_config.end_suffix.len(),
10805            ));
10806        }
10807
10808        if edits.is_empty() {
10809            return;
10810        }
10811
10812        self.transact(window, cx, |this, window, cx| {
10813            let buffer = this.buffer.update(cx, |buffer, cx| {
10814                buffer.edit(edits, None, cx);
10815                buffer.snapshot(cx)
10816            });
10817
10818            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10819            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10820                boundaries.into_iter()
10821            {
10822                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10823                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10824                new_selections.push(open_offset..open_offset);
10825                new_selections.push(close_offset..close_offset);
10826            }
10827
10828            this.change_selections(Default::default(), window, cx, |s| {
10829                s.select_ranges(new_selections);
10830            });
10831
10832            this.request_autoscroll(Autoscroll::fit(), cx);
10833        });
10834    }
10835
10836    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10837        let Some(project) = self.project.clone() else {
10838            return;
10839        };
10840        self.reload(project, window, cx)
10841            .detach_and_notify_err(window, cx);
10842    }
10843
10844    pub fn restore_file(
10845        &mut self,
10846        _: &::git::RestoreFile,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) {
10850        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10851        let mut buffer_ids = HashSet::default();
10852        let snapshot = self.buffer().read(cx).snapshot(cx);
10853        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10854            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10855        }
10856
10857        let buffer = self.buffer().read(cx);
10858        let ranges = buffer_ids
10859            .into_iter()
10860            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10861            .collect::<Vec<_>>();
10862
10863        self.restore_hunks_in_ranges(ranges, window, cx);
10864    }
10865
10866    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10867        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10868        let selections = self
10869            .selections
10870            .all(&self.display_snapshot(cx))
10871            .into_iter()
10872            .map(|s| s.range())
10873            .collect();
10874        self.restore_hunks_in_ranges(selections, window, cx);
10875    }
10876
10877    pub fn restore_hunks_in_ranges(
10878        &mut self,
10879        ranges: Vec<Range<Point>>,
10880        window: &mut Window,
10881        cx: &mut Context<Editor>,
10882    ) {
10883        let mut revert_changes = HashMap::default();
10884        let chunk_by = self
10885            .snapshot(window, cx)
10886            .hunks_for_ranges(ranges)
10887            .into_iter()
10888            .chunk_by(|hunk| hunk.buffer_id);
10889        for (buffer_id, hunks) in &chunk_by {
10890            let hunks = hunks.collect::<Vec<_>>();
10891            for hunk in &hunks {
10892                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10893            }
10894            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10895        }
10896        drop(chunk_by);
10897        if !revert_changes.is_empty() {
10898            self.transact(window, cx, |editor, window, cx| {
10899                editor.restore(revert_changes, window, cx);
10900            });
10901        }
10902    }
10903
10904    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10905        if let Some(status) = self
10906            .addons
10907            .iter()
10908            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10909        {
10910            return Some(status);
10911        }
10912        self.project
10913            .as_ref()?
10914            .read(cx)
10915            .status_for_buffer_id(buffer_id, cx)
10916    }
10917
10918    pub fn open_active_item_in_terminal(
10919        &mut self,
10920        _: &OpenInTerminal,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10925            let project_path = buffer.read(cx).project_path(cx)?;
10926            let project = self.project()?.read(cx);
10927            let entry = project.entry_for_path(&project_path, cx)?;
10928            let parent = match &entry.canonical_path {
10929                Some(canonical_path) => canonical_path.to_path_buf(),
10930                None => project.absolute_path(&project_path, cx)?,
10931            }
10932            .parent()?
10933            .to_path_buf();
10934            Some(parent)
10935        }) {
10936            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10937        }
10938    }
10939
10940    fn set_breakpoint_context_menu(
10941        &mut self,
10942        display_row: DisplayRow,
10943        position: Option<Anchor>,
10944        clicked_point: gpui::Point<Pixels>,
10945        window: &mut Window,
10946        cx: &mut Context<Self>,
10947    ) {
10948        let source = self
10949            .buffer
10950            .read(cx)
10951            .snapshot(cx)
10952            .anchor_before(Point::new(display_row.0, 0u32));
10953
10954        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10955
10956        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10957            self,
10958            source,
10959            clicked_point,
10960            context_menu,
10961            window,
10962            cx,
10963        );
10964    }
10965
10966    fn add_edit_breakpoint_block(
10967        &mut self,
10968        anchor: Anchor,
10969        breakpoint: &Breakpoint,
10970        edit_action: BreakpointPromptEditAction,
10971        window: &mut Window,
10972        cx: &mut Context<Self>,
10973    ) {
10974        let weak_editor = cx.weak_entity();
10975        let bp_prompt = cx.new(|cx| {
10976            BreakpointPromptEditor::new(
10977                weak_editor,
10978                anchor,
10979                breakpoint.clone(),
10980                edit_action,
10981                window,
10982                cx,
10983            )
10984        });
10985
10986        let height = bp_prompt.update(cx, |this, cx| {
10987            this.prompt
10988                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10989        });
10990        let cloned_prompt = bp_prompt.clone();
10991        let blocks = vec![BlockProperties {
10992            style: BlockStyle::Sticky,
10993            placement: BlockPlacement::Above(anchor),
10994            height: Some(height),
10995            render: Arc::new(move |cx| {
10996                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10997                cloned_prompt.clone().into_any_element()
10998            }),
10999            priority: 0,
11000        }];
11001
11002        let focus_handle = bp_prompt.focus_handle(cx);
11003        window.focus(&focus_handle);
11004
11005        let block_ids = self.insert_blocks(blocks, None, cx);
11006        bp_prompt.update(cx, |prompt, _| {
11007            prompt.add_block_ids(block_ids);
11008        });
11009    }
11010
11011    pub(crate) fn breakpoint_at_row(
11012        &self,
11013        row: u32,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) -> Option<(Anchor, Breakpoint)> {
11017        let snapshot = self.snapshot(window, cx);
11018        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11019
11020        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11021    }
11022
11023    pub(crate) fn breakpoint_at_anchor(
11024        &self,
11025        breakpoint_position: Anchor,
11026        snapshot: &EditorSnapshot,
11027        cx: &mut Context<Self>,
11028    ) -> Option<(Anchor, Breakpoint)> {
11029        let buffer = self
11030            .buffer
11031            .read(cx)
11032            .buffer_for_anchor(breakpoint_position, cx)?;
11033
11034        let enclosing_excerpt = breakpoint_position.excerpt_id;
11035        let buffer_snapshot = buffer.read(cx).snapshot();
11036
11037        let row = buffer_snapshot
11038            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11039            .row;
11040
11041        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11042        let anchor_end = snapshot
11043            .buffer_snapshot()
11044            .anchor_after(Point::new(row, line_len));
11045
11046        self.breakpoint_store
11047            .as_ref()?
11048            .read_with(cx, |breakpoint_store, cx| {
11049                breakpoint_store
11050                    .breakpoints(
11051                        &buffer,
11052                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11053                        &buffer_snapshot,
11054                        cx,
11055                    )
11056                    .next()
11057                    .and_then(|(bp, _)| {
11058                        let breakpoint_row = buffer_snapshot
11059                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11060                            .row;
11061
11062                        if breakpoint_row == row {
11063                            snapshot
11064                                .buffer_snapshot()
11065                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11066                                .map(|position| (position, bp.bp.clone()))
11067                        } else {
11068                            None
11069                        }
11070                    })
11071            })
11072    }
11073
11074    pub fn edit_log_breakpoint(
11075        &mut self,
11076        _: &EditLogBreakpoint,
11077        window: &mut Window,
11078        cx: &mut Context<Self>,
11079    ) {
11080        if self.breakpoint_store.is_none() {
11081            return;
11082        }
11083
11084        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11085            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11086                message: None,
11087                state: BreakpointState::Enabled,
11088                condition: None,
11089                hit_condition: None,
11090            });
11091
11092            self.add_edit_breakpoint_block(
11093                anchor,
11094                &breakpoint,
11095                BreakpointPromptEditAction::Log,
11096                window,
11097                cx,
11098            );
11099        }
11100    }
11101
11102    fn breakpoints_at_cursors(
11103        &self,
11104        window: &mut Window,
11105        cx: &mut Context<Self>,
11106    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11107        let snapshot = self.snapshot(window, cx);
11108        let cursors = self
11109            .selections
11110            .disjoint_anchors_arc()
11111            .iter()
11112            .map(|selection| {
11113                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11114
11115                let breakpoint_position = self
11116                    .breakpoint_at_row(cursor_position.row, window, cx)
11117                    .map(|bp| bp.0)
11118                    .unwrap_or_else(|| {
11119                        snapshot
11120                            .display_snapshot
11121                            .buffer_snapshot()
11122                            .anchor_after(Point::new(cursor_position.row, 0))
11123                    });
11124
11125                let breakpoint = self
11126                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11127                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11128
11129                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11130            })
11131            // 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.
11132            .collect::<HashMap<Anchor, _>>();
11133
11134        cursors.into_iter().collect()
11135    }
11136
11137    pub fn enable_breakpoint(
11138        &mut self,
11139        _: &crate::actions::EnableBreakpoint,
11140        window: &mut Window,
11141        cx: &mut Context<Self>,
11142    ) {
11143        if self.breakpoint_store.is_none() {
11144            return;
11145        }
11146
11147        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11148            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11149                continue;
11150            };
11151            self.edit_breakpoint_at_anchor(
11152                anchor,
11153                breakpoint,
11154                BreakpointEditAction::InvertState,
11155                cx,
11156            );
11157        }
11158    }
11159
11160    pub fn disable_breakpoint(
11161        &mut self,
11162        _: &crate::actions::DisableBreakpoint,
11163        window: &mut Window,
11164        cx: &mut Context<Self>,
11165    ) {
11166        if self.breakpoint_store.is_none() {
11167            return;
11168        }
11169
11170        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11171            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11172                continue;
11173            };
11174            self.edit_breakpoint_at_anchor(
11175                anchor,
11176                breakpoint,
11177                BreakpointEditAction::InvertState,
11178                cx,
11179            );
11180        }
11181    }
11182
11183    pub fn toggle_breakpoint(
11184        &mut self,
11185        _: &crate::actions::ToggleBreakpoint,
11186        window: &mut Window,
11187        cx: &mut Context<Self>,
11188    ) {
11189        if self.breakpoint_store.is_none() {
11190            return;
11191        }
11192
11193        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11194            if let Some(breakpoint) = breakpoint {
11195                self.edit_breakpoint_at_anchor(
11196                    anchor,
11197                    breakpoint,
11198                    BreakpointEditAction::Toggle,
11199                    cx,
11200                );
11201            } else {
11202                self.edit_breakpoint_at_anchor(
11203                    anchor,
11204                    Breakpoint::new_standard(),
11205                    BreakpointEditAction::Toggle,
11206                    cx,
11207                );
11208            }
11209        }
11210    }
11211
11212    pub fn edit_breakpoint_at_anchor(
11213        &mut self,
11214        breakpoint_position: Anchor,
11215        breakpoint: Breakpoint,
11216        edit_action: BreakpointEditAction,
11217        cx: &mut Context<Self>,
11218    ) {
11219        let Some(breakpoint_store) = &self.breakpoint_store else {
11220            return;
11221        };
11222
11223        let Some(buffer) = self
11224            .buffer
11225            .read(cx)
11226            .buffer_for_anchor(breakpoint_position, cx)
11227        else {
11228            return;
11229        };
11230
11231        breakpoint_store.update(cx, |breakpoint_store, cx| {
11232            breakpoint_store.toggle_breakpoint(
11233                buffer,
11234                BreakpointWithPosition {
11235                    position: breakpoint_position.text_anchor,
11236                    bp: breakpoint,
11237                },
11238                edit_action,
11239                cx,
11240            );
11241        });
11242
11243        cx.notify();
11244    }
11245
11246    #[cfg(any(test, feature = "test-support"))]
11247    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11248        self.breakpoint_store.clone()
11249    }
11250
11251    pub fn prepare_restore_change(
11252        &self,
11253        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11254        hunk: &MultiBufferDiffHunk,
11255        cx: &mut App,
11256    ) -> Option<()> {
11257        if hunk.is_created_file() {
11258            return None;
11259        }
11260        let buffer = self.buffer.read(cx);
11261        let diff = buffer.diff_for(hunk.buffer_id)?;
11262        let buffer = buffer.buffer(hunk.buffer_id)?;
11263        let buffer = buffer.read(cx);
11264        let original_text = diff
11265            .read(cx)
11266            .base_text()
11267            .as_rope()
11268            .slice(hunk.diff_base_byte_range.clone());
11269        let buffer_snapshot = buffer.snapshot();
11270        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11271        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11272            probe
11273                .0
11274                .start
11275                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11276                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11277        }) {
11278            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11279            Some(())
11280        } else {
11281            None
11282        }
11283    }
11284
11285    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11286        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11287    }
11288
11289    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11290        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11291    }
11292
11293    fn manipulate_lines<M>(
11294        &mut self,
11295        window: &mut Window,
11296        cx: &mut Context<Self>,
11297        mut manipulate: M,
11298    ) where
11299        M: FnMut(&str) -> LineManipulationResult,
11300    {
11301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11302
11303        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11304        let buffer = self.buffer.read(cx).snapshot(cx);
11305
11306        let mut edits = Vec::new();
11307
11308        let selections = self.selections.all::<Point>(&display_map);
11309        let mut selections = selections.iter().peekable();
11310        let mut contiguous_row_selections = Vec::new();
11311        let mut new_selections = Vec::new();
11312        let mut added_lines = 0;
11313        let mut removed_lines = 0;
11314
11315        while let Some(selection) = selections.next() {
11316            let (start_row, end_row) = consume_contiguous_rows(
11317                &mut contiguous_row_selections,
11318                selection,
11319                &display_map,
11320                &mut selections,
11321            );
11322
11323            let start_point = Point::new(start_row.0, 0);
11324            let end_point = Point::new(
11325                end_row.previous_row().0,
11326                buffer.line_len(end_row.previous_row()),
11327            );
11328            let text = buffer
11329                .text_for_range(start_point..end_point)
11330                .collect::<String>();
11331
11332            let LineManipulationResult {
11333                new_text,
11334                line_count_before,
11335                line_count_after,
11336            } = manipulate(&text);
11337
11338            edits.push((start_point..end_point, new_text));
11339
11340            // Selections must change based on added and removed line count
11341            let start_row =
11342                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11343            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11344            new_selections.push(Selection {
11345                id: selection.id,
11346                start: start_row,
11347                end: end_row,
11348                goal: SelectionGoal::None,
11349                reversed: selection.reversed,
11350            });
11351
11352            if line_count_after > line_count_before {
11353                added_lines += line_count_after - line_count_before;
11354            } else if line_count_before > line_count_after {
11355                removed_lines += line_count_before - line_count_after;
11356            }
11357        }
11358
11359        self.transact(window, cx, |this, window, cx| {
11360            let buffer = this.buffer.update(cx, |buffer, cx| {
11361                buffer.edit(edits, None, cx);
11362                buffer.snapshot(cx)
11363            });
11364
11365            // Recalculate offsets on newly edited buffer
11366            let new_selections = new_selections
11367                .iter()
11368                .map(|s| {
11369                    let start_point = Point::new(s.start.0, 0);
11370                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11371                    Selection {
11372                        id: s.id,
11373                        start: buffer.point_to_offset(start_point),
11374                        end: buffer.point_to_offset(end_point),
11375                        goal: s.goal,
11376                        reversed: s.reversed,
11377                    }
11378                })
11379                .collect();
11380
11381            this.change_selections(Default::default(), window, cx, |s| {
11382                s.select(new_selections);
11383            });
11384
11385            this.request_autoscroll(Autoscroll::fit(), cx);
11386        });
11387    }
11388
11389    fn manipulate_immutable_lines<Fn>(
11390        &mut self,
11391        window: &mut Window,
11392        cx: &mut Context<Self>,
11393        mut callback: Fn,
11394    ) where
11395        Fn: FnMut(&mut Vec<&str>),
11396    {
11397        self.manipulate_lines(window, cx, |text| {
11398            let mut lines: Vec<&str> = text.split('\n').collect();
11399            let line_count_before = lines.len();
11400
11401            callback(&mut lines);
11402
11403            LineManipulationResult {
11404                new_text: lines.join("\n"),
11405                line_count_before,
11406                line_count_after: lines.len(),
11407            }
11408        });
11409    }
11410
11411    fn manipulate_mutable_lines<Fn>(
11412        &mut self,
11413        window: &mut Window,
11414        cx: &mut Context<Self>,
11415        mut callback: Fn,
11416    ) where
11417        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11418    {
11419        self.manipulate_lines(window, cx, |text| {
11420            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11421            let line_count_before = lines.len();
11422
11423            callback(&mut lines);
11424
11425            LineManipulationResult {
11426                new_text: lines.join("\n"),
11427                line_count_before,
11428                line_count_after: lines.len(),
11429            }
11430        });
11431    }
11432
11433    pub fn convert_indentation_to_spaces(
11434        &mut self,
11435        _: &ConvertIndentationToSpaces,
11436        window: &mut Window,
11437        cx: &mut Context<Self>,
11438    ) {
11439        let settings = self.buffer.read(cx).language_settings(cx);
11440        let tab_size = settings.tab_size.get() as usize;
11441
11442        self.manipulate_mutable_lines(window, cx, |lines| {
11443            // Allocates a reasonably sized scratch buffer once for the whole loop
11444            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11445            // Avoids recomputing spaces that could be inserted many times
11446            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11447                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11448                .collect();
11449
11450            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11451                let mut chars = line.as_ref().chars();
11452                let mut col = 0;
11453                let mut changed = false;
11454
11455                for ch in chars.by_ref() {
11456                    match ch {
11457                        ' ' => {
11458                            reindented_line.push(' ');
11459                            col += 1;
11460                        }
11461                        '\t' => {
11462                            // \t are converted to spaces depending on the current column
11463                            let spaces_len = tab_size - (col % tab_size);
11464                            reindented_line.extend(&space_cache[spaces_len - 1]);
11465                            col += spaces_len;
11466                            changed = true;
11467                        }
11468                        _ => {
11469                            // If we dont append before break, the character is consumed
11470                            reindented_line.push(ch);
11471                            break;
11472                        }
11473                    }
11474                }
11475
11476                if !changed {
11477                    reindented_line.clear();
11478                    continue;
11479                }
11480                // Append the rest of the line and replace old reference with new one
11481                reindented_line.extend(chars);
11482                *line = Cow::Owned(reindented_line.clone());
11483                reindented_line.clear();
11484            }
11485        });
11486    }
11487
11488    pub fn convert_indentation_to_tabs(
11489        &mut self,
11490        _: &ConvertIndentationToTabs,
11491        window: &mut Window,
11492        cx: &mut Context<Self>,
11493    ) {
11494        let settings = self.buffer.read(cx).language_settings(cx);
11495        let tab_size = settings.tab_size.get() as usize;
11496
11497        self.manipulate_mutable_lines(window, cx, |lines| {
11498            // Allocates a reasonably sized buffer once for the whole loop
11499            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11500            // Avoids recomputing spaces that could be inserted many times
11501            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11502                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11503                .collect();
11504
11505            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11506                let mut chars = line.chars();
11507                let mut spaces_count = 0;
11508                let mut first_non_indent_char = None;
11509                let mut changed = false;
11510
11511                for ch in chars.by_ref() {
11512                    match ch {
11513                        ' ' => {
11514                            // Keep track of spaces. Append \t when we reach tab_size
11515                            spaces_count += 1;
11516                            changed = true;
11517                            if spaces_count == tab_size {
11518                                reindented_line.push('\t');
11519                                spaces_count = 0;
11520                            }
11521                        }
11522                        '\t' => {
11523                            reindented_line.push('\t');
11524                            spaces_count = 0;
11525                        }
11526                        _ => {
11527                            // Dont append it yet, we might have remaining spaces
11528                            first_non_indent_char = Some(ch);
11529                            break;
11530                        }
11531                    }
11532                }
11533
11534                if !changed {
11535                    reindented_line.clear();
11536                    continue;
11537                }
11538                // Remaining spaces that didn't make a full tab stop
11539                if spaces_count > 0 {
11540                    reindented_line.extend(&space_cache[spaces_count - 1]);
11541                }
11542                // If we consume an extra character that was not indentation, add it back
11543                if let Some(extra_char) = first_non_indent_char {
11544                    reindented_line.push(extra_char);
11545                }
11546                // Append the rest of the line and replace old reference with new one
11547                reindented_line.extend(chars);
11548                *line = Cow::Owned(reindented_line.clone());
11549                reindented_line.clear();
11550            }
11551        });
11552    }
11553
11554    pub fn convert_to_upper_case(
11555        &mut self,
11556        _: &ConvertToUpperCase,
11557        window: &mut Window,
11558        cx: &mut Context<Self>,
11559    ) {
11560        self.manipulate_text(window, cx, |text| text.to_uppercase())
11561    }
11562
11563    pub fn convert_to_lower_case(
11564        &mut self,
11565        _: &ConvertToLowerCase,
11566        window: &mut Window,
11567        cx: &mut Context<Self>,
11568    ) {
11569        self.manipulate_text(window, cx, |text| text.to_lowercase())
11570    }
11571
11572    pub fn convert_to_title_case(
11573        &mut self,
11574        _: &ConvertToTitleCase,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.manipulate_text(window, cx, |text| {
11579            text.split('\n')
11580                .map(|line| line.to_case(Case::Title))
11581                .join("\n")
11582        })
11583    }
11584
11585    pub fn convert_to_snake_case(
11586        &mut self,
11587        _: &ConvertToSnakeCase,
11588        window: &mut Window,
11589        cx: &mut Context<Self>,
11590    ) {
11591        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11592    }
11593
11594    pub fn convert_to_kebab_case(
11595        &mut self,
11596        _: &ConvertToKebabCase,
11597        window: &mut Window,
11598        cx: &mut Context<Self>,
11599    ) {
11600        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11601    }
11602
11603    pub fn convert_to_upper_camel_case(
11604        &mut self,
11605        _: &ConvertToUpperCamelCase,
11606        window: &mut Window,
11607        cx: &mut Context<Self>,
11608    ) {
11609        self.manipulate_text(window, cx, |text| {
11610            text.split('\n')
11611                .map(|line| line.to_case(Case::UpperCamel))
11612                .join("\n")
11613        })
11614    }
11615
11616    pub fn convert_to_lower_camel_case(
11617        &mut self,
11618        _: &ConvertToLowerCamelCase,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11623    }
11624
11625    pub fn convert_to_opposite_case(
11626        &mut self,
11627        _: &ConvertToOppositeCase,
11628        window: &mut Window,
11629        cx: &mut Context<Self>,
11630    ) {
11631        self.manipulate_text(window, cx, |text| {
11632            text.chars()
11633                .fold(String::with_capacity(text.len()), |mut t, c| {
11634                    if c.is_uppercase() {
11635                        t.extend(c.to_lowercase());
11636                    } else {
11637                        t.extend(c.to_uppercase());
11638                    }
11639                    t
11640                })
11641        })
11642    }
11643
11644    pub fn convert_to_sentence_case(
11645        &mut self,
11646        _: &ConvertToSentenceCase,
11647        window: &mut Window,
11648        cx: &mut Context<Self>,
11649    ) {
11650        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11651    }
11652
11653    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11654        self.manipulate_text(window, cx, |text| {
11655            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11656            if has_upper_case_characters {
11657                text.to_lowercase()
11658            } else {
11659                text.to_uppercase()
11660            }
11661        })
11662    }
11663
11664    pub fn convert_to_rot13(
11665        &mut self,
11666        _: &ConvertToRot13,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.manipulate_text(window, cx, |text| {
11671            text.chars()
11672                .map(|c| match c {
11673                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11674                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11675                    _ => c,
11676                })
11677                .collect()
11678        })
11679    }
11680
11681    pub fn convert_to_rot47(
11682        &mut self,
11683        _: &ConvertToRot47,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.manipulate_text(window, cx, |text| {
11688            text.chars()
11689                .map(|c| {
11690                    let code_point = c as u32;
11691                    if code_point >= 33 && code_point <= 126 {
11692                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11693                    }
11694                    c
11695                })
11696                .collect()
11697        })
11698    }
11699
11700    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11701    where
11702        Fn: FnMut(&str) -> String,
11703    {
11704        let buffer = self.buffer.read(cx).snapshot(cx);
11705
11706        let mut new_selections = Vec::new();
11707        let mut edits = Vec::new();
11708        let mut selection_adjustment = 0i32;
11709
11710        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11711            let selection_is_empty = selection.is_empty();
11712
11713            let (start, end) = if selection_is_empty {
11714                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11715                (word_range.start, word_range.end)
11716            } else {
11717                (
11718                    buffer.point_to_offset(selection.start),
11719                    buffer.point_to_offset(selection.end),
11720                )
11721            };
11722
11723            let text = buffer.text_for_range(start..end).collect::<String>();
11724            let old_length = text.len() as i32;
11725            let text = callback(&text);
11726
11727            new_selections.push(Selection {
11728                start: (start as i32 - selection_adjustment) as usize,
11729                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11730                goal: SelectionGoal::None,
11731                id: selection.id,
11732                reversed: selection.reversed,
11733            });
11734
11735            selection_adjustment += old_length - text.len() as i32;
11736
11737            edits.push((start..end, text));
11738        }
11739
11740        self.transact(window, cx, |this, window, cx| {
11741            this.buffer.update(cx, |buffer, cx| {
11742                buffer.edit(edits, None, cx);
11743            });
11744
11745            this.change_selections(Default::default(), window, cx, |s| {
11746                s.select(new_selections);
11747            });
11748
11749            this.request_autoscroll(Autoscroll::fit(), cx);
11750        });
11751    }
11752
11753    pub fn move_selection_on_drop(
11754        &mut self,
11755        selection: &Selection<Anchor>,
11756        target: DisplayPoint,
11757        is_cut: bool,
11758        window: &mut Window,
11759        cx: &mut Context<Self>,
11760    ) {
11761        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11762        let buffer = display_map.buffer_snapshot();
11763        let mut edits = Vec::new();
11764        let insert_point = display_map
11765            .clip_point(target, Bias::Left)
11766            .to_point(&display_map);
11767        let text = buffer
11768            .text_for_range(selection.start..selection.end)
11769            .collect::<String>();
11770        if is_cut {
11771            edits.push(((selection.start..selection.end), String::new()));
11772        }
11773        let insert_anchor = buffer.anchor_before(insert_point);
11774        edits.push(((insert_anchor..insert_anchor), text));
11775        let last_edit_start = insert_anchor.bias_left(buffer);
11776        let last_edit_end = insert_anchor.bias_right(buffer);
11777        self.transact(window, cx, |this, window, cx| {
11778            this.buffer.update(cx, |buffer, cx| {
11779                buffer.edit(edits, None, cx);
11780            });
11781            this.change_selections(Default::default(), window, cx, |s| {
11782                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11783            });
11784        });
11785    }
11786
11787    pub fn clear_selection_drag_state(&mut self) {
11788        self.selection_drag_state = SelectionDragState::None;
11789    }
11790
11791    pub fn duplicate(
11792        &mut self,
11793        upwards: bool,
11794        whole_lines: bool,
11795        window: &mut Window,
11796        cx: &mut Context<Self>,
11797    ) {
11798        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11799
11800        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11801        let buffer = display_map.buffer_snapshot();
11802        let selections = self.selections.all::<Point>(&display_map);
11803
11804        let mut edits = Vec::new();
11805        let mut selections_iter = selections.iter().peekable();
11806        while let Some(selection) = selections_iter.next() {
11807            let mut rows = selection.spanned_rows(false, &display_map);
11808            // duplicate line-wise
11809            if whole_lines || selection.start == selection.end {
11810                // Avoid duplicating the same lines twice.
11811                while let Some(next_selection) = selections_iter.peek() {
11812                    let next_rows = next_selection.spanned_rows(false, &display_map);
11813                    if next_rows.start < rows.end {
11814                        rows.end = next_rows.end;
11815                        selections_iter.next().unwrap();
11816                    } else {
11817                        break;
11818                    }
11819                }
11820
11821                // Copy the text from the selected row region and splice it either at the start
11822                // or end of the region.
11823                let start = Point::new(rows.start.0, 0);
11824                let end = Point::new(
11825                    rows.end.previous_row().0,
11826                    buffer.line_len(rows.end.previous_row()),
11827                );
11828
11829                let mut text = buffer.text_for_range(start..end).collect::<String>();
11830
11831                let insert_location = if upwards {
11832                    // When duplicating upward, we need to insert before the current line.
11833                    // If we're on the last line and it doesn't end with a newline,
11834                    // we need to add a newline before the duplicated content.
11835                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11836                        && buffer.max_point().column > 0
11837                        && !text.ends_with('\n');
11838
11839                    if needs_leading_newline {
11840                        text.insert(0, '\n');
11841                        end
11842                    } else {
11843                        text.push('\n');
11844                        Point::new(rows.start.0, 0)
11845                    }
11846                } else {
11847                    text.push('\n');
11848                    start
11849                };
11850                edits.push((insert_location..insert_location, text));
11851            } else {
11852                // duplicate character-wise
11853                let start = selection.start;
11854                let end = selection.end;
11855                let text = buffer.text_for_range(start..end).collect::<String>();
11856                edits.push((selection.end..selection.end, text));
11857            }
11858        }
11859
11860        self.transact(window, cx, |this, window, cx| {
11861            this.buffer.update(cx, |buffer, cx| {
11862                buffer.edit(edits, None, cx);
11863            });
11864
11865            // When duplicating upward with whole lines, move the cursor to the duplicated line
11866            if upwards && whole_lines {
11867                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11868
11869                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11870                    let mut new_ranges = Vec::new();
11871                    let selections = s.all::<Point>(&display_map);
11872                    let mut selections_iter = selections.iter().peekable();
11873
11874                    while let Some(first_selection) = selections_iter.next() {
11875                        // Group contiguous selections together to find the total row span
11876                        let mut group_selections = vec![first_selection];
11877                        let mut rows = first_selection.spanned_rows(false, &display_map);
11878
11879                        while let Some(next_selection) = selections_iter.peek() {
11880                            let next_rows = next_selection.spanned_rows(false, &display_map);
11881                            if next_rows.start < rows.end {
11882                                rows.end = next_rows.end;
11883                                group_selections.push(selections_iter.next().unwrap());
11884                            } else {
11885                                break;
11886                            }
11887                        }
11888
11889                        let row_count = rows.end.0 - rows.start.0;
11890
11891                        // Move all selections in this group up by the total number of duplicated rows
11892                        for selection in group_selections {
11893                            let new_start = Point::new(
11894                                selection.start.row.saturating_sub(row_count),
11895                                selection.start.column,
11896                            );
11897
11898                            let new_end = Point::new(
11899                                selection.end.row.saturating_sub(row_count),
11900                                selection.end.column,
11901                            );
11902
11903                            new_ranges.push(new_start..new_end);
11904                        }
11905                    }
11906
11907                    s.select_ranges(new_ranges);
11908                });
11909            }
11910
11911            this.request_autoscroll(Autoscroll::fit(), cx);
11912        });
11913    }
11914
11915    pub fn duplicate_line_up(
11916        &mut self,
11917        _: &DuplicateLineUp,
11918        window: &mut Window,
11919        cx: &mut Context<Self>,
11920    ) {
11921        self.duplicate(true, true, window, cx);
11922    }
11923
11924    pub fn duplicate_line_down(
11925        &mut self,
11926        _: &DuplicateLineDown,
11927        window: &mut Window,
11928        cx: &mut Context<Self>,
11929    ) {
11930        self.duplicate(false, true, window, cx);
11931    }
11932
11933    pub fn duplicate_selection(
11934        &mut self,
11935        _: &DuplicateSelection,
11936        window: &mut Window,
11937        cx: &mut Context<Self>,
11938    ) {
11939        self.duplicate(false, false, window, cx);
11940    }
11941
11942    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11944        if self.mode.is_single_line() {
11945            cx.propagate();
11946            return;
11947        }
11948
11949        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11950        let buffer = self.buffer.read(cx).snapshot(cx);
11951
11952        let mut edits = Vec::new();
11953        let mut unfold_ranges = Vec::new();
11954        let mut refold_creases = Vec::new();
11955
11956        let selections = self.selections.all::<Point>(&display_map);
11957        let mut selections = selections.iter().peekable();
11958        let mut contiguous_row_selections = Vec::new();
11959        let mut new_selections = Vec::new();
11960
11961        while let Some(selection) = selections.next() {
11962            // Find all the selections that span a contiguous row range
11963            let (start_row, end_row) = consume_contiguous_rows(
11964                &mut contiguous_row_selections,
11965                selection,
11966                &display_map,
11967                &mut selections,
11968            );
11969
11970            // Move the text spanned by the row range to be before the line preceding the row range
11971            if start_row.0 > 0 {
11972                let range_to_move = Point::new(
11973                    start_row.previous_row().0,
11974                    buffer.line_len(start_row.previous_row()),
11975                )
11976                    ..Point::new(
11977                        end_row.previous_row().0,
11978                        buffer.line_len(end_row.previous_row()),
11979                    );
11980                let insertion_point = display_map
11981                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11982                    .0;
11983
11984                // Don't move lines across excerpts
11985                if buffer
11986                    .excerpt_containing(insertion_point..range_to_move.end)
11987                    .is_some()
11988                {
11989                    let text = buffer
11990                        .text_for_range(range_to_move.clone())
11991                        .flat_map(|s| s.chars())
11992                        .skip(1)
11993                        .chain(['\n'])
11994                        .collect::<String>();
11995
11996                    edits.push((
11997                        buffer.anchor_after(range_to_move.start)
11998                            ..buffer.anchor_before(range_to_move.end),
11999                        String::new(),
12000                    ));
12001                    let insertion_anchor = buffer.anchor_after(insertion_point);
12002                    edits.push((insertion_anchor..insertion_anchor, text));
12003
12004                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12005
12006                    // Move selections up
12007                    new_selections.extend(contiguous_row_selections.drain(..).map(
12008                        |mut selection| {
12009                            selection.start.row -= row_delta;
12010                            selection.end.row -= row_delta;
12011                            selection
12012                        },
12013                    ));
12014
12015                    // Move folds up
12016                    unfold_ranges.push(range_to_move.clone());
12017                    for fold in display_map.folds_in_range(
12018                        buffer.anchor_before(range_to_move.start)
12019                            ..buffer.anchor_after(range_to_move.end),
12020                    ) {
12021                        let mut start = fold.range.start.to_point(&buffer);
12022                        let mut end = fold.range.end.to_point(&buffer);
12023                        start.row -= row_delta;
12024                        end.row -= row_delta;
12025                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12026                    }
12027                }
12028            }
12029
12030            // If we didn't move line(s), preserve the existing selections
12031            new_selections.append(&mut contiguous_row_selections);
12032        }
12033
12034        self.transact(window, cx, |this, window, cx| {
12035            this.unfold_ranges(&unfold_ranges, true, true, cx);
12036            this.buffer.update(cx, |buffer, cx| {
12037                for (range, text) in edits {
12038                    buffer.edit([(range, text)], None, cx);
12039                }
12040            });
12041            this.fold_creases(refold_creases, true, window, cx);
12042            this.change_selections(Default::default(), window, cx, |s| {
12043                s.select(new_selections);
12044            })
12045        });
12046    }
12047
12048    pub fn move_line_down(
12049        &mut self,
12050        _: &MoveLineDown,
12051        window: &mut Window,
12052        cx: &mut Context<Self>,
12053    ) {
12054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12055        if self.mode.is_single_line() {
12056            cx.propagate();
12057            return;
12058        }
12059
12060        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12061        let buffer = self.buffer.read(cx).snapshot(cx);
12062
12063        let mut edits = Vec::new();
12064        let mut unfold_ranges = Vec::new();
12065        let mut refold_creases = Vec::new();
12066
12067        let selections = self.selections.all::<Point>(&display_map);
12068        let mut selections = selections.iter().peekable();
12069        let mut contiguous_row_selections = Vec::new();
12070        let mut new_selections = Vec::new();
12071
12072        while let Some(selection) = selections.next() {
12073            // Find all the selections that span a contiguous row range
12074            let (start_row, end_row) = consume_contiguous_rows(
12075                &mut contiguous_row_selections,
12076                selection,
12077                &display_map,
12078                &mut selections,
12079            );
12080
12081            // Move the text spanned by the row range to be after the last line of the row range
12082            if end_row.0 <= buffer.max_point().row {
12083                let range_to_move =
12084                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12085                let insertion_point = display_map
12086                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12087                    .0;
12088
12089                // Don't move lines across excerpt boundaries
12090                if buffer
12091                    .excerpt_containing(range_to_move.start..insertion_point)
12092                    .is_some()
12093                {
12094                    let mut text = String::from("\n");
12095                    text.extend(buffer.text_for_range(range_to_move.clone()));
12096                    text.pop(); // Drop trailing newline
12097                    edits.push((
12098                        buffer.anchor_after(range_to_move.start)
12099                            ..buffer.anchor_before(range_to_move.end),
12100                        String::new(),
12101                    ));
12102                    let insertion_anchor = buffer.anchor_after(insertion_point);
12103                    edits.push((insertion_anchor..insertion_anchor, text));
12104
12105                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12106
12107                    // Move selections down
12108                    new_selections.extend(contiguous_row_selections.drain(..).map(
12109                        |mut selection| {
12110                            selection.start.row += row_delta;
12111                            selection.end.row += row_delta;
12112                            selection
12113                        },
12114                    ));
12115
12116                    // Move folds down
12117                    unfold_ranges.push(range_to_move.clone());
12118                    for fold in display_map.folds_in_range(
12119                        buffer.anchor_before(range_to_move.start)
12120                            ..buffer.anchor_after(range_to_move.end),
12121                    ) {
12122                        let mut start = fold.range.start.to_point(&buffer);
12123                        let mut end = fold.range.end.to_point(&buffer);
12124                        start.row += row_delta;
12125                        end.row += row_delta;
12126                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12127                    }
12128                }
12129            }
12130
12131            // If we didn't move line(s), preserve the existing selections
12132            new_selections.append(&mut contiguous_row_selections);
12133        }
12134
12135        self.transact(window, cx, |this, window, cx| {
12136            this.unfold_ranges(&unfold_ranges, true, true, cx);
12137            this.buffer.update(cx, |buffer, cx| {
12138                for (range, text) in edits {
12139                    buffer.edit([(range, text)], None, cx);
12140                }
12141            });
12142            this.fold_creases(refold_creases, true, window, cx);
12143            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12144        });
12145    }
12146
12147    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12149        let text_layout_details = &self.text_layout_details(window);
12150        self.transact(window, cx, |this, window, cx| {
12151            let edits = this.change_selections(Default::default(), window, cx, |s| {
12152                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12153                s.move_with(|display_map, selection| {
12154                    if !selection.is_empty() {
12155                        return;
12156                    }
12157
12158                    let mut head = selection.head();
12159                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12160                    if head.column() == display_map.line_len(head.row()) {
12161                        transpose_offset = display_map
12162                            .buffer_snapshot()
12163                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12164                    }
12165
12166                    if transpose_offset == 0 {
12167                        return;
12168                    }
12169
12170                    *head.column_mut() += 1;
12171                    head = display_map.clip_point(head, Bias::Right);
12172                    let goal = SelectionGoal::HorizontalPosition(
12173                        display_map
12174                            .x_for_display_point(head, text_layout_details)
12175                            .into(),
12176                    );
12177                    selection.collapse_to(head, goal);
12178
12179                    let transpose_start = display_map
12180                        .buffer_snapshot()
12181                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12182                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12183                        let transpose_end = display_map
12184                            .buffer_snapshot()
12185                            .clip_offset(transpose_offset + 1, Bias::Right);
12186                        if let Some(ch) = display_map
12187                            .buffer_snapshot()
12188                            .chars_at(transpose_start)
12189                            .next()
12190                        {
12191                            edits.push((transpose_start..transpose_offset, String::new()));
12192                            edits.push((transpose_end..transpose_end, ch.to_string()));
12193                        }
12194                    }
12195                });
12196                edits
12197            });
12198            this.buffer
12199                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12200            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12201            this.change_selections(Default::default(), window, cx, |s| {
12202                s.select(selections);
12203            });
12204        });
12205    }
12206
12207    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12208        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12209        if self.mode.is_single_line() {
12210            cx.propagate();
12211            return;
12212        }
12213
12214        self.rewrap_impl(RewrapOptions::default(), cx)
12215    }
12216
12217    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12218        let buffer = self.buffer.read(cx).snapshot(cx);
12219        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12220
12221        #[derive(Clone, Debug, PartialEq)]
12222        enum CommentFormat {
12223            /// single line comment, with prefix for line
12224            Line(String),
12225            /// single line within a block comment, with prefix for line
12226            BlockLine(String),
12227            /// a single line of a block comment that includes the initial delimiter
12228            BlockCommentWithStart(BlockCommentConfig),
12229            /// a single line of a block comment that includes the ending delimiter
12230            BlockCommentWithEnd(BlockCommentConfig),
12231        }
12232
12233        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12234        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12235            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12236                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12237                .peekable();
12238
12239            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12240                row
12241            } else {
12242                return Vec::new();
12243            };
12244
12245            let language_settings = buffer.language_settings_at(selection.head(), cx);
12246            let language_scope = buffer.language_scope_at(selection.head());
12247
12248            let indent_and_prefix_for_row =
12249                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12250                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12251                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12252                        &language_scope
12253                    {
12254                        let indent_end = Point::new(row, indent.len);
12255                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12256                        let line_text_after_indent = buffer
12257                            .text_for_range(indent_end..line_end)
12258                            .collect::<String>();
12259
12260                        let is_within_comment_override = buffer
12261                            .language_scope_at(indent_end)
12262                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12263                        let comment_delimiters = if is_within_comment_override {
12264                            // we are within a comment syntax node, but we don't
12265                            // yet know what kind of comment: block, doc or line
12266                            match (
12267                                language_scope.documentation_comment(),
12268                                language_scope.block_comment(),
12269                            ) {
12270                                (Some(config), _) | (_, Some(config))
12271                                    if buffer.contains_str_at(indent_end, &config.start) =>
12272                                {
12273                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12274                                }
12275                                (Some(config), _) | (_, Some(config))
12276                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12277                                {
12278                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12279                                }
12280                                (Some(config), _) | (_, Some(config))
12281                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12282                                {
12283                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12284                                }
12285                                (_, _) => language_scope
12286                                    .line_comment_prefixes()
12287                                    .iter()
12288                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12289                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12290                            }
12291                        } else {
12292                            // we not in an overridden comment node, but we may
12293                            // be within a non-overridden line comment node
12294                            language_scope
12295                                .line_comment_prefixes()
12296                                .iter()
12297                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12298                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12299                        };
12300
12301                        let rewrap_prefix = language_scope
12302                            .rewrap_prefixes()
12303                            .iter()
12304                            .find_map(|prefix_regex| {
12305                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12306                                    if mat.start() == 0 {
12307                                        Some(mat.as_str().to_string())
12308                                    } else {
12309                                        None
12310                                    }
12311                                })
12312                            })
12313                            .flatten();
12314                        (comment_delimiters, rewrap_prefix)
12315                    } else {
12316                        (None, None)
12317                    };
12318                    (indent, comment_prefix, rewrap_prefix)
12319                };
12320
12321            let mut ranges = Vec::new();
12322            let from_empty_selection = selection.is_empty();
12323
12324            let mut current_range_start = first_row;
12325            let mut prev_row = first_row;
12326            let (
12327                mut current_range_indent,
12328                mut current_range_comment_delimiters,
12329                mut current_range_rewrap_prefix,
12330            ) = indent_and_prefix_for_row(first_row);
12331
12332            for row in non_blank_rows_iter.skip(1) {
12333                let has_paragraph_break = row > prev_row + 1;
12334
12335                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12336                    indent_and_prefix_for_row(row);
12337
12338                let has_indent_change = row_indent != current_range_indent;
12339                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12340
12341                let has_boundary_change = has_comment_change
12342                    || row_rewrap_prefix.is_some()
12343                    || (has_indent_change && current_range_comment_delimiters.is_some());
12344
12345                if has_paragraph_break || has_boundary_change {
12346                    ranges.push((
12347                        language_settings.clone(),
12348                        Point::new(current_range_start, 0)
12349                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12350                        current_range_indent,
12351                        current_range_comment_delimiters.clone(),
12352                        current_range_rewrap_prefix.clone(),
12353                        from_empty_selection,
12354                    ));
12355                    current_range_start = row;
12356                    current_range_indent = row_indent;
12357                    current_range_comment_delimiters = row_comment_delimiters;
12358                    current_range_rewrap_prefix = row_rewrap_prefix;
12359                }
12360                prev_row = row;
12361            }
12362
12363            ranges.push((
12364                language_settings.clone(),
12365                Point::new(current_range_start, 0)
12366                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12367                current_range_indent,
12368                current_range_comment_delimiters,
12369                current_range_rewrap_prefix,
12370                from_empty_selection,
12371            ));
12372
12373            ranges
12374        });
12375
12376        let mut edits = Vec::new();
12377        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12378
12379        for (
12380            language_settings,
12381            wrap_range,
12382            mut indent_size,
12383            comment_prefix,
12384            rewrap_prefix,
12385            from_empty_selection,
12386        ) in wrap_ranges
12387        {
12388            let mut start_row = wrap_range.start.row;
12389            let mut end_row = wrap_range.end.row;
12390
12391            // Skip selections that overlap with a range that has already been rewrapped.
12392            let selection_range = start_row..end_row;
12393            if rewrapped_row_ranges
12394                .iter()
12395                .any(|range| range.overlaps(&selection_range))
12396            {
12397                continue;
12398            }
12399
12400            let tab_size = language_settings.tab_size;
12401
12402            let (line_prefix, inside_comment) = match &comment_prefix {
12403                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12404                    (Some(prefix.as_str()), true)
12405                }
12406                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12407                    (Some(prefix.as_ref()), true)
12408                }
12409                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12410                    start: _,
12411                    end: _,
12412                    prefix,
12413                    tab_size,
12414                })) => {
12415                    indent_size.len += tab_size;
12416                    (Some(prefix.as_ref()), true)
12417                }
12418                None => (None, false),
12419            };
12420            let indent_prefix = indent_size.chars().collect::<String>();
12421            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12422
12423            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12424                RewrapBehavior::InComments => inside_comment,
12425                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12426                RewrapBehavior::Anywhere => true,
12427            };
12428
12429            let should_rewrap = options.override_language_settings
12430                || allow_rewrap_based_on_language
12431                || self.hard_wrap.is_some();
12432            if !should_rewrap {
12433                continue;
12434            }
12435
12436            if from_empty_selection {
12437                'expand_upwards: while start_row > 0 {
12438                    let prev_row = start_row - 1;
12439                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12440                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12441                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12442                    {
12443                        start_row = prev_row;
12444                    } else {
12445                        break 'expand_upwards;
12446                    }
12447                }
12448
12449                'expand_downwards: while end_row < buffer.max_point().row {
12450                    let next_row = end_row + 1;
12451                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12452                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12453                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12454                    {
12455                        end_row = next_row;
12456                    } else {
12457                        break 'expand_downwards;
12458                    }
12459                }
12460            }
12461
12462            let start = Point::new(start_row, 0);
12463            let start_offset = ToOffset::to_offset(&start, &buffer);
12464            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12465            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12466            let mut first_line_delimiter = None;
12467            let mut last_line_delimiter = None;
12468            let Some(lines_without_prefixes) = selection_text
12469                .lines()
12470                .enumerate()
12471                .map(|(ix, line)| {
12472                    let line_trimmed = line.trim_start();
12473                    if rewrap_prefix.is_some() && ix > 0 {
12474                        Ok(line_trimmed)
12475                    } else if let Some(
12476                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12477                            start,
12478                            prefix,
12479                            end,
12480                            tab_size,
12481                        })
12482                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12483                            start,
12484                            prefix,
12485                            end,
12486                            tab_size,
12487                        }),
12488                    ) = &comment_prefix
12489                    {
12490                        let line_trimmed = line_trimmed
12491                            .strip_prefix(start.as_ref())
12492                            .map(|s| {
12493                                let mut indent_size = indent_size;
12494                                indent_size.len -= tab_size;
12495                                let indent_prefix: String = indent_size.chars().collect();
12496                                first_line_delimiter = Some((indent_prefix, start));
12497                                s.trim_start()
12498                            })
12499                            .unwrap_or(line_trimmed);
12500                        let line_trimmed = line_trimmed
12501                            .strip_suffix(end.as_ref())
12502                            .map(|s| {
12503                                last_line_delimiter = Some(end);
12504                                s.trim_end()
12505                            })
12506                            .unwrap_or(line_trimmed);
12507                        let line_trimmed = line_trimmed
12508                            .strip_prefix(prefix.as_ref())
12509                            .unwrap_or(line_trimmed);
12510                        Ok(line_trimmed)
12511                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12512                        line_trimmed.strip_prefix(prefix).with_context(|| {
12513                            format!("line did not start with prefix {prefix:?}: {line:?}")
12514                        })
12515                    } else {
12516                        line_trimmed
12517                            .strip_prefix(&line_prefix.trim_start())
12518                            .with_context(|| {
12519                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12520                            })
12521                    }
12522                })
12523                .collect::<Result<Vec<_>, _>>()
12524                .log_err()
12525            else {
12526                continue;
12527            };
12528
12529            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12530                buffer
12531                    .language_settings_at(Point::new(start_row, 0), cx)
12532                    .preferred_line_length as usize
12533            });
12534
12535            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12536                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12537            } else {
12538                line_prefix.clone()
12539            };
12540
12541            let wrapped_text = {
12542                let mut wrapped_text = wrap_with_prefix(
12543                    line_prefix,
12544                    subsequent_lines_prefix,
12545                    lines_without_prefixes.join("\n"),
12546                    wrap_column,
12547                    tab_size,
12548                    options.preserve_existing_whitespace,
12549                );
12550
12551                if let Some((indent, delimiter)) = first_line_delimiter {
12552                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12553                }
12554                if let Some(last_line) = last_line_delimiter {
12555                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12556                }
12557
12558                wrapped_text
12559            };
12560
12561            // TODO: should always use char-based diff while still supporting cursor behavior that
12562            // matches vim.
12563            let mut diff_options = DiffOptions::default();
12564            if options.override_language_settings {
12565                diff_options.max_word_diff_len = 0;
12566                diff_options.max_word_diff_line_count = 0;
12567            } else {
12568                diff_options.max_word_diff_len = usize::MAX;
12569                diff_options.max_word_diff_line_count = usize::MAX;
12570            }
12571
12572            for (old_range, new_text) in
12573                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12574            {
12575                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12576                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12577                edits.push((edit_start..edit_end, new_text));
12578            }
12579
12580            rewrapped_row_ranges.push(start_row..=end_row);
12581        }
12582
12583        self.buffer
12584            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12585    }
12586
12587    pub fn cut_common(
12588        &mut self,
12589        cut_no_selection_line: bool,
12590        window: &mut Window,
12591        cx: &mut Context<Self>,
12592    ) -> ClipboardItem {
12593        let mut text = String::new();
12594        let buffer = self.buffer.read(cx).snapshot(cx);
12595        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12596        let mut clipboard_selections = Vec::with_capacity(selections.len());
12597        {
12598            let max_point = buffer.max_point();
12599            let mut is_first = true;
12600            let mut prev_selection_was_entire_line = false;
12601            for selection in &mut selections {
12602                let is_entire_line =
12603                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12604                if is_entire_line {
12605                    selection.start = Point::new(selection.start.row, 0);
12606                    if !selection.is_empty() && selection.end.column == 0 {
12607                        selection.end = cmp::min(max_point, selection.end);
12608                    } else {
12609                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12610                    }
12611                    selection.goal = SelectionGoal::None;
12612                }
12613                if is_first {
12614                    is_first = false;
12615                } else if !prev_selection_was_entire_line {
12616                    text += "\n";
12617                }
12618                prev_selection_was_entire_line = is_entire_line;
12619                let mut len = 0;
12620                for chunk in buffer.text_for_range(selection.start..selection.end) {
12621                    text.push_str(chunk);
12622                    len += chunk.len();
12623                }
12624                clipboard_selections.push(ClipboardSelection {
12625                    len,
12626                    is_entire_line,
12627                    first_line_indent: buffer
12628                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12629                        .len,
12630                });
12631            }
12632        }
12633
12634        self.transact(window, cx, |this, window, cx| {
12635            this.change_selections(Default::default(), window, cx, |s| {
12636                s.select(selections);
12637            });
12638            this.insert("", window, cx);
12639        });
12640        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12641    }
12642
12643    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12644        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12645        let item = self.cut_common(true, window, cx);
12646        cx.write_to_clipboard(item);
12647    }
12648
12649    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12650        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12651        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12652            s.move_with(|snapshot, sel| {
12653                if sel.is_empty() {
12654                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12655                }
12656                if sel.is_empty() {
12657                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12658                }
12659            });
12660        });
12661        let item = self.cut_common(false, window, cx);
12662        cx.set_global(KillRing(item))
12663    }
12664
12665    pub fn kill_ring_yank(
12666        &mut self,
12667        _: &KillRingYank,
12668        window: &mut Window,
12669        cx: &mut Context<Self>,
12670    ) {
12671        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12672        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12673            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12674                (kill_ring.text().to_string(), kill_ring.metadata_json())
12675            } else {
12676                return;
12677            }
12678        } else {
12679            return;
12680        };
12681        self.do_paste(&text, metadata, false, window, cx);
12682    }
12683
12684    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12685        self.do_copy(true, cx);
12686    }
12687
12688    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12689        self.do_copy(false, cx);
12690    }
12691
12692    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12693        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12694        let buffer = self.buffer.read(cx).read(cx);
12695        let mut text = String::new();
12696
12697        let mut clipboard_selections = Vec::with_capacity(selections.len());
12698        {
12699            let max_point = buffer.max_point();
12700            let mut is_first = true;
12701            let mut prev_selection_was_entire_line = false;
12702            for selection in &selections {
12703                let mut start = selection.start;
12704                let mut end = selection.end;
12705                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12706                let mut add_trailing_newline = false;
12707                if is_entire_line {
12708                    start = Point::new(start.row, 0);
12709                    let next_line_start = Point::new(end.row + 1, 0);
12710                    if next_line_start <= max_point {
12711                        end = next_line_start;
12712                    } else {
12713                        // We're on the last line without a trailing newline.
12714                        // Copy to the end of the line and add a newline afterwards.
12715                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12716                        add_trailing_newline = true;
12717                    }
12718                }
12719
12720                let mut trimmed_selections = Vec::new();
12721                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12722                    let row = MultiBufferRow(start.row);
12723                    let first_indent = buffer.indent_size_for_line(row);
12724                    if first_indent.len == 0 || start.column > first_indent.len {
12725                        trimmed_selections.push(start..end);
12726                    } else {
12727                        trimmed_selections.push(
12728                            Point::new(row.0, first_indent.len)
12729                                ..Point::new(row.0, buffer.line_len(row)),
12730                        );
12731                        for row in start.row + 1..=end.row {
12732                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12733                            if row == end.row {
12734                                line_len = end.column;
12735                            }
12736                            if line_len == 0 {
12737                                trimmed_selections
12738                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12739                                continue;
12740                            }
12741                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12742                            if row_indent_size.len >= first_indent.len {
12743                                trimmed_selections.push(
12744                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12745                                );
12746                            } else {
12747                                trimmed_selections.clear();
12748                                trimmed_selections.push(start..end);
12749                                break;
12750                            }
12751                        }
12752                    }
12753                } else {
12754                    trimmed_selections.push(start..end);
12755                }
12756
12757                for trimmed_range in trimmed_selections {
12758                    if is_first {
12759                        is_first = false;
12760                    } else if !prev_selection_was_entire_line {
12761                        text += "\n";
12762                    }
12763                    prev_selection_was_entire_line = is_entire_line;
12764                    let mut len = 0;
12765                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12766                        text.push_str(chunk);
12767                        len += chunk.len();
12768                    }
12769                    if add_trailing_newline {
12770                        text.push('\n');
12771                        len += 1;
12772                    }
12773                    clipboard_selections.push(ClipboardSelection {
12774                        len,
12775                        is_entire_line,
12776                        first_line_indent: buffer
12777                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12778                            .len,
12779                    });
12780                }
12781            }
12782        }
12783
12784        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12785            text,
12786            clipboard_selections,
12787        ));
12788    }
12789
12790    pub fn do_paste(
12791        &mut self,
12792        text: &String,
12793        clipboard_selections: Option<Vec<ClipboardSelection>>,
12794        handle_entire_lines: bool,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        if self.read_only(cx) {
12799            return;
12800        }
12801
12802        let clipboard_text = Cow::Borrowed(text.as_str());
12803
12804        self.transact(window, cx, |this, window, cx| {
12805            let had_active_edit_prediction = this.has_active_edit_prediction();
12806            let display_map = this.display_snapshot(cx);
12807            let old_selections = this.selections.all::<usize>(&display_map);
12808            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12809
12810            if let Some(mut clipboard_selections) = clipboard_selections {
12811                let all_selections_were_entire_line =
12812                    clipboard_selections.iter().all(|s| s.is_entire_line);
12813                let first_selection_indent_column =
12814                    clipboard_selections.first().map(|s| s.first_line_indent);
12815                if clipboard_selections.len() != old_selections.len() {
12816                    clipboard_selections.drain(..);
12817                }
12818                let mut auto_indent_on_paste = true;
12819
12820                this.buffer.update(cx, |buffer, cx| {
12821                    let snapshot = buffer.read(cx);
12822                    auto_indent_on_paste = snapshot
12823                        .language_settings_at(cursor_offset, cx)
12824                        .auto_indent_on_paste;
12825
12826                    let mut start_offset = 0;
12827                    let mut edits = Vec::new();
12828                    let mut original_indent_columns = Vec::new();
12829                    for (ix, selection) in old_selections.iter().enumerate() {
12830                        let to_insert;
12831                        let entire_line;
12832                        let original_indent_column;
12833                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12834                            let end_offset = start_offset + clipboard_selection.len;
12835                            to_insert = &clipboard_text[start_offset..end_offset];
12836                            entire_line = clipboard_selection.is_entire_line;
12837                            start_offset = if entire_line {
12838                                end_offset
12839                            } else {
12840                                end_offset + 1
12841                            };
12842                            original_indent_column = Some(clipboard_selection.first_line_indent);
12843                        } else {
12844                            to_insert = &*clipboard_text;
12845                            entire_line = all_selections_were_entire_line;
12846                            original_indent_column = first_selection_indent_column
12847                        }
12848
12849                        let (range, to_insert) =
12850                            if selection.is_empty() && handle_entire_lines && entire_line {
12851                                // If the corresponding selection was empty when this slice of the
12852                                // clipboard text was written, then the entire line containing the
12853                                // selection was copied. If this selection is also currently empty,
12854                                // then paste the line before the current line of the buffer.
12855                                let column = selection.start.to_point(&snapshot).column as usize;
12856                                let line_start = selection.start - column;
12857                                (line_start..line_start, Cow::Borrowed(to_insert))
12858                            } else {
12859                                let language = snapshot.language_at(selection.head());
12860                                let range = selection.range();
12861                                if let Some(language) = language
12862                                    && language.name() == "Markdown".into()
12863                                {
12864                                    edit_for_markdown_paste(
12865                                        &snapshot,
12866                                        range,
12867                                        to_insert,
12868                                        url::Url::parse(to_insert).ok(),
12869                                    )
12870                                } else {
12871                                    (range, Cow::Borrowed(to_insert))
12872                                }
12873                            };
12874
12875                        edits.push((range, to_insert));
12876                        original_indent_columns.push(original_indent_column);
12877                    }
12878                    drop(snapshot);
12879
12880                    buffer.edit(
12881                        edits,
12882                        if auto_indent_on_paste {
12883                            Some(AutoindentMode::Block {
12884                                original_indent_columns,
12885                            })
12886                        } else {
12887                            None
12888                        },
12889                        cx,
12890                    );
12891                });
12892
12893                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12894                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12895            } else {
12896                let url = url::Url::parse(&clipboard_text).ok();
12897
12898                let auto_indent_mode = if !clipboard_text.is_empty() {
12899                    Some(AutoindentMode::Block {
12900                        original_indent_columns: Vec::new(),
12901                    })
12902                } else {
12903                    None
12904                };
12905
12906                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12907                    let snapshot = buffer.snapshot(cx);
12908
12909                    let anchors = old_selections
12910                        .iter()
12911                        .map(|s| {
12912                            let anchor = snapshot.anchor_after(s.head());
12913                            s.map(|_| anchor)
12914                        })
12915                        .collect::<Vec<_>>();
12916
12917                    let mut edits = Vec::new();
12918
12919                    for selection in old_selections.iter() {
12920                        let language = snapshot.language_at(selection.head());
12921                        let range = selection.range();
12922
12923                        let (edit_range, edit_text) = if let Some(language) = language
12924                            && language.name() == "Markdown".into()
12925                        {
12926                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12927                        } else {
12928                            (range, clipboard_text.clone())
12929                        };
12930
12931                        edits.push((edit_range, edit_text));
12932                    }
12933
12934                    drop(snapshot);
12935                    buffer.edit(edits, auto_indent_mode, cx);
12936
12937                    anchors
12938                });
12939
12940                this.change_selections(Default::default(), window, cx, |s| {
12941                    s.select_anchors(selection_anchors);
12942                });
12943            }
12944
12945            //   🤔                 |    ..     | show_in_menu |
12946            // | ..                  |   true        true
12947            // | had_edit_prediction |   false       true
12948
12949            let trigger_in_words =
12950                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12951
12952            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12953        });
12954    }
12955
12956    pub fn diff_clipboard_with_selection(
12957        &mut self,
12958        _: &DiffClipboardWithSelection,
12959        window: &mut Window,
12960        cx: &mut Context<Self>,
12961    ) {
12962        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12963
12964        if selections.is_empty() {
12965            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12966            return;
12967        };
12968
12969        let clipboard_text = match cx.read_from_clipboard() {
12970            Some(item) => match item.entries().first() {
12971                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12972                _ => None,
12973            },
12974            None => None,
12975        };
12976
12977        let Some(clipboard_text) = clipboard_text else {
12978            log::warn!("Clipboard doesn't contain text.");
12979            return;
12980        };
12981
12982        window.dispatch_action(
12983            Box::new(DiffClipboardWithSelectionData {
12984                clipboard_text,
12985                editor: cx.entity(),
12986            }),
12987            cx,
12988        );
12989    }
12990
12991    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12993        if let Some(item) = cx.read_from_clipboard() {
12994            let entries = item.entries();
12995
12996            match entries.first() {
12997                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12998                // of all the pasted entries.
12999                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13000                    .do_paste(
13001                        clipboard_string.text(),
13002                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13003                        true,
13004                        window,
13005                        cx,
13006                    ),
13007                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13008            }
13009        }
13010    }
13011
13012    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13013        if self.read_only(cx) {
13014            return;
13015        }
13016
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13018
13019        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13020            if let Some((selections, _)) =
13021                self.selection_history.transaction(transaction_id).cloned()
13022            {
13023                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13024                    s.select_anchors(selections.to_vec());
13025                });
13026            } else {
13027                log::error!(
13028                    "No entry in selection_history found for undo. \
13029                     This may correspond to a bug where undo does not update the selection. \
13030                     If this is occurring, please add details to \
13031                     https://github.com/zed-industries/zed/issues/22692"
13032                );
13033            }
13034            self.request_autoscroll(Autoscroll::fit(), cx);
13035            self.unmark_text(window, cx);
13036            self.refresh_edit_prediction(true, false, window, cx);
13037            cx.emit(EditorEvent::Edited { transaction_id });
13038            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13039        }
13040    }
13041
13042    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13043        if self.read_only(cx) {
13044            return;
13045        }
13046
13047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13048
13049        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13050            if let Some((_, Some(selections))) =
13051                self.selection_history.transaction(transaction_id).cloned()
13052            {
13053                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13054                    s.select_anchors(selections.to_vec());
13055                });
13056            } else {
13057                log::error!(
13058                    "No entry in selection_history found for redo. \
13059                     This may correspond to a bug where undo does not update the selection. \
13060                     If this is occurring, please add details to \
13061                     https://github.com/zed-industries/zed/issues/22692"
13062                );
13063            }
13064            self.request_autoscroll(Autoscroll::fit(), cx);
13065            self.unmark_text(window, cx);
13066            self.refresh_edit_prediction(true, false, window, cx);
13067            cx.emit(EditorEvent::Edited { transaction_id });
13068        }
13069    }
13070
13071    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13072        self.buffer
13073            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13074    }
13075
13076    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13077        self.buffer
13078            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13079    }
13080
13081    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13083        self.change_selections(Default::default(), window, cx, |s| {
13084            s.move_with(|map, selection| {
13085                let cursor = if selection.is_empty() {
13086                    movement::left(map, selection.start)
13087                } else {
13088                    selection.start
13089                };
13090                selection.collapse_to(cursor, SelectionGoal::None);
13091            });
13092        })
13093    }
13094
13095    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13097        self.change_selections(Default::default(), window, cx, |s| {
13098            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13099        })
13100    }
13101
13102    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13103        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13104        self.change_selections(Default::default(), window, cx, |s| {
13105            s.move_with(|map, selection| {
13106                let cursor = if selection.is_empty() {
13107                    movement::right(map, selection.end)
13108                } else {
13109                    selection.end
13110                };
13111                selection.collapse_to(cursor, SelectionGoal::None)
13112            });
13113        })
13114    }
13115
13116    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13118        self.change_selections(Default::default(), window, cx, |s| {
13119            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13120        });
13121    }
13122
13123    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13124        if self.take_rename(true, window, cx).is_some() {
13125            return;
13126        }
13127
13128        if self.mode.is_single_line() {
13129            cx.propagate();
13130            return;
13131        }
13132
13133        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13134
13135        let text_layout_details = &self.text_layout_details(window);
13136        let selection_count = self.selections.count();
13137        let first_selection = self.selections.first_anchor();
13138
13139        self.change_selections(Default::default(), window, cx, |s| {
13140            s.move_with(|map, selection| {
13141                if !selection.is_empty() {
13142                    selection.goal = SelectionGoal::None;
13143                }
13144                let (cursor, goal) = movement::up(
13145                    map,
13146                    selection.start,
13147                    selection.goal,
13148                    false,
13149                    text_layout_details,
13150                );
13151                selection.collapse_to(cursor, goal);
13152            });
13153        });
13154
13155        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13156        {
13157            cx.propagate();
13158        }
13159    }
13160
13161    pub fn move_up_by_lines(
13162        &mut self,
13163        action: &MoveUpByLines,
13164        window: &mut Window,
13165        cx: &mut Context<Self>,
13166    ) {
13167        if self.take_rename(true, window, cx).is_some() {
13168            return;
13169        }
13170
13171        if self.mode.is_single_line() {
13172            cx.propagate();
13173            return;
13174        }
13175
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13177
13178        let text_layout_details = &self.text_layout_details(window);
13179
13180        self.change_selections(Default::default(), window, cx, |s| {
13181            s.move_with(|map, selection| {
13182                if !selection.is_empty() {
13183                    selection.goal = SelectionGoal::None;
13184                }
13185                let (cursor, goal) = movement::up_by_rows(
13186                    map,
13187                    selection.start,
13188                    action.lines,
13189                    selection.goal,
13190                    false,
13191                    text_layout_details,
13192                );
13193                selection.collapse_to(cursor, goal);
13194            });
13195        })
13196    }
13197
13198    pub fn move_down_by_lines(
13199        &mut self,
13200        action: &MoveDownByLines,
13201        window: &mut Window,
13202        cx: &mut Context<Self>,
13203    ) {
13204        if self.take_rename(true, window, cx).is_some() {
13205            return;
13206        }
13207
13208        if self.mode.is_single_line() {
13209            cx.propagate();
13210            return;
13211        }
13212
13213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13214
13215        let text_layout_details = &self.text_layout_details(window);
13216
13217        self.change_selections(Default::default(), window, cx, |s| {
13218            s.move_with(|map, selection| {
13219                if !selection.is_empty() {
13220                    selection.goal = SelectionGoal::None;
13221                }
13222                let (cursor, goal) = movement::down_by_rows(
13223                    map,
13224                    selection.start,
13225                    action.lines,
13226                    selection.goal,
13227                    false,
13228                    text_layout_details,
13229                );
13230                selection.collapse_to(cursor, goal);
13231            });
13232        })
13233    }
13234
13235    pub fn select_down_by_lines(
13236        &mut self,
13237        action: &SelectDownByLines,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13242        let text_layout_details = &self.text_layout_details(window);
13243        self.change_selections(Default::default(), window, cx, |s| {
13244            s.move_heads_with(|map, head, goal| {
13245                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13246            })
13247        })
13248    }
13249
13250    pub fn select_up_by_lines(
13251        &mut self,
13252        action: &SelectUpByLines,
13253        window: &mut Window,
13254        cx: &mut Context<Self>,
13255    ) {
13256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13257        let text_layout_details = &self.text_layout_details(window);
13258        self.change_selections(Default::default(), window, cx, |s| {
13259            s.move_heads_with(|map, head, goal| {
13260                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13261            })
13262        })
13263    }
13264
13265    pub fn select_page_up(
13266        &mut self,
13267        _: &SelectPageUp,
13268        window: &mut Window,
13269        cx: &mut Context<Self>,
13270    ) {
13271        let Some(row_count) = self.visible_row_count() else {
13272            return;
13273        };
13274
13275        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13276
13277        let text_layout_details = &self.text_layout_details(window);
13278
13279        self.change_selections(Default::default(), window, cx, |s| {
13280            s.move_heads_with(|map, head, goal| {
13281                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13282            })
13283        })
13284    }
13285
13286    pub fn move_page_up(
13287        &mut self,
13288        action: &MovePageUp,
13289        window: &mut Window,
13290        cx: &mut Context<Self>,
13291    ) {
13292        if self.take_rename(true, window, cx).is_some() {
13293            return;
13294        }
13295
13296        if self
13297            .context_menu
13298            .borrow_mut()
13299            .as_mut()
13300            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13301            .unwrap_or(false)
13302        {
13303            return;
13304        }
13305
13306        if matches!(self.mode, EditorMode::SingleLine) {
13307            cx.propagate();
13308            return;
13309        }
13310
13311        let Some(row_count) = self.visible_row_count() else {
13312            return;
13313        };
13314
13315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13316
13317        let effects = if action.center_cursor {
13318            SelectionEffects::scroll(Autoscroll::center())
13319        } else {
13320            SelectionEffects::default()
13321        };
13322
13323        let text_layout_details = &self.text_layout_details(window);
13324
13325        self.change_selections(effects, window, cx, |s| {
13326            s.move_with(|map, selection| {
13327                if !selection.is_empty() {
13328                    selection.goal = SelectionGoal::None;
13329                }
13330                let (cursor, goal) = movement::up_by_rows(
13331                    map,
13332                    selection.end,
13333                    row_count,
13334                    selection.goal,
13335                    false,
13336                    text_layout_details,
13337                );
13338                selection.collapse_to(cursor, goal);
13339            });
13340        });
13341    }
13342
13343    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13345        let text_layout_details = &self.text_layout_details(window);
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.move_heads_with(|map, head, goal| {
13348                movement::up(map, head, goal, false, text_layout_details)
13349            })
13350        })
13351    }
13352
13353    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13354        self.take_rename(true, window, cx);
13355
13356        if self.mode.is_single_line() {
13357            cx.propagate();
13358            return;
13359        }
13360
13361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13362
13363        let text_layout_details = &self.text_layout_details(window);
13364        let selection_count = self.selections.count();
13365        let first_selection = self.selections.first_anchor();
13366
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_with(|map, selection| {
13369                if !selection.is_empty() {
13370                    selection.goal = SelectionGoal::None;
13371                }
13372                let (cursor, goal) = movement::down(
13373                    map,
13374                    selection.end,
13375                    selection.goal,
13376                    false,
13377                    text_layout_details,
13378                );
13379                selection.collapse_to(cursor, goal);
13380            });
13381        });
13382
13383        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13384        {
13385            cx.propagate();
13386        }
13387    }
13388
13389    pub fn select_page_down(
13390        &mut self,
13391        _: &SelectPageDown,
13392        window: &mut Window,
13393        cx: &mut Context<Self>,
13394    ) {
13395        let Some(row_count) = self.visible_row_count() else {
13396            return;
13397        };
13398
13399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13400
13401        let text_layout_details = &self.text_layout_details(window);
13402
13403        self.change_selections(Default::default(), window, cx, |s| {
13404            s.move_heads_with(|map, head, goal| {
13405                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13406            })
13407        })
13408    }
13409
13410    pub fn move_page_down(
13411        &mut self,
13412        action: &MovePageDown,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) {
13416        if self.take_rename(true, window, cx).is_some() {
13417            return;
13418        }
13419
13420        if self
13421            .context_menu
13422            .borrow_mut()
13423            .as_mut()
13424            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13425            .unwrap_or(false)
13426        {
13427            return;
13428        }
13429
13430        if matches!(self.mode, EditorMode::SingleLine) {
13431            cx.propagate();
13432            return;
13433        }
13434
13435        let Some(row_count) = self.visible_row_count() else {
13436            return;
13437        };
13438
13439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13440
13441        let effects = if action.center_cursor {
13442            SelectionEffects::scroll(Autoscroll::center())
13443        } else {
13444            SelectionEffects::default()
13445        };
13446
13447        let text_layout_details = &self.text_layout_details(window);
13448        self.change_selections(effects, window, cx, |s| {
13449            s.move_with(|map, selection| {
13450                if !selection.is_empty() {
13451                    selection.goal = SelectionGoal::None;
13452                }
13453                let (cursor, goal) = movement::down_by_rows(
13454                    map,
13455                    selection.end,
13456                    row_count,
13457                    selection.goal,
13458                    false,
13459                    text_layout_details,
13460                );
13461                selection.collapse_to(cursor, goal);
13462            });
13463        });
13464    }
13465
13466    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13468        let text_layout_details = &self.text_layout_details(window);
13469        self.change_selections(Default::default(), window, cx, |s| {
13470            s.move_heads_with(|map, head, goal| {
13471                movement::down(map, head, goal, false, text_layout_details)
13472            })
13473        });
13474    }
13475
13476    pub fn context_menu_first(
13477        &mut self,
13478        _: &ContextMenuFirst,
13479        window: &mut Window,
13480        cx: &mut Context<Self>,
13481    ) {
13482        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13483            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13484        }
13485    }
13486
13487    pub fn context_menu_prev(
13488        &mut self,
13489        _: &ContextMenuPrevious,
13490        window: &mut Window,
13491        cx: &mut Context<Self>,
13492    ) {
13493        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13494            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13495        }
13496    }
13497
13498    pub fn context_menu_next(
13499        &mut self,
13500        _: &ContextMenuNext,
13501        window: &mut Window,
13502        cx: &mut Context<Self>,
13503    ) {
13504        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13505            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13506        }
13507    }
13508
13509    pub fn context_menu_last(
13510        &mut self,
13511        _: &ContextMenuLast,
13512        window: &mut Window,
13513        cx: &mut Context<Self>,
13514    ) {
13515        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13516            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13517        }
13518    }
13519
13520    pub fn signature_help_prev(
13521        &mut self,
13522        _: &SignatureHelpPrevious,
13523        _: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        if let Some(popover) = self.signature_help_state.popover_mut() {
13527            if popover.current_signature == 0 {
13528                popover.current_signature = popover.signatures.len() - 1;
13529            } else {
13530                popover.current_signature -= 1;
13531            }
13532            cx.notify();
13533        }
13534    }
13535
13536    pub fn signature_help_next(
13537        &mut self,
13538        _: &SignatureHelpNext,
13539        _: &mut Window,
13540        cx: &mut Context<Self>,
13541    ) {
13542        if let Some(popover) = self.signature_help_state.popover_mut() {
13543            if popover.current_signature + 1 == popover.signatures.len() {
13544                popover.current_signature = 0;
13545            } else {
13546                popover.current_signature += 1;
13547            }
13548            cx.notify();
13549        }
13550    }
13551
13552    pub fn move_to_previous_word_start(
13553        &mut self,
13554        _: &MoveToPreviousWordStart,
13555        window: &mut Window,
13556        cx: &mut Context<Self>,
13557    ) {
13558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13559        self.change_selections(Default::default(), window, cx, |s| {
13560            s.move_cursors_with(|map, head, _| {
13561                (
13562                    movement::previous_word_start(map, head),
13563                    SelectionGoal::None,
13564                )
13565            });
13566        })
13567    }
13568
13569    pub fn move_to_previous_subword_start(
13570        &mut self,
13571        _: &MoveToPreviousSubwordStart,
13572        window: &mut Window,
13573        cx: &mut Context<Self>,
13574    ) {
13575        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13576        self.change_selections(Default::default(), window, cx, |s| {
13577            s.move_cursors_with(|map, head, _| {
13578                (
13579                    movement::previous_subword_start(map, head),
13580                    SelectionGoal::None,
13581                )
13582            });
13583        })
13584    }
13585
13586    pub fn select_to_previous_word_start(
13587        &mut self,
13588        _: &SelectToPreviousWordStart,
13589        window: &mut Window,
13590        cx: &mut Context<Self>,
13591    ) {
13592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13593        self.change_selections(Default::default(), window, cx, |s| {
13594            s.move_heads_with(|map, head, _| {
13595                (
13596                    movement::previous_word_start(map, head),
13597                    SelectionGoal::None,
13598                )
13599            });
13600        })
13601    }
13602
13603    pub fn select_to_previous_subword_start(
13604        &mut self,
13605        _: &SelectToPreviousSubwordStart,
13606        window: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13610        self.change_selections(Default::default(), window, cx, |s| {
13611            s.move_heads_with(|map, head, _| {
13612                (
13613                    movement::previous_subword_start(map, head),
13614                    SelectionGoal::None,
13615                )
13616            });
13617        })
13618    }
13619
13620    pub fn delete_to_previous_word_start(
13621        &mut self,
13622        action: &DeleteToPreviousWordStart,
13623        window: &mut Window,
13624        cx: &mut Context<Self>,
13625    ) {
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13627        self.transact(window, cx, |this, window, cx| {
13628            this.select_autoclose_pair(window, cx);
13629            this.change_selections(Default::default(), window, cx, |s| {
13630                s.move_with(|map, selection| {
13631                    if selection.is_empty() {
13632                        let mut cursor = if action.ignore_newlines {
13633                            movement::previous_word_start(map, selection.head())
13634                        } else {
13635                            movement::previous_word_start_or_newline(map, selection.head())
13636                        };
13637                        cursor = movement::adjust_greedy_deletion(
13638                            map,
13639                            selection.head(),
13640                            cursor,
13641                            action.ignore_brackets,
13642                        );
13643                        selection.set_head(cursor, SelectionGoal::None);
13644                    }
13645                });
13646            });
13647            this.insert("", window, cx);
13648        });
13649    }
13650
13651    pub fn delete_to_previous_subword_start(
13652        &mut self,
13653        _: &DeleteToPreviousSubwordStart,
13654        window: &mut Window,
13655        cx: &mut Context<Self>,
13656    ) {
13657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13658        self.transact(window, cx, |this, window, cx| {
13659            this.select_autoclose_pair(window, cx);
13660            this.change_selections(Default::default(), window, cx, |s| {
13661                s.move_with(|map, selection| {
13662                    if selection.is_empty() {
13663                        let mut cursor = movement::previous_subword_start(map, selection.head());
13664                        cursor =
13665                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13666                        selection.set_head(cursor, SelectionGoal::None);
13667                    }
13668                });
13669            });
13670            this.insert("", window, cx);
13671        });
13672    }
13673
13674    pub fn move_to_next_word_end(
13675        &mut self,
13676        _: &MoveToNextWordEnd,
13677        window: &mut Window,
13678        cx: &mut Context<Self>,
13679    ) {
13680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13681        self.change_selections(Default::default(), window, cx, |s| {
13682            s.move_cursors_with(|map, head, _| {
13683                (movement::next_word_end(map, head), SelectionGoal::None)
13684            });
13685        })
13686    }
13687
13688    pub fn move_to_next_subword_end(
13689        &mut self,
13690        _: &MoveToNextSubwordEnd,
13691        window: &mut Window,
13692        cx: &mut Context<Self>,
13693    ) {
13694        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13695        self.change_selections(Default::default(), window, cx, |s| {
13696            s.move_cursors_with(|map, head, _| {
13697                (movement::next_subword_end(map, head), SelectionGoal::None)
13698            });
13699        })
13700    }
13701
13702    pub fn select_to_next_word_end(
13703        &mut self,
13704        _: &SelectToNextWordEnd,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13709        self.change_selections(Default::default(), window, cx, |s| {
13710            s.move_heads_with(|map, head, _| {
13711                (movement::next_word_end(map, head), SelectionGoal::None)
13712            });
13713        })
13714    }
13715
13716    pub fn select_to_next_subword_end(
13717        &mut self,
13718        _: &SelectToNextSubwordEnd,
13719        window: &mut Window,
13720        cx: &mut Context<Self>,
13721    ) {
13722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13723        self.change_selections(Default::default(), window, cx, |s| {
13724            s.move_heads_with(|map, head, _| {
13725                (movement::next_subword_end(map, head), SelectionGoal::None)
13726            });
13727        })
13728    }
13729
13730    pub fn delete_to_next_word_end(
13731        &mut self,
13732        action: &DeleteToNextWordEnd,
13733        window: &mut Window,
13734        cx: &mut Context<Self>,
13735    ) {
13736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13737        self.transact(window, cx, |this, window, cx| {
13738            this.change_selections(Default::default(), window, cx, |s| {
13739                s.move_with(|map, selection| {
13740                    if selection.is_empty() {
13741                        let mut cursor = if action.ignore_newlines {
13742                            movement::next_word_end(map, selection.head())
13743                        } else {
13744                            movement::next_word_end_or_newline(map, selection.head())
13745                        };
13746                        cursor = movement::adjust_greedy_deletion(
13747                            map,
13748                            selection.head(),
13749                            cursor,
13750                            action.ignore_brackets,
13751                        );
13752                        selection.set_head(cursor, SelectionGoal::None);
13753                    }
13754                });
13755            });
13756            this.insert("", window, cx);
13757        });
13758    }
13759
13760    pub fn delete_to_next_subword_end(
13761        &mut self,
13762        _: &DeleteToNextSubwordEnd,
13763        window: &mut Window,
13764        cx: &mut Context<Self>,
13765    ) {
13766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13767        self.transact(window, cx, |this, window, cx| {
13768            this.change_selections(Default::default(), window, cx, |s| {
13769                s.move_with(|map, selection| {
13770                    if selection.is_empty() {
13771                        let mut cursor = movement::next_subword_end(map, selection.head());
13772                        cursor =
13773                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13774                        selection.set_head(cursor, SelectionGoal::None);
13775                    }
13776                });
13777            });
13778            this.insert("", window, cx);
13779        });
13780    }
13781
13782    pub fn move_to_beginning_of_line(
13783        &mut self,
13784        action: &MoveToBeginningOfLine,
13785        window: &mut Window,
13786        cx: &mut Context<Self>,
13787    ) {
13788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13789        self.change_selections(Default::default(), window, cx, |s| {
13790            s.move_cursors_with(|map, head, _| {
13791                (
13792                    movement::indented_line_beginning(
13793                        map,
13794                        head,
13795                        action.stop_at_soft_wraps,
13796                        action.stop_at_indent,
13797                    ),
13798                    SelectionGoal::None,
13799                )
13800            });
13801        })
13802    }
13803
13804    pub fn select_to_beginning_of_line(
13805        &mut self,
13806        action: &SelectToBeginningOfLine,
13807        window: &mut Window,
13808        cx: &mut Context<Self>,
13809    ) {
13810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13811        self.change_selections(Default::default(), window, cx, |s| {
13812            s.move_heads_with(|map, head, _| {
13813                (
13814                    movement::indented_line_beginning(
13815                        map,
13816                        head,
13817                        action.stop_at_soft_wraps,
13818                        action.stop_at_indent,
13819                    ),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        });
13824    }
13825
13826    pub fn delete_to_beginning_of_line(
13827        &mut self,
13828        action: &DeleteToBeginningOfLine,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13833        self.transact(window, cx, |this, window, cx| {
13834            this.change_selections(Default::default(), window, cx, |s| {
13835                s.move_with(|_, selection| {
13836                    selection.reversed = true;
13837                });
13838            });
13839
13840            this.select_to_beginning_of_line(
13841                &SelectToBeginningOfLine {
13842                    stop_at_soft_wraps: false,
13843                    stop_at_indent: action.stop_at_indent,
13844                },
13845                window,
13846                cx,
13847            );
13848            this.backspace(&Backspace, window, cx);
13849        });
13850    }
13851
13852    pub fn move_to_end_of_line(
13853        &mut self,
13854        action: &MoveToEndOfLine,
13855        window: &mut Window,
13856        cx: &mut Context<Self>,
13857    ) {
13858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13859        self.change_selections(Default::default(), window, cx, |s| {
13860            s.move_cursors_with(|map, head, _| {
13861                (
13862                    movement::line_end(map, head, action.stop_at_soft_wraps),
13863                    SelectionGoal::None,
13864                )
13865            });
13866        })
13867    }
13868
13869    pub fn select_to_end_of_line(
13870        &mut self,
13871        action: &SelectToEndOfLine,
13872        window: &mut Window,
13873        cx: &mut Context<Self>,
13874    ) {
13875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13876        self.change_selections(Default::default(), window, cx, |s| {
13877            s.move_heads_with(|map, head, _| {
13878                (
13879                    movement::line_end(map, head, action.stop_at_soft_wraps),
13880                    SelectionGoal::None,
13881                )
13882            });
13883        })
13884    }
13885
13886    pub fn delete_to_end_of_line(
13887        &mut self,
13888        _: &DeleteToEndOfLine,
13889        window: &mut Window,
13890        cx: &mut Context<Self>,
13891    ) {
13892        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13893        self.transact(window, cx, |this, window, cx| {
13894            this.select_to_end_of_line(
13895                &SelectToEndOfLine {
13896                    stop_at_soft_wraps: false,
13897                },
13898                window,
13899                cx,
13900            );
13901            this.delete(&Delete, window, cx);
13902        });
13903    }
13904
13905    pub fn cut_to_end_of_line(
13906        &mut self,
13907        action: &CutToEndOfLine,
13908        window: &mut Window,
13909        cx: &mut Context<Self>,
13910    ) {
13911        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13912        self.transact(window, cx, |this, window, cx| {
13913            this.select_to_end_of_line(
13914                &SelectToEndOfLine {
13915                    stop_at_soft_wraps: false,
13916                },
13917                window,
13918                cx,
13919            );
13920            if !action.stop_at_newlines {
13921                this.change_selections(Default::default(), window, cx, |s| {
13922                    s.move_with(|_, sel| {
13923                        if sel.is_empty() {
13924                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13925                        }
13926                    });
13927                });
13928            }
13929            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13930            let item = this.cut_common(false, window, cx);
13931            cx.write_to_clipboard(item);
13932        });
13933    }
13934
13935    pub fn move_to_start_of_paragraph(
13936        &mut self,
13937        _: &MoveToStartOfParagraph,
13938        window: &mut Window,
13939        cx: &mut Context<Self>,
13940    ) {
13941        if matches!(self.mode, EditorMode::SingleLine) {
13942            cx.propagate();
13943            return;
13944        }
13945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13946        self.change_selections(Default::default(), window, cx, |s| {
13947            s.move_with(|map, selection| {
13948                selection.collapse_to(
13949                    movement::start_of_paragraph(map, selection.head(), 1),
13950                    SelectionGoal::None,
13951                )
13952            });
13953        })
13954    }
13955
13956    pub fn move_to_end_of_paragraph(
13957        &mut self,
13958        _: &MoveToEndOfParagraph,
13959        window: &mut Window,
13960        cx: &mut Context<Self>,
13961    ) {
13962        if matches!(self.mode, EditorMode::SingleLine) {
13963            cx.propagate();
13964            return;
13965        }
13966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13967        self.change_selections(Default::default(), window, cx, |s| {
13968            s.move_with(|map, selection| {
13969                selection.collapse_to(
13970                    movement::end_of_paragraph(map, selection.head(), 1),
13971                    SelectionGoal::None,
13972                )
13973            });
13974        })
13975    }
13976
13977    pub fn select_to_start_of_paragraph(
13978        &mut self,
13979        _: &SelectToStartOfParagraph,
13980        window: &mut Window,
13981        cx: &mut Context<Self>,
13982    ) {
13983        if matches!(self.mode, EditorMode::SingleLine) {
13984            cx.propagate();
13985            return;
13986        }
13987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13988        self.change_selections(Default::default(), window, cx, |s| {
13989            s.move_heads_with(|map, head, _| {
13990                (
13991                    movement::start_of_paragraph(map, head, 1),
13992                    SelectionGoal::None,
13993                )
13994            });
13995        })
13996    }
13997
13998    pub fn select_to_end_of_paragraph(
13999        &mut self,
14000        _: &SelectToEndOfParagraph,
14001        window: &mut Window,
14002        cx: &mut Context<Self>,
14003    ) {
14004        if matches!(self.mode, EditorMode::SingleLine) {
14005            cx.propagate();
14006            return;
14007        }
14008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14009        self.change_selections(Default::default(), window, cx, |s| {
14010            s.move_heads_with(|map, head, _| {
14011                (
14012                    movement::end_of_paragraph(map, head, 1),
14013                    SelectionGoal::None,
14014                )
14015            });
14016        })
14017    }
14018
14019    pub fn move_to_start_of_excerpt(
14020        &mut self,
14021        _: &MoveToStartOfExcerpt,
14022        window: &mut Window,
14023        cx: &mut Context<Self>,
14024    ) {
14025        if matches!(self.mode, EditorMode::SingleLine) {
14026            cx.propagate();
14027            return;
14028        }
14029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14030        self.change_selections(Default::default(), window, cx, |s| {
14031            s.move_with(|map, selection| {
14032                selection.collapse_to(
14033                    movement::start_of_excerpt(
14034                        map,
14035                        selection.head(),
14036                        workspace::searchable::Direction::Prev,
14037                    ),
14038                    SelectionGoal::None,
14039                )
14040            });
14041        })
14042    }
14043
14044    pub fn move_to_start_of_next_excerpt(
14045        &mut self,
14046        _: &MoveToStartOfNextExcerpt,
14047        window: &mut Window,
14048        cx: &mut Context<Self>,
14049    ) {
14050        if matches!(self.mode, EditorMode::SingleLine) {
14051            cx.propagate();
14052            return;
14053        }
14054
14055        self.change_selections(Default::default(), window, cx, |s| {
14056            s.move_with(|map, selection| {
14057                selection.collapse_to(
14058                    movement::start_of_excerpt(
14059                        map,
14060                        selection.head(),
14061                        workspace::searchable::Direction::Next,
14062                    ),
14063                    SelectionGoal::None,
14064                )
14065            });
14066        })
14067    }
14068
14069    pub fn move_to_end_of_excerpt(
14070        &mut self,
14071        _: &MoveToEndOfExcerpt,
14072        window: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        if matches!(self.mode, EditorMode::SingleLine) {
14076            cx.propagate();
14077            return;
14078        }
14079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14080        self.change_selections(Default::default(), window, cx, |s| {
14081            s.move_with(|map, selection| {
14082                selection.collapse_to(
14083                    movement::end_of_excerpt(
14084                        map,
14085                        selection.head(),
14086                        workspace::searchable::Direction::Next,
14087                    ),
14088                    SelectionGoal::None,
14089                )
14090            });
14091        })
14092    }
14093
14094    pub fn move_to_end_of_previous_excerpt(
14095        &mut self,
14096        _: &MoveToEndOfPreviousExcerpt,
14097        window: &mut Window,
14098        cx: &mut Context<Self>,
14099    ) {
14100        if matches!(self.mode, EditorMode::SingleLine) {
14101            cx.propagate();
14102            return;
14103        }
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14105        self.change_selections(Default::default(), window, cx, |s| {
14106            s.move_with(|map, selection| {
14107                selection.collapse_to(
14108                    movement::end_of_excerpt(
14109                        map,
14110                        selection.head(),
14111                        workspace::searchable::Direction::Prev,
14112                    ),
14113                    SelectionGoal::None,
14114                )
14115            });
14116        })
14117    }
14118
14119    pub fn select_to_start_of_excerpt(
14120        &mut self,
14121        _: &SelectToStartOfExcerpt,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) {
14125        if matches!(self.mode, EditorMode::SingleLine) {
14126            cx.propagate();
14127            return;
14128        }
14129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14130        self.change_selections(Default::default(), window, cx, |s| {
14131            s.move_heads_with(|map, head, _| {
14132                (
14133                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14134                    SelectionGoal::None,
14135                )
14136            });
14137        })
14138    }
14139
14140    pub fn select_to_start_of_next_excerpt(
14141        &mut self,
14142        _: &SelectToStartOfNextExcerpt,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) {
14146        if matches!(self.mode, EditorMode::SingleLine) {
14147            cx.propagate();
14148            return;
14149        }
14150        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14151        self.change_selections(Default::default(), window, cx, |s| {
14152            s.move_heads_with(|map, head, _| {
14153                (
14154                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14155                    SelectionGoal::None,
14156                )
14157            });
14158        })
14159    }
14160
14161    pub fn select_to_end_of_excerpt(
14162        &mut self,
14163        _: &SelectToEndOfExcerpt,
14164        window: &mut Window,
14165        cx: &mut Context<Self>,
14166    ) {
14167        if matches!(self.mode, EditorMode::SingleLine) {
14168            cx.propagate();
14169            return;
14170        }
14171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14172        self.change_selections(Default::default(), window, cx, |s| {
14173            s.move_heads_with(|map, head, _| {
14174                (
14175                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14176                    SelectionGoal::None,
14177                )
14178            });
14179        })
14180    }
14181
14182    pub fn select_to_end_of_previous_excerpt(
14183        &mut self,
14184        _: &SelectToEndOfPreviousExcerpt,
14185        window: &mut Window,
14186        cx: &mut Context<Self>,
14187    ) {
14188        if matches!(self.mode, EditorMode::SingleLine) {
14189            cx.propagate();
14190            return;
14191        }
14192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14193        self.change_selections(Default::default(), window, cx, |s| {
14194            s.move_heads_with(|map, head, _| {
14195                (
14196                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14197                    SelectionGoal::None,
14198                )
14199            });
14200        })
14201    }
14202
14203    pub fn move_to_beginning(
14204        &mut self,
14205        _: &MoveToBeginning,
14206        window: &mut Window,
14207        cx: &mut Context<Self>,
14208    ) {
14209        if matches!(self.mode, EditorMode::SingleLine) {
14210            cx.propagate();
14211            return;
14212        }
14213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14214        self.change_selections(Default::default(), window, cx, |s| {
14215            s.select_ranges(vec![0..0]);
14216        });
14217    }
14218
14219    pub fn select_to_beginning(
14220        &mut self,
14221        _: &SelectToBeginning,
14222        window: &mut Window,
14223        cx: &mut Context<Self>,
14224    ) {
14225        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14226        selection.set_head(Point::zero(), SelectionGoal::None);
14227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14228        self.change_selections(Default::default(), window, cx, |s| {
14229            s.select(vec![selection]);
14230        });
14231    }
14232
14233    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14234        if matches!(self.mode, EditorMode::SingleLine) {
14235            cx.propagate();
14236            return;
14237        }
14238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14239        let cursor = self.buffer.read(cx).read(cx).len();
14240        self.change_selections(Default::default(), window, cx, |s| {
14241            s.select_ranges(vec![cursor..cursor])
14242        });
14243    }
14244
14245    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14246        self.nav_history = nav_history;
14247    }
14248
14249    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14250        self.nav_history.as_ref()
14251    }
14252
14253    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14254        self.push_to_nav_history(
14255            self.selections.newest_anchor().head(),
14256            None,
14257            false,
14258            true,
14259            cx,
14260        );
14261    }
14262
14263    fn push_to_nav_history(
14264        &mut self,
14265        cursor_anchor: Anchor,
14266        new_position: Option<Point>,
14267        is_deactivate: bool,
14268        always: bool,
14269        cx: &mut Context<Self>,
14270    ) {
14271        if let Some(nav_history) = self.nav_history.as_mut() {
14272            let buffer = self.buffer.read(cx).read(cx);
14273            let cursor_position = cursor_anchor.to_point(&buffer);
14274            let scroll_state = self.scroll_manager.anchor();
14275            let scroll_top_row = scroll_state.top_row(&buffer);
14276            drop(buffer);
14277
14278            if let Some(new_position) = new_position {
14279                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14280                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14281                    return;
14282                }
14283            }
14284
14285            nav_history.push(
14286                Some(NavigationData {
14287                    cursor_anchor,
14288                    cursor_position,
14289                    scroll_anchor: scroll_state,
14290                    scroll_top_row,
14291                }),
14292                cx,
14293            );
14294            cx.emit(EditorEvent::PushedToNavHistory {
14295                anchor: cursor_anchor,
14296                is_deactivate,
14297            })
14298        }
14299    }
14300
14301    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14303        let buffer = self.buffer.read(cx).snapshot(cx);
14304        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14305        selection.set_head(buffer.len(), SelectionGoal::None);
14306        self.change_selections(Default::default(), window, cx, |s| {
14307            s.select(vec![selection]);
14308        });
14309    }
14310
14311    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14313        let end = self.buffer.read(cx).read(cx).len();
14314        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14315            s.select_ranges(vec![0..end]);
14316        });
14317    }
14318
14319    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14321        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14322        let mut selections = self.selections.all::<Point>(&display_map);
14323        let max_point = display_map.buffer_snapshot().max_point();
14324        for selection in &mut selections {
14325            let rows = selection.spanned_rows(true, &display_map);
14326            selection.start = Point::new(rows.start.0, 0);
14327            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14328            selection.reversed = false;
14329        }
14330        self.change_selections(Default::default(), window, cx, |s| {
14331            s.select(selections);
14332        });
14333    }
14334
14335    pub fn split_selection_into_lines(
14336        &mut self,
14337        action: &SplitSelectionIntoLines,
14338        window: &mut Window,
14339        cx: &mut Context<Self>,
14340    ) {
14341        let selections = self
14342            .selections
14343            .all::<Point>(&self.display_snapshot(cx))
14344            .into_iter()
14345            .map(|selection| selection.start..selection.end)
14346            .collect::<Vec<_>>();
14347        self.unfold_ranges(&selections, true, true, cx);
14348
14349        let mut new_selection_ranges = Vec::new();
14350        {
14351            let buffer = self.buffer.read(cx).read(cx);
14352            for selection in selections {
14353                for row in selection.start.row..selection.end.row {
14354                    let line_start = Point::new(row, 0);
14355                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14356
14357                    if action.keep_selections {
14358                        // Keep the selection range for each line
14359                        let selection_start = if row == selection.start.row {
14360                            selection.start
14361                        } else {
14362                            line_start
14363                        };
14364                        new_selection_ranges.push(selection_start..line_end);
14365                    } else {
14366                        // Collapse to cursor at end of line
14367                        new_selection_ranges.push(line_end..line_end);
14368                    }
14369                }
14370
14371                let is_multiline_selection = selection.start.row != selection.end.row;
14372                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14373                // so this action feels more ergonomic when paired with other selection operations
14374                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14375                if !should_skip_last {
14376                    if action.keep_selections {
14377                        if is_multiline_selection {
14378                            let line_start = Point::new(selection.end.row, 0);
14379                            new_selection_ranges.push(line_start..selection.end);
14380                        } else {
14381                            new_selection_ranges.push(selection.start..selection.end);
14382                        }
14383                    } else {
14384                        new_selection_ranges.push(selection.end..selection.end);
14385                    }
14386                }
14387            }
14388        }
14389        self.change_selections(Default::default(), window, cx, |s| {
14390            s.select_ranges(new_selection_ranges);
14391        });
14392    }
14393
14394    pub fn add_selection_above(
14395        &mut self,
14396        action: &AddSelectionAbove,
14397        window: &mut Window,
14398        cx: &mut Context<Self>,
14399    ) {
14400        self.add_selection(true, action.skip_soft_wrap, window, cx);
14401    }
14402
14403    pub fn add_selection_below(
14404        &mut self,
14405        action: &AddSelectionBelow,
14406        window: &mut Window,
14407        cx: &mut Context<Self>,
14408    ) {
14409        self.add_selection(false, action.skip_soft_wrap, window, cx);
14410    }
14411
14412    fn add_selection(
14413        &mut self,
14414        above: bool,
14415        skip_soft_wrap: bool,
14416        window: &mut Window,
14417        cx: &mut Context<Self>,
14418    ) {
14419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14420
14421        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14422        let all_selections = self.selections.all::<Point>(&display_map);
14423        let text_layout_details = self.text_layout_details(window);
14424
14425        let (mut columnar_selections, new_selections_to_columnarize) = {
14426            if let Some(state) = self.add_selections_state.as_ref() {
14427                let columnar_selection_ids: HashSet<_> = state
14428                    .groups
14429                    .iter()
14430                    .flat_map(|group| group.stack.iter())
14431                    .copied()
14432                    .collect();
14433
14434                all_selections
14435                    .into_iter()
14436                    .partition(|s| columnar_selection_ids.contains(&s.id))
14437            } else {
14438                (Vec::new(), all_selections)
14439            }
14440        };
14441
14442        let mut state = self
14443            .add_selections_state
14444            .take()
14445            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14446
14447        for selection in new_selections_to_columnarize {
14448            let range = selection.display_range(&display_map).sorted();
14449            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14450            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14451            let positions = start_x.min(end_x)..start_x.max(end_x);
14452            let mut stack = Vec::new();
14453            for row in range.start.row().0..=range.end.row().0 {
14454                if let Some(selection) = self.selections.build_columnar_selection(
14455                    &display_map,
14456                    DisplayRow(row),
14457                    &positions,
14458                    selection.reversed,
14459                    &text_layout_details,
14460                ) {
14461                    stack.push(selection.id);
14462                    columnar_selections.push(selection);
14463                }
14464            }
14465            if !stack.is_empty() {
14466                if above {
14467                    stack.reverse();
14468                }
14469                state.groups.push(AddSelectionsGroup { above, stack });
14470            }
14471        }
14472
14473        let mut final_selections = Vec::new();
14474        let end_row = if above {
14475            DisplayRow(0)
14476        } else {
14477            display_map.max_point().row()
14478        };
14479
14480        let mut last_added_item_per_group = HashMap::default();
14481        for group in state.groups.iter_mut() {
14482            if let Some(last_id) = group.stack.last() {
14483                last_added_item_per_group.insert(*last_id, group);
14484            }
14485        }
14486
14487        for selection in columnar_selections {
14488            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14489                if above == group.above {
14490                    let range = selection.display_range(&display_map).sorted();
14491                    debug_assert_eq!(range.start.row(), range.end.row());
14492                    let mut row = range.start.row();
14493                    let positions =
14494                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14495                            Pixels::from(start)..Pixels::from(end)
14496                        } else {
14497                            let start_x =
14498                                display_map.x_for_display_point(range.start, &text_layout_details);
14499                            let end_x =
14500                                display_map.x_for_display_point(range.end, &text_layout_details);
14501                            start_x.min(end_x)..start_x.max(end_x)
14502                        };
14503
14504                    let mut maybe_new_selection = None;
14505                    let direction = if above { -1 } else { 1 };
14506
14507                    while row != end_row {
14508                        if skip_soft_wrap {
14509                            row = display_map
14510                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14511                                .row();
14512                        } else if above {
14513                            row.0 -= 1;
14514                        } else {
14515                            row.0 += 1;
14516                        }
14517
14518                        if let Some(new_selection) = self.selections.build_columnar_selection(
14519                            &display_map,
14520                            row,
14521                            &positions,
14522                            selection.reversed,
14523                            &text_layout_details,
14524                        ) {
14525                            maybe_new_selection = Some(new_selection);
14526                            break;
14527                        }
14528                    }
14529
14530                    if let Some(new_selection) = maybe_new_selection {
14531                        group.stack.push(new_selection.id);
14532                        if above {
14533                            final_selections.push(new_selection);
14534                            final_selections.push(selection);
14535                        } else {
14536                            final_selections.push(selection);
14537                            final_selections.push(new_selection);
14538                        }
14539                    } else {
14540                        final_selections.push(selection);
14541                    }
14542                } else {
14543                    group.stack.pop();
14544                }
14545            } else {
14546                final_selections.push(selection);
14547            }
14548        }
14549
14550        self.change_selections(Default::default(), window, cx, |s| {
14551            s.select(final_selections);
14552        });
14553
14554        let final_selection_ids: HashSet<_> = self
14555            .selections
14556            .all::<Point>(&display_map)
14557            .iter()
14558            .map(|s| s.id)
14559            .collect();
14560        state.groups.retain_mut(|group| {
14561            // selections might get merged above so we remove invalid items from stacks
14562            group.stack.retain(|id| final_selection_ids.contains(id));
14563
14564            // single selection in stack can be treated as initial state
14565            group.stack.len() > 1
14566        });
14567
14568        if !state.groups.is_empty() {
14569            self.add_selections_state = Some(state);
14570        }
14571    }
14572
14573    fn select_match_ranges(
14574        &mut self,
14575        range: Range<usize>,
14576        reversed: bool,
14577        replace_newest: bool,
14578        auto_scroll: Option<Autoscroll>,
14579        window: &mut Window,
14580        cx: &mut Context<Editor>,
14581    ) {
14582        self.unfold_ranges(
14583            std::slice::from_ref(&range),
14584            false,
14585            auto_scroll.is_some(),
14586            cx,
14587        );
14588        let effects = if let Some(scroll) = auto_scroll {
14589            SelectionEffects::scroll(scroll)
14590        } else {
14591            SelectionEffects::no_scroll()
14592        };
14593        self.change_selections(effects, window, cx, |s| {
14594            if replace_newest {
14595                s.delete(s.newest_anchor().id);
14596            }
14597            if reversed {
14598                s.insert_range(range.end..range.start);
14599            } else {
14600                s.insert_range(range);
14601            }
14602        });
14603    }
14604
14605    pub fn select_next_match_internal(
14606        &mut self,
14607        display_map: &DisplaySnapshot,
14608        replace_newest: bool,
14609        autoscroll: Option<Autoscroll>,
14610        window: &mut Window,
14611        cx: &mut Context<Self>,
14612    ) -> Result<()> {
14613        let buffer = display_map.buffer_snapshot();
14614        let mut selections = self.selections.all::<usize>(&display_map);
14615        if let Some(mut select_next_state) = self.select_next_state.take() {
14616            let query = &select_next_state.query;
14617            if !select_next_state.done {
14618                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14619                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14620                let mut next_selected_range = None;
14621
14622                let bytes_after_last_selection =
14623                    buffer.bytes_in_range(last_selection.end..buffer.len());
14624                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14625                let query_matches = query
14626                    .stream_find_iter(bytes_after_last_selection)
14627                    .map(|result| (last_selection.end, result))
14628                    .chain(
14629                        query
14630                            .stream_find_iter(bytes_before_first_selection)
14631                            .map(|result| (0, result)),
14632                    );
14633
14634                for (start_offset, query_match) in query_matches {
14635                    let query_match = query_match.unwrap(); // can only fail due to I/O
14636                    let offset_range =
14637                        start_offset + query_match.start()..start_offset + query_match.end();
14638
14639                    if !select_next_state.wordwise
14640                        || (!buffer.is_inside_word(offset_range.start, None)
14641                            && !buffer.is_inside_word(offset_range.end, None))
14642                    {
14643                        let idx = selections
14644                            .partition_point(|selection| selection.end <= offset_range.start);
14645                        let overlaps = selections
14646                            .get(idx)
14647                            .map_or(false, |selection| selection.start < offset_range.end);
14648
14649                        if !overlaps {
14650                            next_selected_range = Some(offset_range);
14651                            break;
14652                        }
14653                    }
14654                }
14655
14656                if let Some(next_selected_range) = next_selected_range {
14657                    self.select_match_ranges(
14658                        next_selected_range,
14659                        last_selection.reversed,
14660                        replace_newest,
14661                        autoscroll,
14662                        window,
14663                        cx,
14664                    );
14665                } else {
14666                    select_next_state.done = true;
14667                }
14668            }
14669
14670            self.select_next_state = Some(select_next_state);
14671        } else {
14672            let mut only_carets = true;
14673            let mut same_text_selected = true;
14674            let mut selected_text = None;
14675
14676            let mut selections_iter = selections.iter().peekable();
14677            while let Some(selection) = selections_iter.next() {
14678                if selection.start != selection.end {
14679                    only_carets = false;
14680                }
14681
14682                if same_text_selected {
14683                    if selected_text.is_none() {
14684                        selected_text =
14685                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14686                    }
14687
14688                    if let Some(next_selection) = selections_iter.peek() {
14689                        if next_selection.range().len() == selection.range().len() {
14690                            let next_selected_text = buffer
14691                                .text_for_range(next_selection.range())
14692                                .collect::<String>();
14693                            if Some(next_selected_text) != selected_text {
14694                                same_text_selected = false;
14695                                selected_text = None;
14696                            }
14697                        } else {
14698                            same_text_selected = false;
14699                            selected_text = None;
14700                        }
14701                    }
14702                }
14703            }
14704
14705            if only_carets {
14706                for selection in &mut selections {
14707                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14708                    selection.start = word_range.start;
14709                    selection.end = word_range.end;
14710                    selection.goal = SelectionGoal::None;
14711                    selection.reversed = false;
14712                    self.select_match_ranges(
14713                        selection.start..selection.end,
14714                        selection.reversed,
14715                        replace_newest,
14716                        autoscroll,
14717                        window,
14718                        cx,
14719                    );
14720                }
14721
14722                if selections.len() == 1 {
14723                    let selection = selections
14724                        .last()
14725                        .expect("ensured that there's only one selection");
14726                    let query = buffer
14727                        .text_for_range(selection.start..selection.end)
14728                        .collect::<String>();
14729                    let is_empty = query.is_empty();
14730                    let select_state = SelectNextState {
14731                        query: self.build_query(&[query], cx)?,
14732                        wordwise: true,
14733                        done: is_empty,
14734                    };
14735                    self.select_next_state = Some(select_state);
14736                } else {
14737                    self.select_next_state = None;
14738                }
14739            } else if let Some(selected_text) = selected_text {
14740                self.select_next_state = Some(SelectNextState {
14741                    query: self.build_query(&[selected_text], cx)?,
14742                    wordwise: false,
14743                    done: false,
14744                });
14745                self.select_next_match_internal(
14746                    display_map,
14747                    replace_newest,
14748                    autoscroll,
14749                    window,
14750                    cx,
14751                )?;
14752            }
14753        }
14754        Ok(())
14755    }
14756
14757    pub fn select_all_matches(
14758        &mut self,
14759        _action: &SelectAllMatches,
14760        window: &mut Window,
14761        cx: &mut Context<Self>,
14762    ) -> Result<()> {
14763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14764
14765        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14766
14767        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14768        let Some(select_next_state) = self.select_next_state.as_mut() else {
14769            return Ok(());
14770        };
14771        if select_next_state.done {
14772            return Ok(());
14773        }
14774
14775        let mut new_selections = Vec::new();
14776
14777        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14778        let buffer = display_map.buffer_snapshot();
14779        let query_matches = select_next_state
14780            .query
14781            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14782
14783        for query_match in query_matches.into_iter() {
14784            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14785            let offset_range = if reversed {
14786                query_match.end()..query_match.start()
14787            } else {
14788                query_match.start()..query_match.end()
14789            };
14790
14791            if !select_next_state.wordwise
14792                || (!buffer.is_inside_word(offset_range.start, None)
14793                    && !buffer.is_inside_word(offset_range.end, None))
14794            {
14795                new_selections.push(offset_range.start..offset_range.end);
14796            }
14797        }
14798
14799        select_next_state.done = true;
14800
14801        if new_selections.is_empty() {
14802            log::error!("bug: new_selections is empty in select_all_matches");
14803            return Ok(());
14804        }
14805
14806        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14807        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14808            selections.select_ranges(new_selections)
14809        });
14810
14811        Ok(())
14812    }
14813
14814    pub fn select_next(
14815        &mut self,
14816        action: &SelectNext,
14817        window: &mut Window,
14818        cx: &mut Context<Self>,
14819    ) -> Result<()> {
14820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14821        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14822        self.select_next_match_internal(
14823            &display_map,
14824            action.replace_newest,
14825            Some(Autoscroll::newest()),
14826            window,
14827            cx,
14828        )?;
14829        Ok(())
14830    }
14831
14832    pub fn select_previous(
14833        &mut self,
14834        action: &SelectPrevious,
14835        window: &mut Window,
14836        cx: &mut Context<Self>,
14837    ) -> Result<()> {
14838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14839        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14840        let buffer = display_map.buffer_snapshot();
14841        let mut selections = self.selections.all::<usize>(&display_map);
14842        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14843            let query = &select_prev_state.query;
14844            if !select_prev_state.done {
14845                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14846                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14847                let mut next_selected_range = None;
14848                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14849                let bytes_before_last_selection =
14850                    buffer.reversed_bytes_in_range(0..last_selection.start);
14851                let bytes_after_first_selection =
14852                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14853                let query_matches = query
14854                    .stream_find_iter(bytes_before_last_selection)
14855                    .map(|result| (last_selection.start, result))
14856                    .chain(
14857                        query
14858                            .stream_find_iter(bytes_after_first_selection)
14859                            .map(|result| (buffer.len(), result)),
14860                    );
14861                for (end_offset, query_match) in query_matches {
14862                    let query_match = query_match.unwrap(); // can only fail due to I/O
14863                    let offset_range =
14864                        end_offset - query_match.end()..end_offset - query_match.start();
14865
14866                    if !select_prev_state.wordwise
14867                        || (!buffer.is_inside_word(offset_range.start, None)
14868                            && !buffer.is_inside_word(offset_range.end, None))
14869                    {
14870                        next_selected_range = Some(offset_range);
14871                        break;
14872                    }
14873                }
14874
14875                if let Some(next_selected_range) = next_selected_range {
14876                    self.select_match_ranges(
14877                        next_selected_range,
14878                        last_selection.reversed,
14879                        action.replace_newest,
14880                        Some(Autoscroll::newest()),
14881                        window,
14882                        cx,
14883                    );
14884                } else {
14885                    select_prev_state.done = true;
14886                }
14887            }
14888
14889            self.select_prev_state = Some(select_prev_state);
14890        } else {
14891            let mut only_carets = true;
14892            let mut same_text_selected = true;
14893            let mut selected_text = None;
14894
14895            let mut selections_iter = selections.iter().peekable();
14896            while let Some(selection) = selections_iter.next() {
14897                if selection.start != selection.end {
14898                    only_carets = false;
14899                }
14900
14901                if same_text_selected {
14902                    if selected_text.is_none() {
14903                        selected_text =
14904                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14905                    }
14906
14907                    if let Some(next_selection) = selections_iter.peek() {
14908                        if next_selection.range().len() == selection.range().len() {
14909                            let next_selected_text = buffer
14910                                .text_for_range(next_selection.range())
14911                                .collect::<String>();
14912                            if Some(next_selected_text) != selected_text {
14913                                same_text_selected = false;
14914                                selected_text = None;
14915                            }
14916                        } else {
14917                            same_text_selected = false;
14918                            selected_text = None;
14919                        }
14920                    }
14921                }
14922            }
14923
14924            if only_carets {
14925                for selection in &mut selections {
14926                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14927                    selection.start = word_range.start;
14928                    selection.end = word_range.end;
14929                    selection.goal = SelectionGoal::None;
14930                    selection.reversed = false;
14931                    self.select_match_ranges(
14932                        selection.start..selection.end,
14933                        selection.reversed,
14934                        action.replace_newest,
14935                        Some(Autoscroll::newest()),
14936                        window,
14937                        cx,
14938                    );
14939                }
14940                if selections.len() == 1 {
14941                    let selection = selections
14942                        .last()
14943                        .expect("ensured that there's only one selection");
14944                    let query = buffer
14945                        .text_for_range(selection.start..selection.end)
14946                        .collect::<String>();
14947                    let is_empty = query.is_empty();
14948                    let select_state = SelectNextState {
14949                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14950                        wordwise: true,
14951                        done: is_empty,
14952                    };
14953                    self.select_prev_state = Some(select_state);
14954                } else {
14955                    self.select_prev_state = None;
14956                }
14957            } else if let Some(selected_text) = selected_text {
14958                self.select_prev_state = Some(SelectNextState {
14959                    query: self
14960                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
14961                    wordwise: false,
14962                    done: false,
14963                });
14964                self.select_previous(action, window, cx)?;
14965            }
14966        }
14967        Ok(())
14968    }
14969
14970    /// Builds an `AhoCorasick` automaton from the provided patterns, while
14971    /// setting the case sensitivity based on the global
14972    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
14973    /// editor's settings.
14974    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
14975    where
14976        I: IntoIterator<Item = P>,
14977        P: AsRef<[u8]>,
14978    {
14979        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
14980            || EditorSettings::get_global(cx).search.case_sensitive,
14981            |value| value,
14982        );
14983
14984        let mut builder = AhoCorasickBuilder::new();
14985        builder.ascii_case_insensitive(!case_sensitive);
14986        builder.build(patterns)
14987    }
14988
14989    pub fn find_next_match(
14990        &mut self,
14991        _: &FindNextMatch,
14992        window: &mut Window,
14993        cx: &mut Context<Self>,
14994    ) -> Result<()> {
14995        let selections = self.selections.disjoint_anchors_arc();
14996        match selections.first() {
14997            Some(first) if selections.len() >= 2 => {
14998                self.change_selections(Default::default(), window, cx, |s| {
14999                    s.select_ranges([first.range()]);
15000                });
15001            }
15002            _ => self.select_next(
15003                &SelectNext {
15004                    replace_newest: true,
15005                },
15006                window,
15007                cx,
15008            )?,
15009        }
15010        Ok(())
15011    }
15012
15013    pub fn find_previous_match(
15014        &mut self,
15015        _: &FindPreviousMatch,
15016        window: &mut Window,
15017        cx: &mut Context<Self>,
15018    ) -> Result<()> {
15019        let selections = self.selections.disjoint_anchors_arc();
15020        match selections.last() {
15021            Some(last) if selections.len() >= 2 => {
15022                self.change_selections(Default::default(), window, cx, |s| {
15023                    s.select_ranges([last.range()]);
15024                });
15025            }
15026            _ => self.select_previous(
15027                &SelectPrevious {
15028                    replace_newest: true,
15029                },
15030                window,
15031                cx,
15032            )?,
15033        }
15034        Ok(())
15035    }
15036
15037    pub fn toggle_comments(
15038        &mut self,
15039        action: &ToggleComments,
15040        window: &mut Window,
15041        cx: &mut Context<Self>,
15042    ) {
15043        if self.read_only(cx) {
15044            return;
15045        }
15046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15047        let text_layout_details = &self.text_layout_details(window);
15048        self.transact(window, cx, |this, window, cx| {
15049            let mut selections = this
15050                .selections
15051                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15052            let mut edits = Vec::new();
15053            let mut selection_edit_ranges = Vec::new();
15054            let mut last_toggled_row = None;
15055            let snapshot = this.buffer.read(cx).read(cx);
15056            let empty_str: Arc<str> = Arc::default();
15057            let mut suffixes_inserted = Vec::new();
15058            let ignore_indent = action.ignore_indent;
15059
15060            fn comment_prefix_range(
15061                snapshot: &MultiBufferSnapshot,
15062                row: MultiBufferRow,
15063                comment_prefix: &str,
15064                comment_prefix_whitespace: &str,
15065                ignore_indent: bool,
15066            ) -> Range<Point> {
15067                let indent_size = if ignore_indent {
15068                    0
15069                } else {
15070                    snapshot.indent_size_for_line(row).len
15071                };
15072
15073                let start = Point::new(row.0, indent_size);
15074
15075                let mut line_bytes = snapshot
15076                    .bytes_in_range(start..snapshot.max_point())
15077                    .flatten()
15078                    .copied();
15079
15080                // If this line currently begins with the line comment prefix, then record
15081                // the range containing the prefix.
15082                if line_bytes
15083                    .by_ref()
15084                    .take(comment_prefix.len())
15085                    .eq(comment_prefix.bytes())
15086                {
15087                    // Include any whitespace that matches the comment prefix.
15088                    let matching_whitespace_len = line_bytes
15089                        .zip(comment_prefix_whitespace.bytes())
15090                        .take_while(|(a, b)| a == b)
15091                        .count() as u32;
15092                    let end = Point::new(
15093                        start.row,
15094                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15095                    );
15096                    start..end
15097                } else {
15098                    start..start
15099                }
15100            }
15101
15102            fn comment_suffix_range(
15103                snapshot: &MultiBufferSnapshot,
15104                row: MultiBufferRow,
15105                comment_suffix: &str,
15106                comment_suffix_has_leading_space: bool,
15107            ) -> Range<Point> {
15108                let end = Point::new(row.0, snapshot.line_len(row));
15109                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15110
15111                let mut line_end_bytes = snapshot
15112                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15113                    .flatten()
15114                    .copied();
15115
15116                let leading_space_len = if suffix_start_column > 0
15117                    && line_end_bytes.next() == Some(b' ')
15118                    && comment_suffix_has_leading_space
15119                {
15120                    1
15121                } else {
15122                    0
15123                };
15124
15125                // If this line currently begins with the line comment prefix, then record
15126                // the range containing the prefix.
15127                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15128                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15129                    start..end
15130                } else {
15131                    end..end
15132                }
15133            }
15134
15135            // TODO: Handle selections that cross excerpts
15136            for selection in &mut selections {
15137                let start_column = snapshot
15138                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15139                    .len;
15140                let language = if let Some(language) =
15141                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15142                {
15143                    language
15144                } else {
15145                    continue;
15146                };
15147
15148                selection_edit_ranges.clear();
15149
15150                // If multiple selections contain a given row, avoid processing that
15151                // row more than once.
15152                let mut start_row = MultiBufferRow(selection.start.row);
15153                if last_toggled_row == Some(start_row) {
15154                    start_row = start_row.next_row();
15155                }
15156                let end_row =
15157                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15158                        MultiBufferRow(selection.end.row - 1)
15159                    } else {
15160                        MultiBufferRow(selection.end.row)
15161                    };
15162                last_toggled_row = Some(end_row);
15163
15164                if start_row > end_row {
15165                    continue;
15166                }
15167
15168                // If the language has line comments, toggle those.
15169                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15170
15171                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15172                if ignore_indent {
15173                    full_comment_prefixes = full_comment_prefixes
15174                        .into_iter()
15175                        .map(|s| Arc::from(s.trim_end()))
15176                        .collect();
15177                }
15178
15179                if !full_comment_prefixes.is_empty() {
15180                    let first_prefix = full_comment_prefixes
15181                        .first()
15182                        .expect("prefixes is non-empty");
15183                    let prefix_trimmed_lengths = full_comment_prefixes
15184                        .iter()
15185                        .map(|p| p.trim_end_matches(' ').len())
15186                        .collect::<SmallVec<[usize; 4]>>();
15187
15188                    let mut all_selection_lines_are_comments = true;
15189
15190                    for row in start_row.0..=end_row.0 {
15191                        let row = MultiBufferRow(row);
15192                        if start_row < end_row && snapshot.is_line_blank(row) {
15193                            continue;
15194                        }
15195
15196                        let prefix_range = full_comment_prefixes
15197                            .iter()
15198                            .zip(prefix_trimmed_lengths.iter().copied())
15199                            .map(|(prefix, trimmed_prefix_len)| {
15200                                comment_prefix_range(
15201                                    snapshot.deref(),
15202                                    row,
15203                                    &prefix[..trimmed_prefix_len],
15204                                    &prefix[trimmed_prefix_len..],
15205                                    ignore_indent,
15206                                )
15207                            })
15208                            .max_by_key(|range| range.end.column - range.start.column)
15209                            .expect("prefixes is non-empty");
15210
15211                        if prefix_range.is_empty() {
15212                            all_selection_lines_are_comments = false;
15213                        }
15214
15215                        selection_edit_ranges.push(prefix_range);
15216                    }
15217
15218                    if all_selection_lines_are_comments {
15219                        edits.extend(
15220                            selection_edit_ranges
15221                                .iter()
15222                                .cloned()
15223                                .map(|range| (range, empty_str.clone())),
15224                        );
15225                    } else {
15226                        let min_column = selection_edit_ranges
15227                            .iter()
15228                            .map(|range| range.start.column)
15229                            .min()
15230                            .unwrap_or(0);
15231                        edits.extend(selection_edit_ranges.iter().map(|range| {
15232                            let position = Point::new(range.start.row, min_column);
15233                            (position..position, first_prefix.clone())
15234                        }));
15235                    }
15236                } else if let Some(BlockCommentConfig {
15237                    start: full_comment_prefix,
15238                    end: comment_suffix,
15239                    ..
15240                }) = language.block_comment()
15241                {
15242                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15243                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15244                    let prefix_range = comment_prefix_range(
15245                        snapshot.deref(),
15246                        start_row,
15247                        comment_prefix,
15248                        comment_prefix_whitespace,
15249                        ignore_indent,
15250                    );
15251                    let suffix_range = comment_suffix_range(
15252                        snapshot.deref(),
15253                        end_row,
15254                        comment_suffix.trim_start_matches(' '),
15255                        comment_suffix.starts_with(' '),
15256                    );
15257
15258                    if prefix_range.is_empty() || suffix_range.is_empty() {
15259                        edits.push((
15260                            prefix_range.start..prefix_range.start,
15261                            full_comment_prefix.clone(),
15262                        ));
15263                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15264                        suffixes_inserted.push((end_row, comment_suffix.len()));
15265                    } else {
15266                        edits.push((prefix_range, empty_str.clone()));
15267                        edits.push((suffix_range, empty_str.clone()));
15268                    }
15269                } else {
15270                    continue;
15271                }
15272            }
15273
15274            drop(snapshot);
15275            this.buffer.update(cx, |buffer, cx| {
15276                buffer.edit(edits, None, cx);
15277            });
15278
15279            // Adjust selections so that they end before any comment suffixes that
15280            // were inserted.
15281            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15282            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15283            let snapshot = this.buffer.read(cx).read(cx);
15284            for selection in &mut selections {
15285                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15286                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15287                        Ordering::Less => {
15288                            suffixes_inserted.next();
15289                            continue;
15290                        }
15291                        Ordering::Greater => break,
15292                        Ordering::Equal => {
15293                            if selection.end.column == snapshot.line_len(row) {
15294                                if selection.is_empty() {
15295                                    selection.start.column -= suffix_len as u32;
15296                                }
15297                                selection.end.column -= suffix_len as u32;
15298                            }
15299                            break;
15300                        }
15301                    }
15302                }
15303            }
15304
15305            drop(snapshot);
15306            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15307
15308            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15309            let selections_on_single_row = selections.windows(2).all(|selections| {
15310                selections[0].start.row == selections[1].start.row
15311                    && selections[0].end.row == selections[1].end.row
15312                    && selections[0].start.row == selections[0].end.row
15313            });
15314            let selections_selecting = selections
15315                .iter()
15316                .any(|selection| selection.start != selection.end);
15317            let advance_downwards = action.advance_downwards
15318                && selections_on_single_row
15319                && !selections_selecting
15320                && !matches!(this.mode, EditorMode::SingleLine);
15321
15322            if advance_downwards {
15323                let snapshot = this.buffer.read(cx).snapshot(cx);
15324
15325                this.change_selections(Default::default(), window, cx, |s| {
15326                    s.move_cursors_with(|display_snapshot, display_point, _| {
15327                        let mut point = display_point.to_point(display_snapshot);
15328                        point.row += 1;
15329                        point = snapshot.clip_point(point, Bias::Left);
15330                        let display_point = point.to_display_point(display_snapshot);
15331                        let goal = SelectionGoal::HorizontalPosition(
15332                            display_snapshot
15333                                .x_for_display_point(display_point, text_layout_details)
15334                                .into(),
15335                        );
15336                        (display_point, goal)
15337                    })
15338                });
15339            }
15340        });
15341    }
15342
15343    pub fn select_enclosing_symbol(
15344        &mut self,
15345        _: &SelectEnclosingSymbol,
15346        window: &mut Window,
15347        cx: &mut Context<Self>,
15348    ) {
15349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15350
15351        let buffer = self.buffer.read(cx).snapshot(cx);
15352        let old_selections = self
15353            .selections
15354            .all::<usize>(&self.display_snapshot(cx))
15355            .into_boxed_slice();
15356
15357        fn update_selection(
15358            selection: &Selection<usize>,
15359            buffer_snap: &MultiBufferSnapshot,
15360        ) -> Option<Selection<usize>> {
15361            let cursor = selection.head();
15362            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15363            for symbol in symbols.iter().rev() {
15364                let start = symbol.range.start.to_offset(buffer_snap);
15365                let end = symbol.range.end.to_offset(buffer_snap);
15366                let new_range = start..end;
15367                if start < selection.start || end > selection.end {
15368                    return Some(Selection {
15369                        id: selection.id,
15370                        start: new_range.start,
15371                        end: new_range.end,
15372                        goal: SelectionGoal::None,
15373                        reversed: selection.reversed,
15374                    });
15375                }
15376            }
15377            None
15378        }
15379
15380        let mut selected_larger_symbol = false;
15381        let new_selections = old_selections
15382            .iter()
15383            .map(|selection| match update_selection(selection, &buffer) {
15384                Some(new_selection) => {
15385                    if new_selection.range() != selection.range() {
15386                        selected_larger_symbol = true;
15387                    }
15388                    new_selection
15389                }
15390                None => selection.clone(),
15391            })
15392            .collect::<Vec<_>>();
15393
15394        if selected_larger_symbol {
15395            self.change_selections(Default::default(), window, cx, |s| {
15396                s.select(new_selections);
15397            });
15398        }
15399    }
15400
15401    pub fn select_larger_syntax_node(
15402        &mut self,
15403        _: &SelectLargerSyntaxNode,
15404        window: &mut Window,
15405        cx: &mut Context<Self>,
15406    ) {
15407        let Some(visible_row_count) = self.visible_row_count() else {
15408            return;
15409        };
15410        let old_selections: Box<[_]> = self
15411            .selections
15412            .all::<usize>(&self.display_snapshot(cx))
15413            .into();
15414        if old_selections.is_empty() {
15415            return;
15416        }
15417
15418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15419
15420        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15421        let buffer = self.buffer.read(cx).snapshot(cx);
15422
15423        let mut selected_larger_node = false;
15424        let mut new_selections = old_selections
15425            .iter()
15426            .map(|selection| {
15427                let old_range = selection.start..selection.end;
15428
15429                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15430                    // manually select word at selection
15431                    if ["string_content", "inline"].contains(&node.kind()) {
15432                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15433                        // ignore if word is already selected
15434                        if !word_range.is_empty() && old_range != word_range {
15435                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15436                            // only select word if start and end point belongs to same word
15437                            if word_range == last_word_range {
15438                                selected_larger_node = true;
15439                                return Selection {
15440                                    id: selection.id,
15441                                    start: word_range.start,
15442                                    end: word_range.end,
15443                                    goal: SelectionGoal::None,
15444                                    reversed: selection.reversed,
15445                                };
15446                            }
15447                        }
15448                    }
15449                }
15450
15451                let mut new_range = old_range.clone();
15452                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15453                    new_range = range;
15454                    if !node.is_named() {
15455                        continue;
15456                    }
15457                    if !display_map.intersects_fold(new_range.start)
15458                        && !display_map.intersects_fold(new_range.end)
15459                    {
15460                        break;
15461                    }
15462                }
15463
15464                selected_larger_node |= new_range != old_range;
15465                Selection {
15466                    id: selection.id,
15467                    start: new_range.start,
15468                    end: new_range.end,
15469                    goal: SelectionGoal::None,
15470                    reversed: selection.reversed,
15471                }
15472            })
15473            .collect::<Vec<_>>();
15474
15475        if !selected_larger_node {
15476            return; // don't put this call in the history
15477        }
15478
15479        // scroll based on transformation done to the last selection created by the user
15480        let (last_old, last_new) = old_selections
15481            .last()
15482            .zip(new_selections.last().cloned())
15483            .expect("old_selections isn't empty");
15484
15485        // revert selection
15486        let is_selection_reversed = {
15487            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15488            new_selections.last_mut().expect("checked above").reversed =
15489                should_newest_selection_be_reversed;
15490            should_newest_selection_be_reversed
15491        };
15492
15493        if selected_larger_node {
15494            self.select_syntax_node_history.disable_clearing = true;
15495            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15496                s.select(new_selections.clone());
15497            });
15498            self.select_syntax_node_history.disable_clearing = false;
15499        }
15500
15501        let start_row = last_new.start.to_display_point(&display_map).row().0;
15502        let end_row = last_new.end.to_display_point(&display_map).row().0;
15503        let selection_height = end_row - start_row + 1;
15504        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15505
15506        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15507        let scroll_behavior = if fits_on_the_screen {
15508            self.request_autoscroll(Autoscroll::fit(), cx);
15509            SelectSyntaxNodeScrollBehavior::FitSelection
15510        } else if is_selection_reversed {
15511            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15512            SelectSyntaxNodeScrollBehavior::CursorTop
15513        } else {
15514            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15515            SelectSyntaxNodeScrollBehavior::CursorBottom
15516        };
15517
15518        self.select_syntax_node_history.push((
15519            old_selections,
15520            scroll_behavior,
15521            is_selection_reversed,
15522        ));
15523    }
15524
15525    pub fn select_smaller_syntax_node(
15526        &mut self,
15527        _: &SelectSmallerSyntaxNode,
15528        window: &mut Window,
15529        cx: &mut Context<Self>,
15530    ) {
15531        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15532
15533        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15534            self.select_syntax_node_history.pop()
15535        {
15536            if let Some(selection) = selections.last_mut() {
15537                selection.reversed = is_selection_reversed;
15538            }
15539
15540            self.select_syntax_node_history.disable_clearing = true;
15541            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15542                s.select(selections.to_vec());
15543            });
15544            self.select_syntax_node_history.disable_clearing = false;
15545
15546            match scroll_behavior {
15547                SelectSyntaxNodeScrollBehavior::CursorTop => {
15548                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15549                }
15550                SelectSyntaxNodeScrollBehavior::FitSelection => {
15551                    self.request_autoscroll(Autoscroll::fit(), cx);
15552                }
15553                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15554                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15555                }
15556            }
15557        }
15558    }
15559
15560    pub fn unwrap_syntax_node(
15561        &mut self,
15562        _: &UnwrapSyntaxNode,
15563        window: &mut Window,
15564        cx: &mut Context<Self>,
15565    ) {
15566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15567
15568        let buffer = self.buffer.read(cx).snapshot(cx);
15569        let selections = self
15570            .selections
15571            .all::<usize>(&self.display_snapshot(cx))
15572            .into_iter()
15573            // subtracting the offset requires sorting
15574            .sorted_by_key(|i| i.start);
15575
15576        let full_edits = selections
15577            .into_iter()
15578            .filter_map(|selection| {
15579                let child = if selection.is_empty()
15580                    && let Some((_, ancestor_range)) =
15581                        buffer.syntax_ancestor(selection.start..selection.end)
15582                {
15583                    ancestor_range
15584                } else {
15585                    selection.range()
15586                };
15587
15588                let mut parent = child.clone();
15589                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15590                    parent = ancestor_range;
15591                    if parent.start < child.start || parent.end > child.end {
15592                        break;
15593                    }
15594                }
15595
15596                if parent == child {
15597                    return None;
15598                }
15599                let text = buffer.text_for_range(child).collect::<String>();
15600                Some((selection.id, parent, text))
15601            })
15602            .collect::<Vec<_>>();
15603        if full_edits.is_empty() {
15604            return;
15605        }
15606
15607        self.transact(window, cx, |this, window, cx| {
15608            this.buffer.update(cx, |buffer, cx| {
15609                buffer.edit(
15610                    full_edits
15611                        .iter()
15612                        .map(|(_, p, t)| (p.clone(), t.clone()))
15613                        .collect::<Vec<_>>(),
15614                    None,
15615                    cx,
15616                );
15617            });
15618            this.change_selections(Default::default(), window, cx, |s| {
15619                let mut offset = 0;
15620                let mut selections = vec![];
15621                for (id, parent, text) in full_edits {
15622                    let start = parent.start - offset;
15623                    offset += parent.len() - text.len();
15624                    selections.push(Selection {
15625                        id,
15626                        start,
15627                        end: start + text.len(),
15628                        reversed: false,
15629                        goal: Default::default(),
15630                    });
15631                }
15632                s.select(selections);
15633            });
15634        });
15635    }
15636
15637    pub fn select_next_syntax_node(
15638        &mut self,
15639        _: &SelectNextSyntaxNode,
15640        window: &mut Window,
15641        cx: &mut Context<Self>,
15642    ) {
15643        let old_selections: Box<[_]> = self
15644            .selections
15645            .all::<usize>(&self.display_snapshot(cx))
15646            .into();
15647        if old_selections.is_empty() {
15648            return;
15649        }
15650
15651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15652
15653        let buffer = self.buffer.read(cx).snapshot(cx);
15654        let mut selected_sibling = false;
15655
15656        let new_selections = old_selections
15657            .iter()
15658            .map(|selection| {
15659                let old_range = selection.start..selection.end;
15660
15661                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15662                    let new_range = node.byte_range();
15663                    selected_sibling = true;
15664                    Selection {
15665                        id: selection.id,
15666                        start: new_range.start,
15667                        end: new_range.end,
15668                        goal: SelectionGoal::None,
15669                        reversed: selection.reversed,
15670                    }
15671                } else {
15672                    selection.clone()
15673                }
15674            })
15675            .collect::<Vec<_>>();
15676
15677        if selected_sibling {
15678            self.change_selections(
15679                SelectionEffects::scroll(Autoscroll::fit()),
15680                window,
15681                cx,
15682                |s| {
15683                    s.select(new_selections);
15684                },
15685            );
15686        }
15687    }
15688
15689    pub fn select_prev_syntax_node(
15690        &mut self,
15691        _: &SelectPreviousSyntaxNode,
15692        window: &mut Window,
15693        cx: &mut Context<Self>,
15694    ) {
15695        let old_selections: Box<[_]> = self
15696            .selections
15697            .all::<usize>(&self.display_snapshot(cx))
15698            .into();
15699        if old_selections.is_empty() {
15700            return;
15701        }
15702
15703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15704
15705        let buffer = self.buffer.read(cx).snapshot(cx);
15706        let mut selected_sibling = false;
15707
15708        let new_selections = old_selections
15709            .iter()
15710            .map(|selection| {
15711                let old_range = selection.start..selection.end;
15712
15713                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15714                    let new_range = node.byte_range();
15715                    selected_sibling = true;
15716                    Selection {
15717                        id: selection.id,
15718                        start: new_range.start,
15719                        end: new_range.end,
15720                        goal: SelectionGoal::None,
15721                        reversed: selection.reversed,
15722                    }
15723                } else {
15724                    selection.clone()
15725                }
15726            })
15727            .collect::<Vec<_>>();
15728
15729        if selected_sibling {
15730            self.change_selections(
15731                SelectionEffects::scroll(Autoscroll::fit()),
15732                window,
15733                cx,
15734                |s| {
15735                    s.select(new_selections);
15736                },
15737            );
15738        }
15739    }
15740
15741    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15742        if !EditorSettings::get_global(cx).gutter.runnables {
15743            self.clear_tasks();
15744            return Task::ready(());
15745        }
15746        let project = self.project().map(Entity::downgrade);
15747        let task_sources = self.lsp_task_sources(cx);
15748        let multi_buffer = self.buffer.downgrade();
15749        cx.spawn_in(window, async move |editor, cx| {
15750            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15751            let Some(project) = project.and_then(|p| p.upgrade()) else {
15752                return;
15753            };
15754            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15755                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15756            }) else {
15757                return;
15758            };
15759
15760            let hide_runnables = project
15761                .update(cx, |project, _| project.is_via_collab())
15762                .unwrap_or(true);
15763            if hide_runnables {
15764                return;
15765            }
15766            let new_rows =
15767                cx.background_spawn({
15768                    let snapshot = display_snapshot.clone();
15769                    async move {
15770                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15771                    }
15772                })
15773                    .await;
15774            let Ok(lsp_tasks) =
15775                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15776            else {
15777                return;
15778            };
15779            let lsp_tasks = lsp_tasks.await;
15780
15781            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15782                lsp_tasks
15783                    .into_iter()
15784                    .flat_map(|(kind, tasks)| {
15785                        tasks.into_iter().filter_map(move |(location, task)| {
15786                            Some((kind.clone(), location?, task))
15787                        })
15788                    })
15789                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15790                        let buffer = location.target.buffer;
15791                        let buffer_snapshot = buffer.read(cx).snapshot();
15792                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15793                            |(excerpt_id, snapshot, _)| {
15794                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15795                                    display_snapshot
15796                                        .buffer_snapshot()
15797                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15798                                } else {
15799                                    None
15800                                }
15801                            },
15802                        );
15803                        if let Some(offset) = offset {
15804                            let task_buffer_range =
15805                                location.target.range.to_point(&buffer_snapshot);
15806                            let context_buffer_range =
15807                                task_buffer_range.to_offset(&buffer_snapshot);
15808                            let context_range = BufferOffset(context_buffer_range.start)
15809                                ..BufferOffset(context_buffer_range.end);
15810
15811                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15812                                .or_insert_with(|| RunnableTasks {
15813                                    templates: Vec::new(),
15814                                    offset,
15815                                    column: task_buffer_range.start.column,
15816                                    extra_variables: HashMap::default(),
15817                                    context_range,
15818                                })
15819                                .templates
15820                                .push((kind, task.original_task().clone()));
15821                        }
15822
15823                        acc
15824                    })
15825            }) else {
15826                return;
15827            };
15828
15829            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15830                buffer.language_settings(cx).tasks.prefer_lsp
15831            }) else {
15832                return;
15833            };
15834
15835            let rows = Self::runnable_rows(
15836                project,
15837                display_snapshot,
15838                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15839                new_rows,
15840                cx.clone(),
15841            )
15842            .await;
15843            editor
15844                .update(cx, |editor, _| {
15845                    editor.clear_tasks();
15846                    for (key, mut value) in rows {
15847                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15848                            value.templates.extend(lsp_tasks.templates);
15849                        }
15850
15851                        editor.insert_tasks(key, value);
15852                    }
15853                    for (key, value) in lsp_tasks_by_rows {
15854                        editor.insert_tasks(key, value);
15855                    }
15856                })
15857                .ok();
15858        })
15859    }
15860    fn fetch_runnable_ranges(
15861        snapshot: &DisplaySnapshot,
15862        range: Range<Anchor>,
15863    ) -> Vec<language::RunnableRange> {
15864        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15865    }
15866
15867    fn runnable_rows(
15868        project: Entity<Project>,
15869        snapshot: DisplaySnapshot,
15870        prefer_lsp: bool,
15871        runnable_ranges: Vec<RunnableRange>,
15872        cx: AsyncWindowContext,
15873    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15874        cx.spawn(async move |cx| {
15875            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15876            for mut runnable in runnable_ranges {
15877                let Some(tasks) = cx
15878                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15879                    .ok()
15880                else {
15881                    continue;
15882                };
15883                let mut tasks = tasks.await;
15884
15885                if prefer_lsp {
15886                    tasks.retain(|(task_kind, _)| {
15887                        !matches!(task_kind, TaskSourceKind::Language { .. })
15888                    });
15889                }
15890                if tasks.is_empty() {
15891                    continue;
15892                }
15893
15894                let point = runnable
15895                    .run_range
15896                    .start
15897                    .to_point(&snapshot.buffer_snapshot());
15898                let Some(row) = snapshot
15899                    .buffer_snapshot()
15900                    .buffer_line_for_row(MultiBufferRow(point.row))
15901                    .map(|(_, range)| range.start.row)
15902                else {
15903                    continue;
15904                };
15905
15906                let context_range =
15907                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15908                runnable_rows.push((
15909                    (runnable.buffer_id, row),
15910                    RunnableTasks {
15911                        templates: tasks,
15912                        offset: snapshot
15913                            .buffer_snapshot()
15914                            .anchor_before(runnable.run_range.start),
15915                        context_range,
15916                        column: point.column,
15917                        extra_variables: runnable.extra_captures,
15918                    },
15919                ));
15920            }
15921            runnable_rows
15922        })
15923    }
15924
15925    fn templates_with_tags(
15926        project: &Entity<Project>,
15927        runnable: &mut Runnable,
15928        cx: &mut App,
15929    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15930        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15931            let (worktree_id, file) = project
15932                .buffer_for_id(runnable.buffer, cx)
15933                .and_then(|buffer| buffer.read(cx).file())
15934                .map(|file| (file.worktree_id(cx), file.clone()))
15935                .unzip();
15936
15937            (
15938                project.task_store().read(cx).task_inventory().cloned(),
15939                worktree_id,
15940                file,
15941            )
15942        });
15943
15944        let tags = mem::take(&mut runnable.tags);
15945        let language = runnable.language.clone();
15946        cx.spawn(async move |cx| {
15947            let mut templates_with_tags = Vec::new();
15948            if let Some(inventory) = inventory {
15949                for RunnableTag(tag) in tags {
15950                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15951                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15952                    }) else {
15953                        return templates_with_tags;
15954                    };
15955                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15956                        move |(_, template)| {
15957                            template.tags.iter().any(|source_tag| source_tag == &tag)
15958                        },
15959                    ));
15960                }
15961            }
15962            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15963
15964            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15965                // Strongest source wins; if we have worktree tag binding, prefer that to
15966                // global and language bindings;
15967                // if we have a global binding, prefer that to language binding.
15968                let first_mismatch = templates_with_tags
15969                    .iter()
15970                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15971                if let Some(index) = first_mismatch {
15972                    templates_with_tags.truncate(index);
15973                }
15974            }
15975
15976            templates_with_tags
15977        })
15978    }
15979
15980    pub fn move_to_enclosing_bracket(
15981        &mut self,
15982        _: &MoveToEnclosingBracket,
15983        window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15987        self.change_selections(Default::default(), window, cx, |s| {
15988            s.move_offsets_with(|snapshot, selection| {
15989                let Some(enclosing_bracket_ranges) =
15990                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15991                else {
15992                    return;
15993                };
15994
15995                let mut best_length = usize::MAX;
15996                let mut best_inside = false;
15997                let mut best_in_bracket_range = false;
15998                let mut best_destination = None;
15999                for (open, close) in enclosing_bracket_ranges {
16000                    let close = close.to_inclusive();
16001                    let length = close.end() - open.start;
16002                    let inside = selection.start >= open.end && selection.end <= *close.start();
16003                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16004                        || close.contains(&selection.head());
16005
16006                    // If best is next to a bracket and current isn't, skip
16007                    if !in_bracket_range && best_in_bracket_range {
16008                        continue;
16009                    }
16010
16011                    // Prefer smaller lengths unless best is inside and current isn't
16012                    if length > best_length && (best_inside || !inside) {
16013                        continue;
16014                    }
16015
16016                    best_length = length;
16017                    best_inside = inside;
16018                    best_in_bracket_range = in_bracket_range;
16019                    best_destination = Some(
16020                        if close.contains(&selection.start) && close.contains(&selection.end) {
16021                            if inside { open.end } else { open.start }
16022                        } else if inside {
16023                            *close.start()
16024                        } else {
16025                            *close.end()
16026                        },
16027                    );
16028                }
16029
16030                if let Some(destination) = best_destination {
16031                    selection.collapse_to(destination, SelectionGoal::None);
16032                }
16033            })
16034        });
16035    }
16036
16037    pub fn undo_selection(
16038        &mut self,
16039        _: &UndoSelection,
16040        window: &mut Window,
16041        cx: &mut Context<Self>,
16042    ) {
16043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16044        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16045            self.selection_history.mode = SelectionHistoryMode::Undoing;
16046            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16047                this.end_selection(window, cx);
16048                this.change_selections(
16049                    SelectionEffects::scroll(Autoscroll::newest()),
16050                    window,
16051                    cx,
16052                    |s| s.select_anchors(entry.selections.to_vec()),
16053                );
16054            });
16055            self.selection_history.mode = SelectionHistoryMode::Normal;
16056
16057            self.select_next_state = entry.select_next_state;
16058            self.select_prev_state = entry.select_prev_state;
16059            self.add_selections_state = entry.add_selections_state;
16060        }
16061    }
16062
16063    pub fn redo_selection(
16064        &mut self,
16065        _: &RedoSelection,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) {
16069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16070        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16071            self.selection_history.mode = SelectionHistoryMode::Redoing;
16072            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16073                this.end_selection(window, cx);
16074                this.change_selections(
16075                    SelectionEffects::scroll(Autoscroll::newest()),
16076                    window,
16077                    cx,
16078                    |s| s.select_anchors(entry.selections.to_vec()),
16079                );
16080            });
16081            self.selection_history.mode = SelectionHistoryMode::Normal;
16082
16083            self.select_next_state = entry.select_next_state;
16084            self.select_prev_state = entry.select_prev_state;
16085            self.add_selections_state = entry.add_selections_state;
16086        }
16087    }
16088
16089    pub fn expand_excerpts(
16090        &mut self,
16091        action: &ExpandExcerpts,
16092        _: &mut Window,
16093        cx: &mut Context<Self>,
16094    ) {
16095        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16096    }
16097
16098    pub fn expand_excerpts_down(
16099        &mut self,
16100        action: &ExpandExcerptsDown,
16101        _: &mut Window,
16102        cx: &mut Context<Self>,
16103    ) {
16104        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16105    }
16106
16107    pub fn expand_excerpts_up(
16108        &mut self,
16109        action: &ExpandExcerptsUp,
16110        _: &mut Window,
16111        cx: &mut Context<Self>,
16112    ) {
16113        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16114    }
16115
16116    pub fn expand_excerpts_for_direction(
16117        &mut self,
16118        lines: u32,
16119        direction: ExpandExcerptDirection,
16120
16121        cx: &mut Context<Self>,
16122    ) {
16123        let selections = self.selections.disjoint_anchors_arc();
16124
16125        let lines = if lines == 0 {
16126            EditorSettings::get_global(cx).expand_excerpt_lines
16127        } else {
16128            lines
16129        };
16130
16131        self.buffer.update(cx, |buffer, cx| {
16132            let snapshot = buffer.snapshot(cx);
16133            let mut excerpt_ids = selections
16134                .iter()
16135                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16136                .collect::<Vec<_>>();
16137            excerpt_ids.sort();
16138            excerpt_ids.dedup();
16139            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16140        })
16141    }
16142
16143    pub fn expand_excerpt(
16144        &mut self,
16145        excerpt: ExcerptId,
16146        direction: ExpandExcerptDirection,
16147        window: &mut Window,
16148        cx: &mut Context<Self>,
16149    ) {
16150        let current_scroll_position = self.scroll_position(cx);
16151        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16152        let mut scroll = None;
16153
16154        if direction == ExpandExcerptDirection::Down {
16155            let multi_buffer = self.buffer.read(cx);
16156            let snapshot = multi_buffer.snapshot(cx);
16157            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16158                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16159                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16160            {
16161                let buffer_snapshot = buffer.read(cx).snapshot();
16162                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16163                let last_row = buffer_snapshot.max_point().row;
16164                let lines_below = last_row.saturating_sub(excerpt_end_row);
16165                if lines_below >= lines_to_expand {
16166                    scroll = Some(
16167                        current_scroll_position
16168                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16169                    );
16170                }
16171            }
16172        }
16173        if direction == ExpandExcerptDirection::Up
16174            && self
16175                .buffer
16176                .read(cx)
16177                .snapshot(cx)
16178                .excerpt_before(excerpt)
16179                .is_none()
16180        {
16181            scroll = Some(current_scroll_position);
16182        }
16183
16184        self.buffer.update(cx, |buffer, cx| {
16185            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16186        });
16187
16188        if let Some(new_scroll_position) = scroll {
16189            self.set_scroll_position(new_scroll_position, window, cx);
16190        }
16191    }
16192
16193    pub fn go_to_singleton_buffer_point(
16194        &mut self,
16195        point: Point,
16196        window: &mut Window,
16197        cx: &mut Context<Self>,
16198    ) {
16199        self.go_to_singleton_buffer_range(point..point, window, cx);
16200    }
16201
16202    pub fn go_to_singleton_buffer_range(
16203        &mut self,
16204        range: Range<Point>,
16205        window: &mut Window,
16206        cx: &mut Context<Self>,
16207    ) {
16208        let multibuffer = self.buffer().read(cx);
16209        let Some(buffer) = multibuffer.as_singleton() else {
16210            return;
16211        };
16212        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16213            return;
16214        };
16215        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16216            return;
16217        };
16218        self.change_selections(
16219            SelectionEffects::default().nav_history(true),
16220            window,
16221            cx,
16222            |s| s.select_anchor_ranges([start..end]),
16223        );
16224    }
16225
16226    pub fn go_to_diagnostic(
16227        &mut self,
16228        action: &GoToDiagnostic,
16229        window: &mut Window,
16230        cx: &mut Context<Self>,
16231    ) {
16232        if !self.diagnostics_enabled() {
16233            return;
16234        }
16235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16236        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16237    }
16238
16239    pub fn go_to_prev_diagnostic(
16240        &mut self,
16241        action: &GoToPreviousDiagnostic,
16242        window: &mut Window,
16243        cx: &mut Context<Self>,
16244    ) {
16245        if !self.diagnostics_enabled() {
16246            return;
16247        }
16248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16249        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16250    }
16251
16252    pub fn go_to_diagnostic_impl(
16253        &mut self,
16254        direction: Direction,
16255        severity: GoToDiagnosticSeverityFilter,
16256        window: &mut Window,
16257        cx: &mut Context<Self>,
16258    ) {
16259        let buffer = self.buffer.read(cx).snapshot(cx);
16260        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16261
16262        let mut active_group_id = None;
16263        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16264            && active_group.active_range.start.to_offset(&buffer) == selection.start
16265        {
16266            active_group_id = Some(active_group.group_id);
16267        }
16268
16269        fn filtered<'a>(
16270            severity: GoToDiagnosticSeverityFilter,
16271            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16272        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16273            diagnostics
16274                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16275                .filter(|entry| entry.range.start != entry.range.end)
16276                .filter(|entry| !entry.diagnostic.is_unnecessary)
16277        }
16278
16279        let before = filtered(
16280            severity,
16281            buffer
16282                .diagnostics_in_range(0..selection.start)
16283                .filter(|entry| entry.range.start <= selection.start),
16284        );
16285        let after = filtered(
16286            severity,
16287            buffer
16288                .diagnostics_in_range(selection.start..buffer.len())
16289                .filter(|entry| entry.range.start >= selection.start),
16290        );
16291
16292        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16293        if direction == Direction::Prev {
16294            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16295            {
16296                for diagnostic in prev_diagnostics.into_iter().rev() {
16297                    if diagnostic.range.start != selection.start
16298                        || active_group_id
16299                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16300                    {
16301                        found = Some(diagnostic);
16302                        break 'outer;
16303                    }
16304                }
16305            }
16306        } else {
16307            for diagnostic in after.chain(before) {
16308                if diagnostic.range.start != selection.start
16309                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16310                {
16311                    found = Some(diagnostic);
16312                    break;
16313                }
16314            }
16315        }
16316        let Some(next_diagnostic) = found else {
16317            return;
16318        };
16319
16320        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16321        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16322            return;
16323        };
16324        let snapshot = self.snapshot(window, cx);
16325        if snapshot.intersects_fold(next_diagnostic.range.start) {
16326            self.unfold_ranges(
16327                std::slice::from_ref(&next_diagnostic.range),
16328                true,
16329                false,
16330                cx,
16331            );
16332        }
16333        self.change_selections(Default::default(), window, cx, |s| {
16334            s.select_ranges(vec![
16335                next_diagnostic.range.start..next_diagnostic.range.start,
16336            ])
16337        });
16338        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16339        self.refresh_edit_prediction(false, true, window, cx);
16340    }
16341
16342    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16344        let snapshot = self.snapshot(window, cx);
16345        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16346        self.go_to_hunk_before_or_after_position(
16347            &snapshot,
16348            selection.head(),
16349            Direction::Next,
16350            window,
16351            cx,
16352        );
16353    }
16354
16355    pub fn go_to_hunk_before_or_after_position(
16356        &mut self,
16357        snapshot: &EditorSnapshot,
16358        position: Point,
16359        direction: Direction,
16360        window: &mut Window,
16361        cx: &mut Context<Editor>,
16362    ) {
16363        let row = if direction == Direction::Next {
16364            self.hunk_after_position(snapshot, position)
16365                .map(|hunk| hunk.row_range.start)
16366        } else {
16367            self.hunk_before_position(snapshot, position)
16368        };
16369
16370        if let Some(row) = row {
16371            let destination = Point::new(row.0, 0);
16372            let autoscroll = Autoscroll::center();
16373
16374            self.unfold_ranges(&[destination..destination], false, false, cx);
16375            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16376                s.select_ranges([destination..destination]);
16377            });
16378        }
16379    }
16380
16381    fn hunk_after_position(
16382        &mut self,
16383        snapshot: &EditorSnapshot,
16384        position: Point,
16385    ) -> Option<MultiBufferDiffHunk> {
16386        snapshot
16387            .buffer_snapshot()
16388            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16389            .find(|hunk| hunk.row_range.start.0 > position.row)
16390            .or_else(|| {
16391                snapshot
16392                    .buffer_snapshot()
16393                    .diff_hunks_in_range(Point::zero()..position)
16394                    .find(|hunk| hunk.row_range.end.0 < position.row)
16395            })
16396    }
16397
16398    fn go_to_prev_hunk(
16399        &mut self,
16400        _: &GoToPreviousHunk,
16401        window: &mut Window,
16402        cx: &mut Context<Self>,
16403    ) {
16404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16405        let snapshot = self.snapshot(window, cx);
16406        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16407        self.go_to_hunk_before_or_after_position(
16408            &snapshot,
16409            selection.head(),
16410            Direction::Prev,
16411            window,
16412            cx,
16413        );
16414    }
16415
16416    fn hunk_before_position(
16417        &mut self,
16418        snapshot: &EditorSnapshot,
16419        position: Point,
16420    ) -> Option<MultiBufferRow> {
16421        snapshot
16422            .buffer_snapshot()
16423            .diff_hunk_before(position)
16424            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16425    }
16426
16427    fn go_to_next_change(
16428        &mut self,
16429        _: &GoToNextChange,
16430        window: &mut Window,
16431        cx: &mut Context<Self>,
16432    ) {
16433        if let Some(selections) = self
16434            .change_list
16435            .next_change(1, Direction::Next)
16436            .map(|s| s.to_vec())
16437        {
16438            self.change_selections(Default::default(), window, cx, |s| {
16439                let map = s.display_snapshot();
16440                s.select_display_ranges(selections.iter().map(|a| {
16441                    let point = a.to_display_point(&map);
16442                    point..point
16443                }))
16444            })
16445        }
16446    }
16447
16448    fn go_to_previous_change(
16449        &mut self,
16450        _: &GoToPreviousChange,
16451        window: &mut Window,
16452        cx: &mut Context<Self>,
16453    ) {
16454        if let Some(selections) = self
16455            .change_list
16456            .next_change(1, Direction::Prev)
16457            .map(|s| s.to_vec())
16458        {
16459            self.change_selections(Default::default(), window, cx, |s| {
16460                let map = s.display_snapshot();
16461                s.select_display_ranges(selections.iter().map(|a| {
16462                    let point = a.to_display_point(&map);
16463                    point..point
16464                }))
16465            })
16466        }
16467    }
16468
16469    pub fn go_to_next_document_highlight(
16470        &mut self,
16471        _: &GoToNextDocumentHighlight,
16472        window: &mut Window,
16473        cx: &mut Context<Self>,
16474    ) {
16475        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16476    }
16477
16478    pub fn go_to_prev_document_highlight(
16479        &mut self,
16480        _: &GoToPreviousDocumentHighlight,
16481        window: &mut Window,
16482        cx: &mut Context<Self>,
16483    ) {
16484        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16485    }
16486
16487    pub fn go_to_document_highlight_before_or_after_position(
16488        &mut self,
16489        direction: Direction,
16490        window: &mut Window,
16491        cx: &mut Context<Editor>,
16492    ) {
16493        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16494        let snapshot = self.snapshot(window, cx);
16495        let buffer = &snapshot.buffer_snapshot();
16496        let position = self
16497            .selections
16498            .newest::<Point>(&snapshot.display_snapshot)
16499            .head();
16500        let anchor_position = buffer.anchor_after(position);
16501
16502        // Get all document highlights (both read and write)
16503        let mut all_highlights = Vec::new();
16504
16505        if let Some((_, read_highlights)) = self
16506            .background_highlights
16507            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16508        {
16509            all_highlights.extend(read_highlights.iter());
16510        }
16511
16512        if let Some((_, write_highlights)) = self
16513            .background_highlights
16514            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16515        {
16516            all_highlights.extend(write_highlights.iter());
16517        }
16518
16519        if all_highlights.is_empty() {
16520            return;
16521        }
16522
16523        // Sort highlights by position
16524        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16525
16526        let target_highlight = match direction {
16527            Direction::Next => {
16528                // Find the first highlight after the current position
16529                all_highlights
16530                    .iter()
16531                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16532            }
16533            Direction::Prev => {
16534                // Find the last highlight before the current position
16535                all_highlights
16536                    .iter()
16537                    .rev()
16538                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16539            }
16540        };
16541
16542        if let Some(highlight) = target_highlight {
16543            let destination = highlight.start.to_point(buffer);
16544            let autoscroll = Autoscroll::center();
16545
16546            self.unfold_ranges(&[destination..destination], false, false, cx);
16547            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16548                s.select_ranges([destination..destination]);
16549            });
16550        }
16551    }
16552
16553    fn go_to_line<T: 'static>(
16554        &mut self,
16555        position: Anchor,
16556        highlight_color: Option<Hsla>,
16557        window: &mut Window,
16558        cx: &mut Context<Self>,
16559    ) {
16560        let snapshot = self.snapshot(window, cx).display_snapshot;
16561        let position = position.to_point(&snapshot.buffer_snapshot());
16562        let start = snapshot
16563            .buffer_snapshot()
16564            .clip_point(Point::new(position.row, 0), Bias::Left);
16565        let end = start + Point::new(1, 0);
16566        let start = snapshot.buffer_snapshot().anchor_before(start);
16567        let end = snapshot.buffer_snapshot().anchor_before(end);
16568
16569        self.highlight_rows::<T>(
16570            start..end,
16571            highlight_color
16572                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16573            Default::default(),
16574            cx,
16575        );
16576
16577        if self.buffer.read(cx).is_singleton() {
16578            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16579        }
16580    }
16581
16582    pub fn go_to_definition(
16583        &mut self,
16584        _: &GoToDefinition,
16585        window: &mut Window,
16586        cx: &mut Context<Self>,
16587    ) -> Task<Result<Navigated>> {
16588        let definition =
16589            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16590        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16591        cx.spawn_in(window, async move |editor, cx| {
16592            if definition.await? == Navigated::Yes {
16593                return Ok(Navigated::Yes);
16594            }
16595            match fallback_strategy {
16596                GoToDefinitionFallback::None => Ok(Navigated::No),
16597                GoToDefinitionFallback::FindAllReferences => {
16598                    match editor.update_in(cx, |editor, window, cx| {
16599                        editor.find_all_references(&FindAllReferences, window, cx)
16600                    })? {
16601                        Some(references) => references.await,
16602                        None => Ok(Navigated::No),
16603                    }
16604                }
16605            }
16606        })
16607    }
16608
16609    pub fn go_to_declaration(
16610        &mut self,
16611        _: &GoToDeclaration,
16612        window: &mut Window,
16613        cx: &mut Context<Self>,
16614    ) -> Task<Result<Navigated>> {
16615        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16616    }
16617
16618    pub fn go_to_declaration_split(
16619        &mut self,
16620        _: &GoToDeclaration,
16621        window: &mut Window,
16622        cx: &mut Context<Self>,
16623    ) -> Task<Result<Navigated>> {
16624        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16625    }
16626
16627    pub fn go_to_implementation(
16628        &mut self,
16629        _: &GoToImplementation,
16630        window: &mut Window,
16631        cx: &mut Context<Self>,
16632    ) -> Task<Result<Navigated>> {
16633        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16634    }
16635
16636    pub fn go_to_implementation_split(
16637        &mut self,
16638        _: &GoToImplementationSplit,
16639        window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) -> Task<Result<Navigated>> {
16642        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16643    }
16644
16645    pub fn go_to_type_definition(
16646        &mut self,
16647        _: &GoToTypeDefinition,
16648        window: &mut Window,
16649        cx: &mut Context<Self>,
16650    ) -> Task<Result<Navigated>> {
16651        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16652    }
16653
16654    pub fn go_to_definition_split(
16655        &mut self,
16656        _: &GoToDefinitionSplit,
16657        window: &mut Window,
16658        cx: &mut Context<Self>,
16659    ) -> Task<Result<Navigated>> {
16660        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16661    }
16662
16663    pub fn go_to_type_definition_split(
16664        &mut self,
16665        _: &GoToTypeDefinitionSplit,
16666        window: &mut Window,
16667        cx: &mut Context<Self>,
16668    ) -> Task<Result<Navigated>> {
16669        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16670    }
16671
16672    fn go_to_definition_of_kind(
16673        &mut self,
16674        kind: GotoDefinitionKind,
16675        split: bool,
16676        window: &mut Window,
16677        cx: &mut Context<Self>,
16678    ) -> Task<Result<Navigated>> {
16679        let Some(provider) = self.semantics_provider.clone() else {
16680            return Task::ready(Ok(Navigated::No));
16681        };
16682        let head = self
16683            .selections
16684            .newest::<usize>(&self.display_snapshot(cx))
16685            .head();
16686        let buffer = self.buffer.read(cx);
16687        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16688            return Task::ready(Ok(Navigated::No));
16689        };
16690        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16691            return Task::ready(Ok(Navigated::No));
16692        };
16693
16694        cx.spawn_in(window, async move |editor, cx| {
16695            let Some(definitions) = definitions.await? else {
16696                return Ok(Navigated::No);
16697            };
16698            let navigated = editor
16699                .update_in(cx, |editor, window, cx| {
16700                    editor.navigate_to_hover_links(
16701                        Some(kind),
16702                        definitions
16703                            .into_iter()
16704                            .filter(|location| {
16705                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16706                            })
16707                            .map(HoverLink::Text)
16708                            .collect::<Vec<_>>(),
16709                        split,
16710                        window,
16711                        cx,
16712                    )
16713                })?
16714                .await?;
16715            anyhow::Ok(navigated)
16716        })
16717    }
16718
16719    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16720        let selection = self.selections.newest_anchor();
16721        let head = selection.head();
16722        let tail = selection.tail();
16723
16724        let Some((buffer, start_position)) =
16725            self.buffer.read(cx).text_anchor_for_position(head, cx)
16726        else {
16727            return;
16728        };
16729
16730        let end_position = if head != tail {
16731            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16732                return;
16733            };
16734            Some(pos)
16735        } else {
16736            None
16737        };
16738
16739        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16740            let url = if let Some(end_pos) = end_position {
16741                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16742            } else {
16743                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16744            };
16745
16746            if let Some(url) = url {
16747                cx.update(|window, cx| {
16748                    if parse_zed_link(&url, cx).is_some() {
16749                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16750                    } else {
16751                        cx.open_url(&url);
16752                    }
16753                })?;
16754            }
16755
16756            anyhow::Ok(())
16757        });
16758
16759        url_finder.detach();
16760    }
16761
16762    pub fn open_selected_filename(
16763        &mut self,
16764        _: &OpenSelectedFilename,
16765        window: &mut Window,
16766        cx: &mut Context<Self>,
16767    ) {
16768        let Some(workspace) = self.workspace() else {
16769            return;
16770        };
16771
16772        let position = self.selections.newest_anchor().head();
16773
16774        let Some((buffer, buffer_position)) =
16775            self.buffer.read(cx).text_anchor_for_position(position, cx)
16776        else {
16777            return;
16778        };
16779
16780        let project = self.project.clone();
16781
16782        cx.spawn_in(window, async move |_, cx| {
16783            let result = find_file(&buffer, project, buffer_position, cx).await;
16784
16785            if let Some((_, path)) = result {
16786                workspace
16787                    .update_in(cx, |workspace, window, cx| {
16788                        workspace.open_resolved_path(path, window, cx)
16789                    })?
16790                    .await?;
16791            }
16792            anyhow::Ok(())
16793        })
16794        .detach();
16795    }
16796
16797    pub(crate) fn navigate_to_hover_links(
16798        &mut self,
16799        kind: Option<GotoDefinitionKind>,
16800        definitions: Vec<HoverLink>,
16801        split: bool,
16802        window: &mut Window,
16803        cx: &mut Context<Editor>,
16804    ) -> Task<Result<Navigated>> {
16805        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16806        let mut first_url_or_file = None;
16807        let definitions: Vec<_> = definitions
16808            .into_iter()
16809            .filter_map(|def| match def {
16810                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16811                HoverLink::InlayHint(lsp_location, server_id) => {
16812                    let computation =
16813                        self.compute_target_location(lsp_location, server_id, window, cx);
16814                    Some(cx.background_spawn(computation))
16815                }
16816                HoverLink::Url(url) => {
16817                    first_url_or_file = Some(Either::Left(url));
16818                    None
16819                }
16820                HoverLink::File(path) => {
16821                    first_url_or_file = Some(Either::Right(path));
16822                    None
16823                }
16824            })
16825            .collect();
16826
16827        let workspace = self.workspace();
16828
16829        cx.spawn_in(window, async move |editor, cx| {
16830            let locations: Vec<Location> = future::join_all(definitions)
16831                .await
16832                .into_iter()
16833                .filter_map(|location| location.transpose())
16834                .collect::<Result<_>>()
16835                .context("location tasks")?;
16836            let mut locations = cx.update(|_, cx| {
16837                locations
16838                    .into_iter()
16839                    .map(|location| {
16840                        let buffer = location.buffer.read(cx);
16841                        (location.buffer, location.range.to_point(buffer))
16842                    })
16843                    .into_group_map()
16844            })?;
16845            let mut num_locations = 0;
16846            for ranges in locations.values_mut() {
16847                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16848                ranges.dedup();
16849                num_locations += ranges.len();
16850            }
16851
16852            if num_locations > 1 {
16853                let Some(workspace) = workspace else {
16854                    return Ok(Navigated::No);
16855                };
16856
16857                let tab_kind = match kind {
16858                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16859                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16860                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16861                    Some(GotoDefinitionKind::Type) => "Types",
16862                };
16863                let title = editor
16864                    .update_in(cx, |_, _, cx| {
16865                        let target = locations
16866                            .iter()
16867                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16868                            .map(|(buffer, location)| {
16869                                buffer
16870                                    .read(cx)
16871                                    .text_for_range(location.clone())
16872                                    .collect::<String>()
16873                            })
16874                            .filter(|text| !text.contains('\n'))
16875                            .unique()
16876                            .take(3)
16877                            .join(", ");
16878                        if target.is_empty() {
16879                            tab_kind.to_owned()
16880                        } else {
16881                            format!("{tab_kind} for {target}")
16882                        }
16883                    })
16884                    .context("buffer title")?;
16885
16886                let opened = workspace
16887                    .update_in(cx, |workspace, window, cx| {
16888                        Self::open_locations_in_multibuffer(
16889                            workspace,
16890                            locations,
16891                            title,
16892                            split,
16893                            MultibufferSelectionMode::First,
16894                            window,
16895                            cx,
16896                        )
16897                    })
16898                    .is_ok();
16899
16900                anyhow::Ok(Navigated::from_bool(opened))
16901            } else if num_locations == 0 {
16902                // If there is one url or file, open it directly
16903                match first_url_or_file {
16904                    Some(Either::Left(url)) => {
16905                        cx.update(|_, cx| cx.open_url(&url))?;
16906                        Ok(Navigated::Yes)
16907                    }
16908                    Some(Either::Right(path)) => {
16909                        let Some(workspace) = workspace else {
16910                            return Ok(Navigated::No);
16911                        };
16912
16913                        workspace
16914                            .update_in(cx, |workspace, window, cx| {
16915                                workspace.open_resolved_path(path, window, cx)
16916                            })?
16917                            .await?;
16918                        Ok(Navigated::Yes)
16919                    }
16920                    None => Ok(Navigated::No),
16921                }
16922            } else {
16923                let Some(workspace) = workspace else {
16924                    return Ok(Navigated::No);
16925                };
16926
16927                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16928                let target_range = target_ranges.first().unwrap().clone();
16929
16930                editor.update_in(cx, |editor, window, cx| {
16931                    let range = target_range.to_point(target_buffer.read(cx));
16932                    let range = editor.range_for_match(&range);
16933                    let range = collapse_multiline_range(range);
16934
16935                    if !split
16936                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16937                    {
16938                        editor.go_to_singleton_buffer_range(range, window, cx);
16939                    } else {
16940                        let pane = workspace.read(cx).active_pane().clone();
16941                        window.defer(cx, move |window, cx| {
16942                            let target_editor: Entity<Self> =
16943                                workspace.update(cx, |workspace, cx| {
16944                                    let pane = if split {
16945                                        workspace.adjacent_pane(window, cx)
16946                                    } else {
16947                                        workspace.active_pane().clone()
16948                                    };
16949
16950                                    workspace.open_project_item(
16951                                        pane,
16952                                        target_buffer.clone(),
16953                                        true,
16954                                        true,
16955                                        window,
16956                                        cx,
16957                                    )
16958                                });
16959                            target_editor.update(cx, |target_editor, cx| {
16960                                // When selecting a definition in a different buffer, disable the nav history
16961                                // to avoid creating a history entry at the previous cursor location.
16962                                pane.update(cx, |pane, _| pane.disable_history());
16963                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16964                                pane.update(cx, |pane, _| pane.enable_history());
16965                            });
16966                        });
16967                    }
16968                    Navigated::Yes
16969                })
16970            }
16971        })
16972    }
16973
16974    fn compute_target_location(
16975        &self,
16976        lsp_location: lsp::Location,
16977        server_id: LanguageServerId,
16978        window: &mut Window,
16979        cx: &mut Context<Self>,
16980    ) -> Task<anyhow::Result<Option<Location>>> {
16981        let Some(project) = self.project.clone() else {
16982            return Task::ready(Ok(None));
16983        };
16984
16985        cx.spawn_in(window, async move |editor, cx| {
16986            let location_task = editor.update(cx, |_, cx| {
16987                project.update(cx, |project, cx| {
16988                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16989                })
16990            })?;
16991            let location = Some({
16992                let target_buffer_handle = location_task.await.context("open local buffer")?;
16993                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16994                    let target_start = target_buffer
16995                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16996                    let target_end = target_buffer
16997                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16998                    target_buffer.anchor_after(target_start)
16999                        ..target_buffer.anchor_before(target_end)
17000                })?;
17001                Location {
17002                    buffer: target_buffer_handle,
17003                    range,
17004                }
17005            });
17006            Ok(location)
17007        })
17008    }
17009
17010    fn go_to_next_reference(
17011        &mut self,
17012        _: &GoToNextReference,
17013        window: &mut Window,
17014        cx: &mut Context<Self>,
17015    ) {
17016        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17017        if let Some(task) = task {
17018            task.detach();
17019        };
17020    }
17021
17022    fn go_to_prev_reference(
17023        &mut self,
17024        _: &GoToPreviousReference,
17025        window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17029        if let Some(task) = task {
17030            task.detach();
17031        };
17032    }
17033
17034    pub fn go_to_reference_before_or_after_position(
17035        &mut self,
17036        direction: Direction,
17037        count: usize,
17038        window: &mut Window,
17039        cx: &mut Context<Self>,
17040    ) -> Option<Task<Result<()>>> {
17041        let selection = self.selections.newest_anchor();
17042        let head = selection.head();
17043
17044        let multi_buffer = self.buffer.read(cx);
17045
17046        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17047        let workspace = self.workspace()?;
17048        let project = workspace.read(cx).project().clone();
17049        let references =
17050            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17051        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17052            let Some(locations) = references.await? else {
17053                return Ok(());
17054            };
17055
17056            if locations.is_empty() {
17057                // totally normal - the cursor may be on something which is not
17058                // a symbol (e.g. a keyword)
17059                log::info!("no references found under cursor");
17060                return Ok(());
17061            }
17062
17063            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17064
17065            let multi_buffer_snapshot =
17066                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
17067
17068            let (locations, current_location_index) =
17069                multi_buffer.update(cx, |multi_buffer, cx| {
17070                    let mut locations = locations
17071                        .into_iter()
17072                        .filter_map(|loc| {
17073                            let start = multi_buffer.buffer_anchor_to_anchor(
17074                                &loc.buffer,
17075                                loc.range.start,
17076                                cx,
17077                            )?;
17078                            let end = multi_buffer.buffer_anchor_to_anchor(
17079                                &loc.buffer,
17080                                loc.range.end,
17081                                cx,
17082                            )?;
17083                            Some(start..end)
17084                        })
17085                        .collect::<Vec<_>>();
17086
17087                    // There is an O(n) implementation, but given this list will be
17088                    // small (usually <100 items), the extra O(log(n)) factor isn't
17089                    // worth the (surprisingly large amount of) extra complexity.
17090                    locations
17091                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17092
17093                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17094
17095                    let current_location_index = locations.iter().position(|loc| {
17096                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17097                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17098                    });
17099
17100                    (locations, current_location_index)
17101                })?;
17102
17103            let Some(current_location_index) = current_location_index else {
17104                // This indicates something has gone wrong, because we already
17105                // handle the "no references" case above
17106                log::error!(
17107                    "failed to find current reference under cursor. Total references: {}",
17108                    locations.len()
17109                );
17110                return Ok(());
17111            };
17112
17113            let destination_location_index = match direction {
17114                Direction::Next => (current_location_index + count) % locations.len(),
17115                Direction::Prev => {
17116                    (current_location_index + locations.len() - count % locations.len())
17117                        % locations.len()
17118                }
17119            };
17120
17121            // TODO(cameron): is this needed?
17122            // the thinking is to avoid "jumping to the current location" (avoid
17123            // polluting "jumplist" in vim terms)
17124            if current_location_index == destination_location_index {
17125                return Ok(());
17126            }
17127
17128            let Range { start, end } = locations[destination_location_index];
17129
17130            editor.update_in(cx, |editor, window, cx| {
17131                let effects = SelectionEffects::default();
17132
17133                editor.unfold_ranges(&[start..end], false, false, cx);
17134                editor.change_selections(effects, window, cx, |s| {
17135                    s.select_ranges([start..start]);
17136                });
17137            })?;
17138
17139            Ok(())
17140        }))
17141    }
17142
17143    pub fn find_all_references(
17144        &mut self,
17145        _: &FindAllReferences,
17146        window: &mut Window,
17147        cx: &mut Context<Self>,
17148    ) -> Option<Task<Result<Navigated>>> {
17149        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17150        let multi_buffer = self.buffer.read(cx);
17151        let head = selection.head();
17152
17153        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17154        let head_anchor = multi_buffer_snapshot.anchor_at(
17155            head,
17156            if head < selection.tail() {
17157                Bias::Right
17158            } else {
17159                Bias::Left
17160            },
17161        );
17162
17163        match self
17164            .find_all_references_task_sources
17165            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17166        {
17167            Ok(_) => {
17168                log::info!(
17169                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17170                );
17171                return None;
17172            }
17173            Err(i) => {
17174                self.find_all_references_task_sources.insert(i, head_anchor);
17175            }
17176        }
17177
17178        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17179        let workspace = self.workspace()?;
17180        let project = workspace.read(cx).project().clone();
17181        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17182        Some(cx.spawn_in(window, async move |editor, cx| {
17183            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17184                if let Ok(i) = editor
17185                    .find_all_references_task_sources
17186                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17187                {
17188                    editor.find_all_references_task_sources.remove(i);
17189                }
17190            });
17191
17192            let Some(locations) = references.await? else {
17193                return anyhow::Ok(Navigated::No);
17194            };
17195            let mut locations = cx.update(|_, cx| {
17196                locations
17197                    .into_iter()
17198                    .map(|location| {
17199                        let buffer = location.buffer.read(cx);
17200                        (location.buffer, location.range.to_point(buffer))
17201                    })
17202                    .into_group_map()
17203            })?;
17204            if locations.is_empty() {
17205                return anyhow::Ok(Navigated::No);
17206            }
17207            for ranges in locations.values_mut() {
17208                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17209                ranges.dedup();
17210            }
17211
17212            workspace.update_in(cx, |workspace, window, cx| {
17213                let target = locations
17214                    .iter()
17215                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17216                    .map(|(buffer, location)| {
17217                        buffer
17218                            .read(cx)
17219                            .text_for_range(location.clone())
17220                            .collect::<String>()
17221                    })
17222                    .filter(|text| !text.contains('\n'))
17223                    .unique()
17224                    .take(3)
17225                    .join(", ");
17226                let title = if target.is_empty() {
17227                    "References".to_owned()
17228                } else {
17229                    format!("References to {target}")
17230                };
17231                Self::open_locations_in_multibuffer(
17232                    workspace,
17233                    locations,
17234                    title,
17235                    false,
17236                    MultibufferSelectionMode::First,
17237                    window,
17238                    cx,
17239                );
17240                Navigated::Yes
17241            })
17242        }))
17243    }
17244
17245    /// Opens a multibuffer with the given project locations in it
17246    pub fn open_locations_in_multibuffer(
17247        workspace: &mut Workspace,
17248        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17249        title: String,
17250        split: bool,
17251        multibuffer_selection_mode: MultibufferSelectionMode,
17252        window: &mut Window,
17253        cx: &mut Context<Workspace>,
17254    ) {
17255        if locations.is_empty() {
17256            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17257            return;
17258        }
17259
17260        let capability = workspace.project().read(cx).capability();
17261        let mut ranges = <Vec<Range<Anchor>>>::new();
17262
17263        // a key to find existing multibuffer editors with the same set of locations
17264        // to prevent us from opening more and more multibuffer tabs for searches and the like
17265        let mut key = (title.clone(), vec![]);
17266        let excerpt_buffer = cx.new(|cx| {
17267            let key = &mut key.1;
17268            let mut multibuffer = MultiBuffer::new(capability);
17269            for (buffer, mut ranges_for_buffer) in locations {
17270                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17271                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17272                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17273                    PathKey::for_buffer(&buffer, cx),
17274                    buffer.clone(),
17275                    ranges_for_buffer,
17276                    multibuffer_context_lines(cx),
17277                    cx,
17278                );
17279                ranges.extend(new_ranges)
17280            }
17281
17282            multibuffer.with_title(title)
17283        });
17284        let existing = workspace.active_pane().update(cx, |pane, cx| {
17285            pane.items()
17286                .filter_map(|item| item.downcast::<Editor>())
17287                .find(|editor| {
17288                    editor
17289                        .read(cx)
17290                        .lookup_key
17291                        .as_ref()
17292                        .and_then(|it| {
17293                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17294                        })
17295                        .is_some_and(|it| *it == key)
17296                })
17297        });
17298        let editor = existing.unwrap_or_else(|| {
17299            cx.new(|cx| {
17300                let mut editor = Editor::for_multibuffer(
17301                    excerpt_buffer,
17302                    Some(workspace.project().clone()),
17303                    window,
17304                    cx,
17305                );
17306                editor.lookup_key = Some(Box::new(key));
17307                editor
17308            })
17309        });
17310        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17311            MultibufferSelectionMode::First => {
17312                if let Some(first_range) = ranges.first() {
17313                    editor.change_selections(
17314                        SelectionEffects::no_scroll(),
17315                        window,
17316                        cx,
17317                        |selections| {
17318                            selections.clear_disjoint();
17319                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17320                        },
17321                    );
17322                }
17323                editor.highlight_background::<Self>(
17324                    &ranges,
17325                    |theme| theme.colors().editor_highlighted_line_background,
17326                    cx,
17327                );
17328            }
17329            MultibufferSelectionMode::All => {
17330                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17331                    selections.clear_disjoint();
17332                    selections.select_anchor_ranges(ranges);
17333                });
17334            }
17335        });
17336
17337        let item = Box::new(editor);
17338        let item_id = item.item_id();
17339
17340        if split {
17341            let pane = workspace.adjacent_pane(window, cx);
17342            workspace.add_item(pane, item, None, true, true, window, cx);
17343        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17344            let (preview_item_id, preview_item_idx) =
17345                workspace.active_pane().read_with(cx, |pane, _| {
17346                    (pane.preview_item_id(), pane.preview_item_idx())
17347                });
17348
17349            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17350
17351            if let Some(preview_item_id) = preview_item_id {
17352                workspace.active_pane().update(cx, |pane, cx| {
17353                    pane.remove_item(preview_item_id, false, false, window, cx);
17354                });
17355            }
17356        } else {
17357            workspace.add_item_to_active_pane(item, None, true, window, cx);
17358        }
17359        workspace.active_pane().update(cx, |pane, cx| {
17360            pane.set_preview_item_id(Some(item_id), cx);
17361        });
17362    }
17363
17364    pub fn rename(
17365        &mut self,
17366        _: &Rename,
17367        window: &mut Window,
17368        cx: &mut Context<Self>,
17369    ) -> Option<Task<Result<()>>> {
17370        use language::ToOffset as _;
17371
17372        let provider = self.semantics_provider.clone()?;
17373        let selection = self.selections.newest_anchor().clone();
17374        let (cursor_buffer, cursor_buffer_position) = self
17375            .buffer
17376            .read(cx)
17377            .text_anchor_for_position(selection.head(), cx)?;
17378        let (tail_buffer, cursor_buffer_position_end) = self
17379            .buffer
17380            .read(cx)
17381            .text_anchor_for_position(selection.tail(), cx)?;
17382        if tail_buffer != cursor_buffer {
17383            return None;
17384        }
17385
17386        let snapshot = cursor_buffer.read(cx).snapshot();
17387        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17388        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17389        let prepare_rename = provider
17390            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17391            .unwrap_or_else(|| Task::ready(Ok(None)));
17392        drop(snapshot);
17393
17394        Some(cx.spawn_in(window, async move |this, cx| {
17395            let rename_range = if let Some(range) = prepare_rename.await? {
17396                Some(range)
17397            } else {
17398                this.update(cx, |this, cx| {
17399                    let buffer = this.buffer.read(cx).snapshot(cx);
17400                    let mut buffer_highlights = this
17401                        .document_highlights_for_position(selection.head(), &buffer)
17402                        .filter(|highlight| {
17403                            highlight.start.excerpt_id == selection.head().excerpt_id
17404                                && highlight.end.excerpt_id == selection.head().excerpt_id
17405                        });
17406                    buffer_highlights
17407                        .next()
17408                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17409                })?
17410            };
17411            if let Some(rename_range) = rename_range {
17412                this.update_in(cx, |this, window, cx| {
17413                    let snapshot = cursor_buffer.read(cx).snapshot();
17414                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17415                    let cursor_offset_in_rename_range =
17416                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17417                    let cursor_offset_in_rename_range_end =
17418                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17419
17420                    this.take_rename(false, window, cx);
17421                    let buffer = this.buffer.read(cx).read(cx);
17422                    let cursor_offset = selection.head().to_offset(&buffer);
17423                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17424                    let rename_end = rename_start + rename_buffer_range.len();
17425                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17426                    let mut old_highlight_id = None;
17427                    let old_name: Arc<str> = buffer
17428                        .chunks(rename_start..rename_end, true)
17429                        .map(|chunk| {
17430                            if old_highlight_id.is_none() {
17431                                old_highlight_id = chunk.syntax_highlight_id;
17432                            }
17433                            chunk.text
17434                        })
17435                        .collect::<String>()
17436                        .into();
17437
17438                    drop(buffer);
17439
17440                    // Position the selection in the rename editor so that it matches the current selection.
17441                    this.show_local_selections = false;
17442                    let rename_editor = cx.new(|cx| {
17443                        let mut editor = Editor::single_line(window, cx);
17444                        editor.buffer.update(cx, |buffer, cx| {
17445                            buffer.edit([(0..0, old_name.clone())], None, cx)
17446                        });
17447                        let rename_selection_range = match cursor_offset_in_rename_range
17448                            .cmp(&cursor_offset_in_rename_range_end)
17449                        {
17450                            Ordering::Equal => {
17451                                editor.select_all(&SelectAll, window, cx);
17452                                return editor;
17453                            }
17454                            Ordering::Less => {
17455                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17456                            }
17457                            Ordering::Greater => {
17458                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17459                            }
17460                        };
17461                        if rename_selection_range.end > old_name.len() {
17462                            editor.select_all(&SelectAll, window, cx);
17463                        } else {
17464                            editor.change_selections(Default::default(), window, cx, |s| {
17465                                s.select_ranges([rename_selection_range]);
17466                            });
17467                        }
17468                        editor
17469                    });
17470                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17471                        if e == &EditorEvent::Focused {
17472                            cx.emit(EditorEvent::FocusedIn)
17473                        }
17474                    })
17475                    .detach();
17476
17477                    let write_highlights =
17478                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17479                    let read_highlights =
17480                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17481                    let ranges = write_highlights
17482                        .iter()
17483                        .flat_map(|(_, ranges)| ranges.iter())
17484                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17485                        .cloned()
17486                        .collect();
17487
17488                    this.highlight_text::<Rename>(
17489                        ranges,
17490                        HighlightStyle {
17491                            fade_out: Some(0.6),
17492                            ..Default::default()
17493                        },
17494                        cx,
17495                    );
17496                    let rename_focus_handle = rename_editor.focus_handle(cx);
17497                    window.focus(&rename_focus_handle);
17498                    let block_id = this.insert_blocks(
17499                        [BlockProperties {
17500                            style: BlockStyle::Flex,
17501                            placement: BlockPlacement::Below(range.start),
17502                            height: Some(1),
17503                            render: Arc::new({
17504                                let rename_editor = rename_editor.clone();
17505                                move |cx: &mut BlockContext| {
17506                                    let mut text_style = cx.editor_style.text.clone();
17507                                    if let Some(highlight_style) = old_highlight_id
17508                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17509                                    {
17510                                        text_style = text_style.highlight(highlight_style);
17511                                    }
17512                                    div()
17513                                        .block_mouse_except_scroll()
17514                                        .pl(cx.anchor_x)
17515                                        .child(EditorElement::new(
17516                                            &rename_editor,
17517                                            EditorStyle {
17518                                                background: cx.theme().system().transparent,
17519                                                local_player: cx.editor_style.local_player,
17520                                                text: text_style,
17521                                                scrollbar_width: cx.editor_style.scrollbar_width,
17522                                                syntax: cx.editor_style.syntax.clone(),
17523                                                status: cx.editor_style.status.clone(),
17524                                                inlay_hints_style: HighlightStyle {
17525                                                    font_weight: Some(FontWeight::BOLD),
17526                                                    ..make_inlay_hints_style(cx.app)
17527                                                },
17528                                                edit_prediction_styles: make_suggestion_styles(
17529                                                    cx.app,
17530                                                ),
17531                                                ..EditorStyle::default()
17532                                            },
17533                                        ))
17534                                        .into_any_element()
17535                                }
17536                            }),
17537                            priority: 0,
17538                        }],
17539                        Some(Autoscroll::fit()),
17540                        cx,
17541                    )[0];
17542                    this.pending_rename = Some(RenameState {
17543                        range,
17544                        old_name,
17545                        editor: rename_editor,
17546                        block_id,
17547                    });
17548                })?;
17549            }
17550
17551            Ok(())
17552        }))
17553    }
17554
17555    pub fn confirm_rename(
17556        &mut self,
17557        _: &ConfirmRename,
17558        window: &mut Window,
17559        cx: &mut Context<Self>,
17560    ) -> Option<Task<Result<()>>> {
17561        let rename = self.take_rename(false, window, cx)?;
17562        let workspace = self.workspace()?.downgrade();
17563        let (buffer, start) = self
17564            .buffer
17565            .read(cx)
17566            .text_anchor_for_position(rename.range.start, cx)?;
17567        let (end_buffer, _) = self
17568            .buffer
17569            .read(cx)
17570            .text_anchor_for_position(rename.range.end, cx)?;
17571        if buffer != end_buffer {
17572            return None;
17573        }
17574
17575        let old_name = rename.old_name;
17576        let new_name = rename.editor.read(cx).text(cx);
17577
17578        let rename = self.semantics_provider.as_ref()?.perform_rename(
17579            &buffer,
17580            start,
17581            new_name.clone(),
17582            cx,
17583        )?;
17584
17585        Some(cx.spawn_in(window, async move |editor, cx| {
17586            let project_transaction = rename.await?;
17587            Self::open_project_transaction(
17588                &editor,
17589                workspace,
17590                project_transaction,
17591                format!("Rename: {}{}", old_name, new_name),
17592                cx,
17593            )
17594            .await?;
17595
17596            editor.update(cx, |editor, cx| {
17597                editor.refresh_document_highlights(cx);
17598            })?;
17599            Ok(())
17600        }))
17601    }
17602
17603    fn take_rename(
17604        &mut self,
17605        moving_cursor: bool,
17606        window: &mut Window,
17607        cx: &mut Context<Self>,
17608    ) -> Option<RenameState> {
17609        let rename = self.pending_rename.take()?;
17610        if rename.editor.focus_handle(cx).is_focused(window) {
17611            window.focus(&self.focus_handle);
17612        }
17613
17614        self.remove_blocks(
17615            [rename.block_id].into_iter().collect(),
17616            Some(Autoscroll::fit()),
17617            cx,
17618        );
17619        self.clear_highlights::<Rename>(cx);
17620        self.show_local_selections = true;
17621
17622        if moving_cursor {
17623            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17624                editor
17625                    .selections
17626                    .newest::<usize>(&editor.display_snapshot(cx))
17627                    .head()
17628            });
17629
17630            // Update the selection to match the position of the selection inside
17631            // the rename editor.
17632            let snapshot = self.buffer.read(cx).read(cx);
17633            let rename_range = rename.range.to_offset(&snapshot);
17634            let cursor_in_editor = snapshot
17635                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17636                .min(rename_range.end);
17637            drop(snapshot);
17638
17639            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17640                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17641            });
17642        } else {
17643            self.refresh_document_highlights(cx);
17644        }
17645
17646        Some(rename)
17647    }
17648
17649    pub fn pending_rename(&self) -> Option<&RenameState> {
17650        self.pending_rename.as_ref()
17651    }
17652
17653    fn format(
17654        &mut self,
17655        _: &Format,
17656        window: &mut Window,
17657        cx: &mut Context<Self>,
17658    ) -> Option<Task<Result<()>>> {
17659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17660
17661        let project = match &self.project {
17662            Some(project) => project.clone(),
17663            None => return None,
17664        };
17665
17666        Some(self.perform_format(
17667            project,
17668            FormatTrigger::Manual,
17669            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17670            window,
17671            cx,
17672        ))
17673    }
17674
17675    fn format_selections(
17676        &mut self,
17677        _: &FormatSelections,
17678        window: &mut Window,
17679        cx: &mut Context<Self>,
17680    ) -> Option<Task<Result<()>>> {
17681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17682
17683        let project = match &self.project {
17684            Some(project) => project.clone(),
17685            None => return None,
17686        };
17687
17688        let ranges = self
17689            .selections
17690            .all_adjusted(&self.display_snapshot(cx))
17691            .into_iter()
17692            .map(|selection| selection.range())
17693            .collect_vec();
17694
17695        Some(self.perform_format(
17696            project,
17697            FormatTrigger::Manual,
17698            FormatTarget::Ranges(ranges),
17699            window,
17700            cx,
17701        ))
17702    }
17703
17704    fn perform_format(
17705        &mut self,
17706        project: Entity<Project>,
17707        trigger: FormatTrigger,
17708        target: FormatTarget,
17709        window: &mut Window,
17710        cx: &mut Context<Self>,
17711    ) -> Task<Result<()>> {
17712        let buffer = self.buffer.clone();
17713        let (buffers, target) = match target {
17714            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17715            FormatTarget::Ranges(selection_ranges) => {
17716                let multi_buffer = buffer.read(cx);
17717                let snapshot = multi_buffer.read(cx);
17718                let mut buffers = HashSet::default();
17719                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17720                    BTreeMap::new();
17721                for selection_range in selection_ranges {
17722                    for (buffer, buffer_range, _) in
17723                        snapshot.range_to_buffer_ranges(selection_range)
17724                    {
17725                        let buffer_id = buffer.remote_id();
17726                        let start = buffer.anchor_before(buffer_range.start);
17727                        let end = buffer.anchor_after(buffer_range.end);
17728                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17729                        buffer_id_to_ranges
17730                            .entry(buffer_id)
17731                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17732                            .or_insert_with(|| vec![start..end]);
17733                    }
17734                }
17735                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17736            }
17737        };
17738
17739        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17740        let selections_prev = transaction_id_prev
17741            .and_then(|transaction_id_prev| {
17742                // default to selections as they were after the last edit, if we have them,
17743                // instead of how they are now.
17744                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17745                // will take you back to where you made the last edit, instead of staying where you scrolled
17746                self.selection_history
17747                    .transaction(transaction_id_prev)
17748                    .map(|t| t.0.clone())
17749            })
17750            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17751
17752        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17753        let format = project.update(cx, |project, cx| {
17754            project.format(buffers, target, true, trigger, cx)
17755        });
17756
17757        cx.spawn_in(window, async move |editor, cx| {
17758            let transaction = futures::select_biased! {
17759                transaction = format.log_err().fuse() => transaction,
17760                () = timeout => {
17761                    log::warn!("timed out waiting for formatting");
17762                    None
17763                }
17764            };
17765
17766            buffer
17767                .update(cx, |buffer, cx| {
17768                    if let Some(transaction) = transaction
17769                        && !buffer.is_singleton()
17770                    {
17771                        buffer.push_transaction(&transaction.0, cx);
17772                    }
17773                    cx.notify();
17774                })
17775                .ok();
17776
17777            if let Some(transaction_id_now) =
17778                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17779            {
17780                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17781                if has_new_transaction {
17782                    _ = editor.update(cx, |editor, _| {
17783                        editor
17784                            .selection_history
17785                            .insert_transaction(transaction_id_now, selections_prev);
17786                    });
17787                }
17788            }
17789
17790            Ok(())
17791        })
17792    }
17793
17794    fn organize_imports(
17795        &mut self,
17796        _: &OrganizeImports,
17797        window: &mut Window,
17798        cx: &mut Context<Self>,
17799    ) -> Option<Task<Result<()>>> {
17800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17801        let project = match &self.project {
17802            Some(project) => project.clone(),
17803            None => return None,
17804        };
17805        Some(self.perform_code_action_kind(
17806            project,
17807            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17808            window,
17809            cx,
17810        ))
17811    }
17812
17813    fn perform_code_action_kind(
17814        &mut self,
17815        project: Entity<Project>,
17816        kind: CodeActionKind,
17817        window: &mut Window,
17818        cx: &mut Context<Self>,
17819    ) -> Task<Result<()>> {
17820        let buffer = self.buffer.clone();
17821        let buffers = buffer.read(cx).all_buffers();
17822        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17823        let apply_action = project.update(cx, |project, cx| {
17824            project.apply_code_action_kind(buffers, kind, true, cx)
17825        });
17826        cx.spawn_in(window, async move |_, cx| {
17827            let transaction = futures::select_biased! {
17828                () = timeout => {
17829                    log::warn!("timed out waiting for executing code action");
17830                    None
17831                }
17832                transaction = apply_action.log_err().fuse() => transaction,
17833            };
17834            buffer
17835                .update(cx, |buffer, cx| {
17836                    // check if we need this
17837                    if let Some(transaction) = transaction
17838                        && !buffer.is_singleton()
17839                    {
17840                        buffer.push_transaction(&transaction.0, cx);
17841                    }
17842                    cx.notify();
17843                })
17844                .ok();
17845            Ok(())
17846        })
17847    }
17848
17849    pub fn restart_language_server(
17850        &mut self,
17851        _: &RestartLanguageServer,
17852        _: &mut Window,
17853        cx: &mut Context<Self>,
17854    ) {
17855        if let Some(project) = self.project.clone() {
17856            self.buffer.update(cx, |multi_buffer, cx| {
17857                project.update(cx, |project, cx| {
17858                    project.restart_language_servers_for_buffers(
17859                        multi_buffer.all_buffers().into_iter().collect(),
17860                        HashSet::default(),
17861                        cx,
17862                    );
17863                });
17864            })
17865        }
17866    }
17867
17868    pub fn stop_language_server(
17869        &mut self,
17870        _: &StopLanguageServer,
17871        _: &mut Window,
17872        cx: &mut Context<Self>,
17873    ) {
17874        if let Some(project) = self.project.clone() {
17875            self.buffer.update(cx, |multi_buffer, cx| {
17876                project.update(cx, |project, cx| {
17877                    project.stop_language_servers_for_buffers(
17878                        multi_buffer.all_buffers().into_iter().collect(),
17879                        HashSet::default(),
17880                        cx,
17881                    );
17882                });
17883            });
17884            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17885        }
17886    }
17887
17888    fn cancel_language_server_work(
17889        workspace: &mut Workspace,
17890        _: &actions::CancelLanguageServerWork,
17891        _: &mut Window,
17892        cx: &mut Context<Workspace>,
17893    ) {
17894        let project = workspace.project();
17895        let buffers = workspace
17896            .active_item(cx)
17897            .and_then(|item| item.act_as::<Editor>(cx))
17898            .map_or(HashSet::default(), |editor| {
17899                editor.read(cx).buffer.read(cx).all_buffers()
17900            });
17901        project.update(cx, |project, cx| {
17902            project.cancel_language_server_work_for_buffers(buffers, cx);
17903        });
17904    }
17905
17906    fn show_character_palette(
17907        &mut self,
17908        _: &ShowCharacterPalette,
17909        window: &mut Window,
17910        _: &mut Context<Self>,
17911    ) {
17912        window.show_character_palette();
17913    }
17914
17915    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17916        if !self.diagnostics_enabled() {
17917            return;
17918        }
17919
17920        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17921            let buffer = self.buffer.read(cx).snapshot(cx);
17922            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17923            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17924            let is_valid = buffer
17925                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17926                .any(|entry| {
17927                    entry.diagnostic.is_primary
17928                        && !entry.range.is_empty()
17929                        && entry.range.start == primary_range_start
17930                        && entry.diagnostic.message == active_diagnostics.active_message
17931                });
17932
17933            if !is_valid {
17934                self.dismiss_diagnostics(cx);
17935            }
17936        }
17937    }
17938
17939    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17940        match &self.active_diagnostics {
17941            ActiveDiagnostic::Group(group) => Some(group),
17942            _ => None,
17943        }
17944    }
17945
17946    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17947        if !self.diagnostics_enabled() {
17948            return;
17949        }
17950        self.dismiss_diagnostics(cx);
17951        self.active_diagnostics = ActiveDiagnostic::All;
17952    }
17953
17954    fn activate_diagnostics(
17955        &mut self,
17956        buffer_id: BufferId,
17957        diagnostic: DiagnosticEntryRef<'_, usize>,
17958        window: &mut Window,
17959        cx: &mut Context<Self>,
17960    ) {
17961        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17962            return;
17963        }
17964        self.dismiss_diagnostics(cx);
17965        let snapshot = self.snapshot(window, cx);
17966        let buffer = self.buffer.read(cx).snapshot(cx);
17967        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17968            return;
17969        };
17970
17971        let diagnostic_group = buffer
17972            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17973            .collect::<Vec<_>>();
17974
17975        let language_registry = self
17976            .project()
17977            .map(|project| project.read(cx).languages().clone());
17978
17979        let blocks = renderer.render_group(
17980            diagnostic_group,
17981            buffer_id,
17982            snapshot,
17983            cx.weak_entity(),
17984            language_registry,
17985            cx,
17986        );
17987
17988        let blocks = self.display_map.update(cx, |display_map, cx| {
17989            display_map.insert_blocks(blocks, cx).into_iter().collect()
17990        });
17991        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17992            active_range: buffer.anchor_before(diagnostic.range.start)
17993                ..buffer.anchor_after(diagnostic.range.end),
17994            active_message: diagnostic.diagnostic.message.clone(),
17995            group_id: diagnostic.diagnostic.group_id,
17996            blocks,
17997        });
17998        cx.notify();
17999    }
18000
18001    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18002        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18003            return;
18004        };
18005
18006        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18007        if let ActiveDiagnostic::Group(group) = prev {
18008            self.display_map.update(cx, |display_map, cx| {
18009                display_map.remove_blocks(group.blocks, cx);
18010            });
18011            cx.notify();
18012        }
18013    }
18014
18015    /// Disable inline diagnostics rendering for this editor.
18016    pub fn disable_inline_diagnostics(&mut self) {
18017        self.inline_diagnostics_enabled = false;
18018        self.inline_diagnostics_update = Task::ready(());
18019        self.inline_diagnostics.clear();
18020    }
18021
18022    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18023        self.diagnostics_enabled = false;
18024        self.dismiss_diagnostics(cx);
18025        self.inline_diagnostics_update = Task::ready(());
18026        self.inline_diagnostics.clear();
18027    }
18028
18029    pub fn disable_word_completions(&mut self) {
18030        self.word_completions_enabled = false;
18031    }
18032
18033    pub fn diagnostics_enabled(&self) -> bool {
18034        self.diagnostics_enabled && self.mode.is_full()
18035    }
18036
18037    pub fn inline_diagnostics_enabled(&self) -> bool {
18038        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18039    }
18040
18041    pub fn show_inline_diagnostics(&self) -> bool {
18042        self.show_inline_diagnostics
18043    }
18044
18045    pub fn toggle_inline_diagnostics(
18046        &mut self,
18047        _: &ToggleInlineDiagnostics,
18048        window: &mut Window,
18049        cx: &mut Context<Editor>,
18050    ) {
18051        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18052        self.refresh_inline_diagnostics(false, window, cx);
18053    }
18054
18055    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18056        self.diagnostics_max_severity = severity;
18057        self.display_map.update(cx, |display_map, _| {
18058            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18059        });
18060    }
18061
18062    pub fn toggle_diagnostics(
18063        &mut self,
18064        _: &ToggleDiagnostics,
18065        window: &mut Window,
18066        cx: &mut Context<Editor>,
18067    ) {
18068        if !self.diagnostics_enabled() {
18069            return;
18070        }
18071
18072        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18073            EditorSettings::get_global(cx)
18074                .diagnostics_max_severity
18075                .filter(|severity| severity != &DiagnosticSeverity::Off)
18076                .unwrap_or(DiagnosticSeverity::Hint)
18077        } else {
18078            DiagnosticSeverity::Off
18079        };
18080        self.set_max_diagnostics_severity(new_severity, cx);
18081        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18082            self.active_diagnostics = ActiveDiagnostic::None;
18083            self.inline_diagnostics_update = Task::ready(());
18084            self.inline_diagnostics.clear();
18085        } else {
18086            self.refresh_inline_diagnostics(false, window, cx);
18087        }
18088
18089        cx.notify();
18090    }
18091
18092    pub fn toggle_minimap(
18093        &mut self,
18094        _: &ToggleMinimap,
18095        window: &mut Window,
18096        cx: &mut Context<Editor>,
18097    ) {
18098        if self.supports_minimap(cx) {
18099            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18100        }
18101    }
18102
18103    fn refresh_inline_diagnostics(
18104        &mut self,
18105        debounce: bool,
18106        window: &mut Window,
18107        cx: &mut Context<Self>,
18108    ) {
18109        let max_severity = ProjectSettings::get_global(cx)
18110            .diagnostics
18111            .inline
18112            .max_severity
18113            .unwrap_or(self.diagnostics_max_severity);
18114
18115        if !self.inline_diagnostics_enabled()
18116            || !self.diagnostics_enabled()
18117            || !self.show_inline_diagnostics
18118            || max_severity == DiagnosticSeverity::Off
18119        {
18120            self.inline_diagnostics_update = Task::ready(());
18121            self.inline_diagnostics.clear();
18122            return;
18123        }
18124
18125        let debounce_ms = ProjectSettings::get_global(cx)
18126            .diagnostics
18127            .inline
18128            .update_debounce_ms;
18129        let debounce = if debounce && debounce_ms > 0 {
18130            Some(Duration::from_millis(debounce_ms))
18131        } else {
18132            None
18133        };
18134        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18135            if let Some(debounce) = debounce {
18136                cx.background_executor().timer(debounce).await;
18137            }
18138            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18139                editor
18140                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18141                    .ok()
18142            }) else {
18143                return;
18144            };
18145
18146            let new_inline_diagnostics = cx
18147                .background_spawn(async move {
18148                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18149                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18150                        let message = diagnostic_entry
18151                            .diagnostic
18152                            .message
18153                            .split_once('\n')
18154                            .map(|(line, _)| line)
18155                            .map(SharedString::new)
18156                            .unwrap_or_else(|| {
18157                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18158                            });
18159                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18160                        let (Ok(i) | Err(i)) = inline_diagnostics
18161                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18162                        inline_diagnostics.insert(
18163                            i,
18164                            (
18165                                start_anchor,
18166                                InlineDiagnostic {
18167                                    message,
18168                                    group_id: diagnostic_entry.diagnostic.group_id,
18169                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18170                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18171                                    severity: diagnostic_entry.diagnostic.severity,
18172                                },
18173                            ),
18174                        );
18175                    }
18176                    inline_diagnostics
18177                })
18178                .await;
18179
18180            editor
18181                .update(cx, |editor, cx| {
18182                    editor.inline_diagnostics = new_inline_diagnostics;
18183                    cx.notify();
18184                })
18185                .ok();
18186        });
18187    }
18188
18189    fn pull_diagnostics(
18190        &mut self,
18191        buffer_id: Option<BufferId>,
18192        window: &Window,
18193        cx: &mut Context<Self>,
18194    ) -> Option<()> {
18195        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18196            return None;
18197        }
18198        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18199            .diagnostics
18200            .lsp_pull_diagnostics;
18201        if !pull_diagnostics_settings.enabled {
18202            return None;
18203        }
18204        let project = self.project()?.downgrade();
18205        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18206        let mut buffers = self.buffer.read(cx).all_buffers();
18207        buffers.retain(|buffer| {
18208            let buffer_id_to_retain = buffer.read(cx).remote_id();
18209            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18210                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18211        });
18212        if buffers.is_empty() {
18213            self.pull_diagnostics_task = Task::ready(());
18214            return None;
18215        }
18216
18217        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18218            cx.background_executor().timer(debounce).await;
18219
18220            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18221                buffers
18222                    .into_iter()
18223                    .filter_map(|buffer| {
18224                        project
18225                            .update(cx, |project, cx| {
18226                                project.lsp_store().update(cx, |lsp_store, cx| {
18227                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18228                                })
18229                            })
18230                            .ok()
18231                    })
18232                    .collect::<FuturesUnordered<_>>()
18233            }) else {
18234                return;
18235            };
18236
18237            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18238                match pull_task {
18239                    Ok(()) => {
18240                        if editor
18241                            .update_in(cx, |editor, window, cx| {
18242                                editor.update_diagnostics_state(window, cx);
18243                            })
18244                            .is_err()
18245                        {
18246                            return;
18247                        }
18248                    }
18249                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18250                }
18251            }
18252        });
18253
18254        Some(())
18255    }
18256
18257    pub fn set_selections_from_remote(
18258        &mut self,
18259        selections: Vec<Selection<Anchor>>,
18260        pending_selection: Option<Selection<Anchor>>,
18261        window: &mut Window,
18262        cx: &mut Context<Self>,
18263    ) {
18264        let old_cursor_position = self.selections.newest_anchor().head();
18265        self.selections
18266            .change_with(&self.display_snapshot(cx), |s| {
18267                s.select_anchors(selections);
18268                if let Some(pending_selection) = pending_selection {
18269                    s.set_pending(pending_selection, SelectMode::Character);
18270                } else {
18271                    s.clear_pending();
18272                }
18273            });
18274        self.selections_did_change(
18275            false,
18276            &old_cursor_position,
18277            SelectionEffects::default(),
18278            window,
18279            cx,
18280        );
18281    }
18282
18283    pub fn transact(
18284        &mut self,
18285        window: &mut Window,
18286        cx: &mut Context<Self>,
18287        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18288    ) -> Option<TransactionId> {
18289        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18290            this.start_transaction_at(Instant::now(), window, cx);
18291            update(this, window, cx);
18292            this.end_transaction_at(Instant::now(), cx)
18293        })
18294    }
18295
18296    pub fn start_transaction_at(
18297        &mut self,
18298        now: Instant,
18299        window: &mut Window,
18300        cx: &mut Context<Self>,
18301    ) -> Option<TransactionId> {
18302        self.end_selection(window, cx);
18303        if let Some(tx_id) = self
18304            .buffer
18305            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18306        {
18307            self.selection_history
18308                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18309            cx.emit(EditorEvent::TransactionBegun {
18310                transaction_id: tx_id,
18311            });
18312            Some(tx_id)
18313        } else {
18314            None
18315        }
18316    }
18317
18318    pub fn end_transaction_at(
18319        &mut self,
18320        now: Instant,
18321        cx: &mut Context<Self>,
18322    ) -> Option<TransactionId> {
18323        if let Some(transaction_id) = self
18324            .buffer
18325            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18326        {
18327            if let Some((_, end_selections)) =
18328                self.selection_history.transaction_mut(transaction_id)
18329            {
18330                *end_selections = Some(self.selections.disjoint_anchors_arc());
18331            } else {
18332                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18333            }
18334
18335            cx.emit(EditorEvent::Edited { transaction_id });
18336            Some(transaction_id)
18337        } else {
18338            None
18339        }
18340    }
18341
18342    pub fn modify_transaction_selection_history(
18343        &mut self,
18344        transaction_id: TransactionId,
18345        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18346    ) -> bool {
18347        self.selection_history
18348            .transaction_mut(transaction_id)
18349            .map(modify)
18350            .is_some()
18351    }
18352
18353    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18354        if self.selection_mark_mode {
18355            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18356                s.move_with(|_, sel| {
18357                    sel.collapse_to(sel.head(), SelectionGoal::None);
18358                });
18359            })
18360        }
18361        self.selection_mark_mode = true;
18362        cx.notify();
18363    }
18364
18365    pub fn swap_selection_ends(
18366        &mut self,
18367        _: &actions::SwapSelectionEnds,
18368        window: &mut Window,
18369        cx: &mut Context<Self>,
18370    ) {
18371        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18372            s.move_with(|_, sel| {
18373                if sel.start != sel.end {
18374                    sel.reversed = !sel.reversed
18375                }
18376            });
18377        });
18378        self.request_autoscroll(Autoscroll::newest(), cx);
18379        cx.notify();
18380    }
18381
18382    pub fn toggle_focus(
18383        workspace: &mut Workspace,
18384        _: &actions::ToggleFocus,
18385        window: &mut Window,
18386        cx: &mut Context<Workspace>,
18387    ) {
18388        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18389            return;
18390        };
18391        workspace.activate_item(&item, true, true, window, cx);
18392    }
18393
18394    pub fn toggle_fold(
18395        &mut self,
18396        _: &actions::ToggleFold,
18397        window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18401            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18402            let selection = self.selections.newest::<Point>(&display_map);
18403
18404            let range = if selection.is_empty() {
18405                let point = selection.head().to_display_point(&display_map);
18406                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18407                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18408                    .to_point(&display_map);
18409                start..end
18410            } else {
18411                selection.range()
18412            };
18413            if display_map.folds_in_range(range).next().is_some() {
18414                self.unfold_lines(&Default::default(), window, cx)
18415            } else {
18416                self.fold(&Default::default(), window, cx)
18417            }
18418        } else {
18419            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18420            let buffer_ids: HashSet<_> = self
18421                .selections
18422                .disjoint_anchor_ranges()
18423                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18424                .collect();
18425
18426            let should_unfold = buffer_ids
18427                .iter()
18428                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18429
18430            for buffer_id in buffer_ids {
18431                if should_unfold {
18432                    self.unfold_buffer(buffer_id, cx);
18433                } else {
18434                    self.fold_buffer(buffer_id, cx);
18435                }
18436            }
18437        }
18438    }
18439
18440    pub fn toggle_fold_recursive(
18441        &mut self,
18442        _: &actions::ToggleFoldRecursive,
18443        window: &mut Window,
18444        cx: &mut Context<Self>,
18445    ) {
18446        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18447
18448        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18449        let range = if selection.is_empty() {
18450            let point = selection.head().to_display_point(&display_map);
18451            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18452            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18453                .to_point(&display_map);
18454            start..end
18455        } else {
18456            selection.range()
18457        };
18458        if display_map.folds_in_range(range).next().is_some() {
18459            self.unfold_recursive(&Default::default(), window, cx)
18460        } else {
18461            self.fold_recursive(&Default::default(), window, cx)
18462        }
18463    }
18464
18465    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18466        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18467            let mut to_fold = Vec::new();
18468            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18469            let selections = self.selections.all_adjusted(&display_map);
18470
18471            for selection in selections {
18472                let range = selection.range().sorted();
18473                let buffer_start_row = range.start.row;
18474
18475                if range.start.row != range.end.row {
18476                    let mut found = false;
18477                    let mut row = range.start.row;
18478                    while row <= range.end.row {
18479                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18480                        {
18481                            found = true;
18482                            row = crease.range().end.row + 1;
18483                            to_fold.push(crease);
18484                        } else {
18485                            row += 1
18486                        }
18487                    }
18488                    if found {
18489                        continue;
18490                    }
18491                }
18492
18493                for row in (0..=range.start.row).rev() {
18494                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18495                        && crease.range().end.row >= buffer_start_row
18496                    {
18497                        to_fold.push(crease);
18498                        if row <= range.start.row {
18499                            break;
18500                        }
18501                    }
18502                }
18503            }
18504
18505            self.fold_creases(to_fold, true, window, cx);
18506        } else {
18507            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18508            let buffer_ids = self
18509                .selections
18510                .disjoint_anchor_ranges()
18511                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18512                .collect::<HashSet<_>>();
18513            for buffer_id in buffer_ids {
18514                self.fold_buffer(buffer_id, cx);
18515            }
18516        }
18517    }
18518
18519    pub fn toggle_fold_all(
18520        &mut self,
18521        _: &actions::ToggleFoldAll,
18522        window: &mut Window,
18523        cx: &mut Context<Self>,
18524    ) {
18525        if self.buffer.read(cx).is_singleton() {
18526            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18527            let has_folds = display_map
18528                .folds_in_range(0..display_map.buffer_snapshot().len())
18529                .next()
18530                .is_some();
18531
18532            if has_folds {
18533                self.unfold_all(&actions::UnfoldAll, window, cx);
18534            } else {
18535                self.fold_all(&actions::FoldAll, window, cx);
18536            }
18537        } else {
18538            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18539            let should_unfold = buffer_ids
18540                .iter()
18541                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18542
18543            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18544                editor
18545                    .update_in(cx, |editor, _, cx| {
18546                        for buffer_id in buffer_ids {
18547                            if should_unfold {
18548                                editor.unfold_buffer(buffer_id, cx);
18549                            } else {
18550                                editor.fold_buffer(buffer_id, cx);
18551                            }
18552                        }
18553                    })
18554                    .ok();
18555            });
18556        }
18557    }
18558
18559    fn fold_at_level(
18560        &mut self,
18561        fold_at: &FoldAtLevel,
18562        window: &mut Window,
18563        cx: &mut Context<Self>,
18564    ) {
18565        if !self.buffer.read(cx).is_singleton() {
18566            return;
18567        }
18568
18569        let fold_at_level = fold_at.0;
18570        let snapshot = self.buffer.read(cx).snapshot(cx);
18571        let mut to_fold = Vec::new();
18572        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18573
18574        let row_ranges_to_keep: Vec<Range<u32>> = self
18575            .selections
18576            .all::<Point>(&self.display_snapshot(cx))
18577            .into_iter()
18578            .map(|sel| sel.start.row..sel.end.row)
18579            .collect();
18580
18581        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18582            while start_row < end_row {
18583                match self
18584                    .snapshot(window, cx)
18585                    .crease_for_buffer_row(MultiBufferRow(start_row))
18586                {
18587                    Some(crease) => {
18588                        let nested_start_row = crease.range().start.row + 1;
18589                        let nested_end_row = crease.range().end.row;
18590
18591                        if current_level < fold_at_level {
18592                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18593                        } else if current_level == fold_at_level {
18594                            // Fold iff there is no selection completely contained within the fold region
18595                            if !row_ranges_to_keep.iter().any(|selection| {
18596                                selection.end >= nested_start_row
18597                                    && selection.start <= nested_end_row
18598                            }) {
18599                                to_fold.push(crease);
18600                            }
18601                        }
18602
18603                        start_row = nested_end_row + 1;
18604                    }
18605                    None => start_row += 1,
18606                }
18607            }
18608        }
18609
18610        self.fold_creases(to_fold, true, window, cx);
18611    }
18612
18613    pub fn fold_at_level_1(
18614        &mut self,
18615        _: &actions::FoldAtLevel1,
18616        window: &mut Window,
18617        cx: &mut Context<Self>,
18618    ) {
18619        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18620    }
18621
18622    pub fn fold_at_level_2(
18623        &mut self,
18624        _: &actions::FoldAtLevel2,
18625        window: &mut Window,
18626        cx: &mut Context<Self>,
18627    ) {
18628        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18629    }
18630
18631    pub fn fold_at_level_3(
18632        &mut self,
18633        _: &actions::FoldAtLevel3,
18634        window: &mut Window,
18635        cx: &mut Context<Self>,
18636    ) {
18637        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18638    }
18639
18640    pub fn fold_at_level_4(
18641        &mut self,
18642        _: &actions::FoldAtLevel4,
18643        window: &mut Window,
18644        cx: &mut Context<Self>,
18645    ) {
18646        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18647    }
18648
18649    pub fn fold_at_level_5(
18650        &mut self,
18651        _: &actions::FoldAtLevel5,
18652        window: &mut Window,
18653        cx: &mut Context<Self>,
18654    ) {
18655        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18656    }
18657
18658    pub fn fold_at_level_6(
18659        &mut self,
18660        _: &actions::FoldAtLevel6,
18661        window: &mut Window,
18662        cx: &mut Context<Self>,
18663    ) {
18664        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18665    }
18666
18667    pub fn fold_at_level_7(
18668        &mut self,
18669        _: &actions::FoldAtLevel7,
18670        window: &mut Window,
18671        cx: &mut Context<Self>,
18672    ) {
18673        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18674    }
18675
18676    pub fn fold_at_level_8(
18677        &mut self,
18678        _: &actions::FoldAtLevel8,
18679        window: &mut Window,
18680        cx: &mut Context<Self>,
18681    ) {
18682        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18683    }
18684
18685    pub fn fold_at_level_9(
18686        &mut self,
18687        _: &actions::FoldAtLevel9,
18688        window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) {
18691        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18692    }
18693
18694    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18695        if self.buffer.read(cx).is_singleton() {
18696            let mut fold_ranges = Vec::new();
18697            let snapshot = self.buffer.read(cx).snapshot(cx);
18698
18699            for row in 0..snapshot.max_row().0 {
18700                if let Some(foldable_range) = self
18701                    .snapshot(window, cx)
18702                    .crease_for_buffer_row(MultiBufferRow(row))
18703                {
18704                    fold_ranges.push(foldable_range);
18705                }
18706            }
18707
18708            self.fold_creases(fold_ranges, true, window, cx);
18709        } else {
18710            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18711                editor
18712                    .update_in(cx, |editor, _, cx| {
18713                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18714                            editor.fold_buffer(buffer_id, cx);
18715                        }
18716                    })
18717                    .ok();
18718            });
18719        }
18720    }
18721
18722    pub fn fold_function_bodies(
18723        &mut self,
18724        _: &actions::FoldFunctionBodies,
18725        window: &mut Window,
18726        cx: &mut Context<Self>,
18727    ) {
18728        let snapshot = self.buffer.read(cx).snapshot(cx);
18729
18730        let ranges = snapshot
18731            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18732            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18733            .collect::<Vec<_>>();
18734
18735        let creases = ranges
18736            .into_iter()
18737            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18738            .collect();
18739
18740        self.fold_creases(creases, true, window, cx);
18741    }
18742
18743    pub fn fold_recursive(
18744        &mut self,
18745        _: &actions::FoldRecursive,
18746        window: &mut Window,
18747        cx: &mut Context<Self>,
18748    ) {
18749        let mut to_fold = Vec::new();
18750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18751        let selections = self.selections.all_adjusted(&display_map);
18752
18753        for selection in selections {
18754            let range = selection.range().sorted();
18755            let buffer_start_row = range.start.row;
18756
18757            if range.start.row != range.end.row {
18758                let mut found = false;
18759                for row in range.start.row..=range.end.row {
18760                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18761                        found = true;
18762                        to_fold.push(crease);
18763                    }
18764                }
18765                if found {
18766                    continue;
18767                }
18768            }
18769
18770            for row in (0..=range.start.row).rev() {
18771                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18772                    if crease.range().end.row >= buffer_start_row {
18773                        to_fold.push(crease);
18774                    } else {
18775                        break;
18776                    }
18777                }
18778            }
18779        }
18780
18781        self.fold_creases(to_fold, true, window, cx);
18782    }
18783
18784    pub fn fold_at(
18785        &mut self,
18786        buffer_row: MultiBufferRow,
18787        window: &mut Window,
18788        cx: &mut Context<Self>,
18789    ) {
18790        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18791
18792        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18793            let autoscroll = self
18794                .selections
18795                .all::<Point>(&display_map)
18796                .iter()
18797                .any(|selection| crease.range().overlaps(&selection.range()));
18798
18799            self.fold_creases(vec![crease], autoscroll, window, cx);
18800        }
18801    }
18802
18803    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18804        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18805            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18806            let buffer = display_map.buffer_snapshot();
18807            let selections = self.selections.all::<Point>(&display_map);
18808            let ranges = selections
18809                .iter()
18810                .map(|s| {
18811                    let range = s.display_range(&display_map).sorted();
18812                    let mut start = range.start.to_point(&display_map);
18813                    let mut end = range.end.to_point(&display_map);
18814                    start.column = 0;
18815                    end.column = buffer.line_len(MultiBufferRow(end.row));
18816                    start..end
18817                })
18818                .collect::<Vec<_>>();
18819
18820            self.unfold_ranges(&ranges, true, true, cx);
18821        } else {
18822            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18823            let buffer_ids = self
18824                .selections
18825                .disjoint_anchor_ranges()
18826                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18827                .collect::<HashSet<_>>();
18828            for buffer_id in buffer_ids {
18829                self.unfold_buffer(buffer_id, cx);
18830            }
18831        }
18832    }
18833
18834    pub fn unfold_recursive(
18835        &mut self,
18836        _: &UnfoldRecursive,
18837        _window: &mut Window,
18838        cx: &mut Context<Self>,
18839    ) {
18840        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18841        let selections = self.selections.all::<Point>(&display_map);
18842        let ranges = selections
18843            .iter()
18844            .map(|s| {
18845                let mut range = s.display_range(&display_map).sorted();
18846                *range.start.column_mut() = 0;
18847                *range.end.column_mut() = display_map.line_len(range.end.row());
18848                let start = range.start.to_point(&display_map);
18849                let end = range.end.to_point(&display_map);
18850                start..end
18851            })
18852            .collect::<Vec<_>>();
18853
18854        self.unfold_ranges(&ranges, true, true, cx);
18855    }
18856
18857    pub fn unfold_at(
18858        &mut self,
18859        buffer_row: MultiBufferRow,
18860        _window: &mut Window,
18861        cx: &mut Context<Self>,
18862    ) {
18863        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18864
18865        let intersection_range = Point::new(buffer_row.0, 0)
18866            ..Point::new(
18867                buffer_row.0,
18868                display_map.buffer_snapshot().line_len(buffer_row),
18869            );
18870
18871        let autoscroll = self
18872            .selections
18873            .all::<Point>(&display_map)
18874            .iter()
18875            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18876
18877        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18878    }
18879
18880    pub fn unfold_all(
18881        &mut self,
18882        _: &actions::UnfoldAll,
18883        _window: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        if self.buffer.read(cx).is_singleton() {
18887            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18888            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18889        } else {
18890            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18891                editor
18892                    .update(cx, |editor, cx| {
18893                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18894                            editor.unfold_buffer(buffer_id, cx);
18895                        }
18896                    })
18897                    .ok();
18898            });
18899        }
18900    }
18901
18902    pub fn fold_selected_ranges(
18903        &mut self,
18904        _: &FoldSelectedRanges,
18905        window: &mut Window,
18906        cx: &mut Context<Self>,
18907    ) {
18908        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18909        let selections = self.selections.all_adjusted(&display_map);
18910        let ranges = selections
18911            .into_iter()
18912            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18913            .collect::<Vec<_>>();
18914        self.fold_creases(ranges, true, window, cx);
18915    }
18916
18917    pub fn fold_ranges<T: ToOffset + Clone>(
18918        &mut self,
18919        ranges: Vec<Range<T>>,
18920        auto_scroll: bool,
18921        window: &mut Window,
18922        cx: &mut Context<Self>,
18923    ) {
18924        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18925        let ranges = ranges
18926            .into_iter()
18927            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18928            .collect::<Vec<_>>();
18929        self.fold_creases(ranges, auto_scroll, window, cx);
18930    }
18931
18932    pub fn fold_creases<T: ToOffset + Clone>(
18933        &mut self,
18934        creases: Vec<Crease<T>>,
18935        auto_scroll: bool,
18936        _window: &mut Window,
18937        cx: &mut Context<Self>,
18938    ) {
18939        if creases.is_empty() {
18940            return;
18941        }
18942
18943        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18944
18945        if auto_scroll {
18946            self.request_autoscroll(Autoscroll::fit(), cx);
18947        }
18948
18949        cx.notify();
18950
18951        self.scrollbar_marker_state.dirty = true;
18952        self.folds_did_change(cx);
18953    }
18954
18955    /// Removes any folds whose ranges intersect any of the given ranges.
18956    pub fn unfold_ranges<T: ToOffset + Clone>(
18957        &mut self,
18958        ranges: &[Range<T>],
18959        inclusive: bool,
18960        auto_scroll: bool,
18961        cx: &mut Context<Self>,
18962    ) {
18963        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18964            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18965        });
18966        self.folds_did_change(cx);
18967    }
18968
18969    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18970        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18971            return;
18972        }
18973
18974        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18975        self.display_map.update(cx, |display_map, cx| {
18976            display_map.fold_buffers([buffer_id], cx)
18977        });
18978
18979        let snapshot = self.display_snapshot(cx);
18980        self.selections.change_with(&snapshot, |selections| {
18981            selections.remove_selections_from_buffer(buffer_id);
18982        });
18983
18984        cx.emit(EditorEvent::BufferFoldToggled {
18985            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18986            folded: true,
18987        });
18988        cx.notify();
18989    }
18990
18991    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18992        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18993            return;
18994        }
18995        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18996        self.display_map.update(cx, |display_map, cx| {
18997            display_map.unfold_buffers([buffer_id], cx);
18998        });
18999        cx.emit(EditorEvent::BufferFoldToggled {
19000            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19001            folded: false,
19002        });
19003        cx.notify();
19004    }
19005
19006    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19007        self.display_map.read(cx).is_buffer_folded(buffer)
19008    }
19009
19010    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19011        self.display_map.read(cx).folded_buffers()
19012    }
19013
19014    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19015        self.display_map.update(cx, |display_map, cx| {
19016            display_map.disable_header_for_buffer(buffer_id, cx);
19017        });
19018        cx.notify();
19019    }
19020
19021    /// Removes any folds with the given ranges.
19022    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19023        &mut self,
19024        ranges: &[Range<T>],
19025        type_id: TypeId,
19026        auto_scroll: bool,
19027        cx: &mut Context<Self>,
19028    ) {
19029        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19030            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19031        });
19032        self.folds_did_change(cx);
19033    }
19034
19035    fn remove_folds_with<T: ToOffset + Clone>(
19036        &mut self,
19037        ranges: &[Range<T>],
19038        auto_scroll: bool,
19039        cx: &mut Context<Self>,
19040        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19041    ) {
19042        if ranges.is_empty() {
19043            return;
19044        }
19045
19046        let mut buffers_affected = HashSet::default();
19047        let multi_buffer = self.buffer().read(cx);
19048        for range in ranges {
19049            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19050                buffers_affected.insert(buffer.read(cx).remote_id());
19051            };
19052        }
19053
19054        self.display_map.update(cx, update);
19055
19056        if auto_scroll {
19057            self.request_autoscroll(Autoscroll::fit(), cx);
19058        }
19059
19060        cx.notify();
19061        self.scrollbar_marker_state.dirty = true;
19062        self.active_indent_guides_state.dirty = true;
19063    }
19064
19065    pub fn update_renderer_widths(
19066        &mut self,
19067        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19068        cx: &mut Context<Self>,
19069    ) -> bool {
19070        self.display_map
19071            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19072    }
19073
19074    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19075        self.display_map.read(cx).fold_placeholder.clone()
19076    }
19077
19078    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19079        self.buffer.update(cx, |buffer, cx| {
19080            buffer.set_all_diff_hunks_expanded(cx);
19081        });
19082    }
19083
19084    pub fn expand_all_diff_hunks(
19085        &mut self,
19086        _: &ExpandAllDiffHunks,
19087        _window: &mut Window,
19088        cx: &mut Context<Self>,
19089    ) {
19090        self.buffer.update(cx, |buffer, cx| {
19091            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19092        });
19093    }
19094
19095    pub fn collapse_all_diff_hunks(
19096        &mut self,
19097        _: &CollapseAllDiffHunks,
19098        _window: &mut Window,
19099        cx: &mut Context<Self>,
19100    ) {
19101        self.buffer.update(cx, |buffer, cx| {
19102            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19103        });
19104    }
19105
19106    pub fn toggle_selected_diff_hunks(
19107        &mut self,
19108        _: &ToggleSelectedDiffHunks,
19109        _window: &mut Window,
19110        cx: &mut Context<Self>,
19111    ) {
19112        let ranges: Vec<_> = self
19113            .selections
19114            .disjoint_anchors()
19115            .iter()
19116            .map(|s| s.range())
19117            .collect();
19118        self.toggle_diff_hunks_in_ranges(ranges, cx);
19119    }
19120
19121    pub fn diff_hunks_in_ranges<'a>(
19122        &'a self,
19123        ranges: &'a [Range<Anchor>],
19124        buffer: &'a MultiBufferSnapshot,
19125    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19126        ranges.iter().flat_map(move |range| {
19127            let end_excerpt_id = range.end.excerpt_id;
19128            let range = range.to_point(buffer);
19129            let mut peek_end = range.end;
19130            if range.end.row < buffer.max_row().0 {
19131                peek_end = Point::new(range.end.row + 1, 0);
19132            }
19133            buffer
19134                .diff_hunks_in_range(range.start..peek_end)
19135                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19136        })
19137    }
19138
19139    pub fn has_stageable_diff_hunks_in_ranges(
19140        &self,
19141        ranges: &[Range<Anchor>],
19142        snapshot: &MultiBufferSnapshot,
19143    ) -> bool {
19144        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19145        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19146    }
19147
19148    pub fn toggle_staged_selected_diff_hunks(
19149        &mut self,
19150        _: &::git::ToggleStaged,
19151        _: &mut Window,
19152        cx: &mut Context<Self>,
19153    ) {
19154        let snapshot = self.buffer.read(cx).snapshot(cx);
19155        let ranges: Vec<_> = self
19156            .selections
19157            .disjoint_anchors()
19158            .iter()
19159            .map(|s| s.range())
19160            .collect();
19161        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19162        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19163    }
19164
19165    pub fn set_render_diff_hunk_controls(
19166        &mut self,
19167        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19168        cx: &mut Context<Self>,
19169    ) {
19170        self.render_diff_hunk_controls = render_diff_hunk_controls;
19171        cx.notify();
19172    }
19173
19174    pub fn stage_and_next(
19175        &mut self,
19176        _: &::git::StageAndNext,
19177        window: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        self.do_stage_or_unstage_and_next(true, window, cx);
19181    }
19182
19183    pub fn unstage_and_next(
19184        &mut self,
19185        _: &::git::UnstageAndNext,
19186        window: &mut Window,
19187        cx: &mut Context<Self>,
19188    ) {
19189        self.do_stage_or_unstage_and_next(false, window, cx);
19190    }
19191
19192    pub fn stage_or_unstage_diff_hunks(
19193        &mut self,
19194        stage: bool,
19195        ranges: Vec<Range<Anchor>>,
19196        cx: &mut Context<Self>,
19197    ) {
19198        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19199        cx.spawn(async move |this, cx| {
19200            task.await?;
19201            this.update(cx, |this, cx| {
19202                let snapshot = this.buffer.read(cx).snapshot(cx);
19203                let chunk_by = this
19204                    .diff_hunks_in_ranges(&ranges, &snapshot)
19205                    .chunk_by(|hunk| hunk.buffer_id);
19206                for (buffer_id, hunks) in &chunk_by {
19207                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19208                }
19209            })
19210        })
19211        .detach_and_log_err(cx);
19212    }
19213
19214    fn save_buffers_for_ranges_if_needed(
19215        &mut self,
19216        ranges: &[Range<Anchor>],
19217        cx: &mut Context<Editor>,
19218    ) -> Task<Result<()>> {
19219        let multibuffer = self.buffer.read(cx);
19220        let snapshot = multibuffer.read(cx);
19221        let buffer_ids: HashSet<_> = ranges
19222            .iter()
19223            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19224            .collect();
19225        drop(snapshot);
19226
19227        let mut buffers = HashSet::default();
19228        for buffer_id in buffer_ids {
19229            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19230                let buffer = buffer_entity.read(cx);
19231                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19232                {
19233                    buffers.insert(buffer_entity);
19234                }
19235            }
19236        }
19237
19238        if let Some(project) = &self.project {
19239            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19240        } else {
19241            Task::ready(Ok(()))
19242        }
19243    }
19244
19245    fn do_stage_or_unstage_and_next(
19246        &mut self,
19247        stage: bool,
19248        window: &mut Window,
19249        cx: &mut Context<Self>,
19250    ) {
19251        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19252
19253        if ranges.iter().any(|range| range.start != range.end) {
19254            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19255            return;
19256        }
19257
19258        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19259        let snapshot = self.snapshot(window, cx);
19260        let position = self
19261            .selections
19262            .newest::<Point>(&snapshot.display_snapshot)
19263            .head();
19264        let mut row = snapshot
19265            .buffer_snapshot()
19266            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19267            .find(|hunk| hunk.row_range.start.0 > position.row)
19268            .map(|hunk| hunk.row_range.start);
19269
19270        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19271        // Outside of the project diff editor, wrap around to the beginning.
19272        if !all_diff_hunks_expanded {
19273            row = row.or_else(|| {
19274                snapshot
19275                    .buffer_snapshot()
19276                    .diff_hunks_in_range(Point::zero()..position)
19277                    .find(|hunk| hunk.row_range.end.0 < position.row)
19278                    .map(|hunk| hunk.row_range.start)
19279            });
19280        }
19281
19282        if let Some(row) = row {
19283            let destination = Point::new(row.0, 0);
19284            let autoscroll = Autoscroll::center();
19285
19286            self.unfold_ranges(&[destination..destination], false, false, cx);
19287            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19288                s.select_ranges([destination..destination]);
19289            });
19290        }
19291    }
19292
19293    fn do_stage_or_unstage(
19294        &self,
19295        stage: bool,
19296        buffer_id: BufferId,
19297        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19298        cx: &mut App,
19299    ) -> Option<()> {
19300        let project = self.project()?;
19301        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19302        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19303        let buffer_snapshot = buffer.read(cx).snapshot();
19304        let file_exists = buffer_snapshot
19305            .file()
19306            .is_some_and(|file| file.disk_state().exists());
19307        diff.update(cx, |diff, cx| {
19308            diff.stage_or_unstage_hunks(
19309                stage,
19310                &hunks
19311                    .map(|hunk| buffer_diff::DiffHunk {
19312                        buffer_range: hunk.buffer_range,
19313                        diff_base_byte_range: hunk.diff_base_byte_range,
19314                        secondary_status: hunk.secondary_status,
19315                        range: Point::zero()..Point::zero(), // unused
19316                    })
19317                    .collect::<Vec<_>>(),
19318                &buffer_snapshot,
19319                file_exists,
19320                cx,
19321            )
19322        });
19323        None
19324    }
19325
19326    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19327        let ranges: Vec<_> = self
19328            .selections
19329            .disjoint_anchors()
19330            .iter()
19331            .map(|s| s.range())
19332            .collect();
19333        self.buffer
19334            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19335    }
19336
19337    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19338        self.buffer.update(cx, |buffer, cx| {
19339            let ranges = vec![Anchor::min()..Anchor::max()];
19340            if !buffer.all_diff_hunks_expanded()
19341                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19342            {
19343                buffer.collapse_diff_hunks(ranges, cx);
19344                true
19345            } else {
19346                false
19347            }
19348        })
19349    }
19350
19351    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19352        if self.buffer.read(cx).all_diff_hunks_expanded() {
19353            return true;
19354        }
19355        let ranges = vec![Anchor::min()..Anchor::max()];
19356        self.buffer
19357            .read(cx)
19358            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19359    }
19360
19361    fn toggle_diff_hunks_in_ranges(
19362        &mut self,
19363        ranges: Vec<Range<Anchor>>,
19364        cx: &mut Context<Editor>,
19365    ) {
19366        self.buffer.update(cx, |buffer, cx| {
19367            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19368            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19369        })
19370    }
19371
19372    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19373        self.buffer.update(cx, |buffer, cx| {
19374            let snapshot = buffer.snapshot(cx);
19375            let excerpt_id = range.end.excerpt_id;
19376            let point_range = range.to_point(&snapshot);
19377            let expand = !buffer.single_hunk_is_expanded(range, cx);
19378            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19379        })
19380    }
19381
19382    pub(crate) fn apply_all_diff_hunks(
19383        &mut self,
19384        _: &ApplyAllDiffHunks,
19385        window: &mut Window,
19386        cx: &mut Context<Self>,
19387    ) {
19388        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19389
19390        let buffers = self.buffer.read(cx).all_buffers();
19391        for branch_buffer in buffers {
19392            branch_buffer.update(cx, |branch_buffer, cx| {
19393                branch_buffer.merge_into_base(Vec::new(), cx);
19394            });
19395        }
19396
19397        if let Some(project) = self.project.clone() {
19398            self.save(
19399                SaveOptions {
19400                    format: true,
19401                    autosave: false,
19402                },
19403                project,
19404                window,
19405                cx,
19406            )
19407            .detach_and_log_err(cx);
19408        }
19409    }
19410
19411    pub(crate) fn apply_selected_diff_hunks(
19412        &mut self,
19413        _: &ApplyDiffHunk,
19414        window: &mut Window,
19415        cx: &mut Context<Self>,
19416    ) {
19417        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19418        let snapshot = self.snapshot(window, cx);
19419        let hunks = snapshot.hunks_for_ranges(
19420            self.selections
19421                .all(&snapshot.display_snapshot)
19422                .into_iter()
19423                .map(|selection| selection.range()),
19424        );
19425        let mut ranges_by_buffer = HashMap::default();
19426        self.transact(window, cx, |editor, _window, cx| {
19427            for hunk in hunks {
19428                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19429                    ranges_by_buffer
19430                        .entry(buffer.clone())
19431                        .or_insert_with(Vec::new)
19432                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19433                }
19434            }
19435
19436            for (buffer, ranges) in ranges_by_buffer {
19437                buffer.update(cx, |buffer, cx| {
19438                    buffer.merge_into_base(ranges, cx);
19439                });
19440            }
19441        });
19442
19443        if let Some(project) = self.project.clone() {
19444            self.save(
19445                SaveOptions {
19446                    format: true,
19447                    autosave: false,
19448                },
19449                project,
19450                window,
19451                cx,
19452            )
19453            .detach_and_log_err(cx);
19454        }
19455    }
19456
19457    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19458        if hovered != self.gutter_hovered {
19459            self.gutter_hovered = hovered;
19460            cx.notify();
19461        }
19462    }
19463
19464    pub fn insert_blocks(
19465        &mut self,
19466        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19467        autoscroll: Option<Autoscroll>,
19468        cx: &mut Context<Self>,
19469    ) -> Vec<CustomBlockId> {
19470        let blocks = self
19471            .display_map
19472            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19473        if let Some(autoscroll) = autoscroll {
19474            self.request_autoscroll(autoscroll, cx);
19475        }
19476        cx.notify();
19477        blocks
19478    }
19479
19480    pub fn resize_blocks(
19481        &mut self,
19482        heights: HashMap<CustomBlockId, u32>,
19483        autoscroll: Option<Autoscroll>,
19484        cx: &mut Context<Self>,
19485    ) {
19486        self.display_map
19487            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19488        if let Some(autoscroll) = autoscroll {
19489            self.request_autoscroll(autoscroll, cx);
19490        }
19491        cx.notify();
19492    }
19493
19494    pub fn replace_blocks(
19495        &mut self,
19496        renderers: HashMap<CustomBlockId, RenderBlock>,
19497        autoscroll: Option<Autoscroll>,
19498        cx: &mut Context<Self>,
19499    ) {
19500        self.display_map
19501            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19502        if let Some(autoscroll) = autoscroll {
19503            self.request_autoscroll(autoscroll, cx);
19504        }
19505        cx.notify();
19506    }
19507
19508    pub fn remove_blocks(
19509        &mut self,
19510        block_ids: HashSet<CustomBlockId>,
19511        autoscroll: Option<Autoscroll>,
19512        cx: &mut Context<Self>,
19513    ) {
19514        self.display_map.update(cx, |display_map, cx| {
19515            display_map.remove_blocks(block_ids, cx)
19516        });
19517        if let Some(autoscroll) = autoscroll {
19518            self.request_autoscroll(autoscroll, cx);
19519        }
19520        cx.notify();
19521    }
19522
19523    pub fn row_for_block(
19524        &self,
19525        block_id: CustomBlockId,
19526        cx: &mut Context<Self>,
19527    ) -> Option<DisplayRow> {
19528        self.display_map
19529            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19530    }
19531
19532    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19533        self.focused_block = Some(focused_block);
19534    }
19535
19536    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19537        self.focused_block.take()
19538    }
19539
19540    pub fn insert_creases(
19541        &mut self,
19542        creases: impl IntoIterator<Item = Crease<Anchor>>,
19543        cx: &mut Context<Self>,
19544    ) -> Vec<CreaseId> {
19545        self.display_map
19546            .update(cx, |map, cx| map.insert_creases(creases, cx))
19547    }
19548
19549    pub fn remove_creases(
19550        &mut self,
19551        ids: impl IntoIterator<Item = CreaseId>,
19552        cx: &mut Context<Self>,
19553    ) -> Vec<(CreaseId, Range<Anchor>)> {
19554        self.display_map
19555            .update(cx, |map, cx| map.remove_creases(ids, cx))
19556    }
19557
19558    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19559        self.display_map
19560            .update(cx, |map, cx| map.snapshot(cx))
19561            .longest_row()
19562    }
19563
19564    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19565        self.display_map
19566            .update(cx, |map, cx| map.snapshot(cx))
19567            .max_point()
19568    }
19569
19570    pub fn text(&self, cx: &App) -> String {
19571        self.buffer.read(cx).read(cx).text()
19572    }
19573
19574    pub fn is_empty(&self, cx: &App) -> bool {
19575        self.buffer.read(cx).read(cx).is_empty()
19576    }
19577
19578    pub fn text_option(&self, cx: &App) -> Option<String> {
19579        let text = self.text(cx);
19580        let text = text.trim();
19581
19582        if text.is_empty() {
19583            return None;
19584        }
19585
19586        Some(text.to_string())
19587    }
19588
19589    pub fn set_text(
19590        &mut self,
19591        text: impl Into<Arc<str>>,
19592        window: &mut Window,
19593        cx: &mut Context<Self>,
19594    ) {
19595        self.transact(window, cx, |this, _, cx| {
19596            this.buffer
19597                .read(cx)
19598                .as_singleton()
19599                .expect("you can only call set_text on editors for singleton buffers")
19600                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19601        });
19602    }
19603
19604    pub fn display_text(&self, cx: &mut App) -> String {
19605        self.display_map
19606            .update(cx, |map, cx| map.snapshot(cx))
19607            .text()
19608    }
19609
19610    fn create_minimap(
19611        &self,
19612        minimap_settings: MinimapSettings,
19613        window: &mut Window,
19614        cx: &mut Context<Self>,
19615    ) -> Option<Entity<Self>> {
19616        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19617            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19618    }
19619
19620    fn initialize_new_minimap(
19621        &self,
19622        minimap_settings: MinimapSettings,
19623        window: &mut Window,
19624        cx: &mut Context<Self>,
19625    ) -> Entity<Self> {
19626        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19627
19628        let mut minimap = Editor::new_internal(
19629            EditorMode::Minimap {
19630                parent: cx.weak_entity(),
19631            },
19632            self.buffer.clone(),
19633            None,
19634            Some(self.display_map.clone()),
19635            window,
19636            cx,
19637        );
19638        minimap.scroll_manager.clone_state(&self.scroll_manager);
19639        minimap.set_text_style_refinement(TextStyleRefinement {
19640            font_size: Some(MINIMAP_FONT_SIZE),
19641            font_weight: Some(MINIMAP_FONT_WEIGHT),
19642            ..Default::default()
19643        });
19644        minimap.update_minimap_configuration(minimap_settings, cx);
19645        cx.new(|_| minimap)
19646    }
19647
19648    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19649        let current_line_highlight = minimap_settings
19650            .current_line_highlight
19651            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19652        self.set_current_line_highlight(Some(current_line_highlight));
19653    }
19654
19655    pub fn minimap(&self) -> Option<&Entity<Self>> {
19656        self.minimap
19657            .as_ref()
19658            .filter(|_| self.minimap_visibility.visible())
19659    }
19660
19661    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19662        let mut wrap_guides = smallvec![];
19663
19664        if self.show_wrap_guides == Some(false) {
19665            return wrap_guides;
19666        }
19667
19668        let settings = self.buffer.read(cx).language_settings(cx);
19669        if settings.show_wrap_guides {
19670            match self.soft_wrap_mode(cx) {
19671                SoftWrap::Column(soft_wrap) => {
19672                    wrap_guides.push((soft_wrap as usize, true));
19673                }
19674                SoftWrap::Bounded(soft_wrap) => {
19675                    wrap_guides.push((soft_wrap as usize, true));
19676                }
19677                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19678            }
19679            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19680        }
19681
19682        wrap_guides
19683    }
19684
19685    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19686        let settings = self.buffer.read(cx).language_settings(cx);
19687        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19688        match mode {
19689            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19690                SoftWrap::None
19691            }
19692            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19693            language_settings::SoftWrap::PreferredLineLength => {
19694                SoftWrap::Column(settings.preferred_line_length)
19695            }
19696            language_settings::SoftWrap::Bounded => {
19697                SoftWrap::Bounded(settings.preferred_line_length)
19698            }
19699        }
19700    }
19701
19702    pub fn set_soft_wrap_mode(
19703        &mut self,
19704        mode: language_settings::SoftWrap,
19705
19706        cx: &mut Context<Self>,
19707    ) {
19708        self.soft_wrap_mode_override = Some(mode);
19709        cx.notify();
19710    }
19711
19712    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19713        self.hard_wrap = hard_wrap;
19714        cx.notify();
19715    }
19716
19717    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19718        self.text_style_refinement = Some(style);
19719    }
19720
19721    /// called by the Element so we know what style we were most recently rendered with.
19722    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19723        // We intentionally do not inform the display map about the minimap style
19724        // so that wrapping is not recalculated and stays consistent for the editor
19725        // and its linked minimap.
19726        if !self.mode.is_minimap() {
19727            let font = style.text.font();
19728            let font_size = style.text.font_size.to_pixels(window.rem_size());
19729            let display_map = self
19730                .placeholder_display_map
19731                .as_ref()
19732                .filter(|_| self.is_empty(cx))
19733                .unwrap_or(&self.display_map);
19734
19735            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19736        }
19737        self.style = Some(style);
19738    }
19739
19740    pub fn style(&self) -> Option<&EditorStyle> {
19741        self.style.as_ref()
19742    }
19743
19744    // Called by the element. This method is not designed to be called outside of the editor
19745    // element's layout code because it does not notify when rewrapping is computed synchronously.
19746    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19747        if self.is_empty(cx) {
19748            self.placeholder_display_map
19749                .as_ref()
19750                .map_or(false, |display_map| {
19751                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19752                })
19753        } else {
19754            self.display_map
19755                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19756        }
19757    }
19758
19759    pub fn set_soft_wrap(&mut self) {
19760        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19761    }
19762
19763    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19764        if self.soft_wrap_mode_override.is_some() {
19765            self.soft_wrap_mode_override.take();
19766        } else {
19767            let soft_wrap = match self.soft_wrap_mode(cx) {
19768                SoftWrap::GitDiff => return,
19769                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19770                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19771                    language_settings::SoftWrap::None
19772                }
19773            };
19774            self.soft_wrap_mode_override = Some(soft_wrap);
19775        }
19776        cx.notify();
19777    }
19778
19779    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19780        let Some(workspace) = self.workspace() else {
19781            return;
19782        };
19783        let fs = workspace.read(cx).app_state().fs.clone();
19784        let current_show = TabBarSettings::get_global(cx).show;
19785        update_settings_file(fs, cx, move |setting, _| {
19786            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19787        });
19788    }
19789
19790    pub fn toggle_indent_guides(
19791        &mut self,
19792        _: &ToggleIndentGuides,
19793        _: &mut Window,
19794        cx: &mut Context<Self>,
19795    ) {
19796        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19797            self.buffer
19798                .read(cx)
19799                .language_settings(cx)
19800                .indent_guides
19801                .enabled
19802        });
19803        self.show_indent_guides = Some(!currently_enabled);
19804        cx.notify();
19805    }
19806
19807    fn should_show_indent_guides(&self) -> Option<bool> {
19808        self.show_indent_guides
19809    }
19810
19811    pub fn toggle_line_numbers(
19812        &mut self,
19813        _: &ToggleLineNumbers,
19814        _: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        let mut editor_settings = EditorSettings::get_global(cx).clone();
19818        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19819        EditorSettings::override_global(editor_settings, cx);
19820    }
19821
19822    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19823        if let Some(show_line_numbers) = self.show_line_numbers {
19824            return show_line_numbers;
19825        }
19826        EditorSettings::get_global(cx).gutter.line_numbers
19827    }
19828
19829    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19830        match (
19831            self.use_relative_line_numbers,
19832            EditorSettings::get_global(cx).relative_line_numbers,
19833        ) {
19834            (None, setting) => setting,
19835            (Some(false), _) => RelativeLineNumbers::Disabled,
19836            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19837            (Some(true), _) => RelativeLineNumbers::Enabled,
19838        }
19839    }
19840
19841    pub fn toggle_relative_line_numbers(
19842        &mut self,
19843        _: &ToggleRelativeLineNumbers,
19844        _: &mut Window,
19845        cx: &mut Context<Self>,
19846    ) {
19847        let is_relative = self.relative_line_numbers(cx);
19848        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19849    }
19850
19851    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19852        self.use_relative_line_numbers = is_relative;
19853        cx.notify();
19854    }
19855
19856    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19857        self.show_gutter = show_gutter;
19858        cx.notify();
19859    }
19860
19861    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19862        self.show_scrollbars = ScrollbarAxes {
19863            horizontal: show,
19864            vertical: show,
19865        };
19866        cx.notify();
19867    }
19868
19869    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19870        self.show_scrollbars.vertical = show;
19871        cx.notify();
19872    }
19873
19874    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19875        self.show_scrollbars.horizontal = show;
19876        cx.notify();
19877    }
19878
19879    pub fn set_minimap_visibility(
19880        &mut self,
19881        minimap_visibility: MinimapVisibility,
19882        window: &mut Window,
19883        cx: &mut Context<Self>,
19884    ) {
19885        if self.minimap_visibility != minimap_visibility {
19886            if minimap_visibility.visible() && self.minimap.is_none() {
19887                let minimap_settings = EditorSettings::get_global(cx).minimap;
19888                self.minimap =
19889                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19890            }
19891            self.minimap_visibility = minimap_visibility;
19892            cx.notify();
19893        }
19894    }
19895
19896    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19897        self.set_show_scrollbars(false, cx);
19898        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19899    }
19900
19901    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19902        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19903    }
19904
19905    /// Normally the text in full mode and auto height editors is padded on the
19906    /// left side by roughly half a character width for improved hit testing.
19907    ///
19908    /// Use this method to disable this for cases where this is not wanted (e.g.
19909    /// if you want to align the editor text with some other text above or below)
19910    /// or if you want to add this padding to single-line editors.
19911    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19912        self.offset_content = offset_content;
19913        cx.notify();
19914    }
19915
19916    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19917        self.show_line_numbers = Some(show_line_numbers);
19918        cx.notify();
19919    }
19920
19921    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19922        self.disable_expand_excerpt_buttons = true;
19923        cx.notify();
19924    }
19925
19926    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19927        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19928        cx.notify();
19929    }
19930
19931    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19932        self.show_code_actions = Some(show_code_actions);
19933        cx.notify();
19934    }
19935
19936    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19937        self.show_runnables = Some(show_runnables);
19938        cx.notify();
19939    }
19940
19941    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19942        self.show_breakpoints = Some(show_breakpoints);
19943        cx.notify();
19944    }
19945
19946    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19947        if self.display_map.read(cx).masked != masked {
19948            self.display_map.update(cx, |map, _| map.masked = masked);
19949        }
19950        cx.notify()
19951    }
19952
19953    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19954        self.show_wrap_guides = Some(show_wrap_guides);
19955        cx.notify();
19956    }
19957
19958    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19959        self.show_indent_guides = Some(show_indent_guides);
19960        cx.notify();
19961    }
19962
19963    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19964        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19965            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19966                && let Some(dir) = file.abs_path(cx).parent()
19967            {
19968                return Some(dir.to_owned());
19969            }
19970        }
19971
19972        None
19973    }
19974
19975    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19976        self.active_excerpt(cx)?
19977            .1
19978            .read(cx)
19979            .file()
19980            .and_then(|f| f.as_local())
19981    }
19982
19983    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19984        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19985            let buffer = buffer.read(cx);
19986            if let Some(project_path) = buffer.project_path(cx) {
19987                let project = self.project()?.read(cx);
19988                project.absolute_path(&project_path, cx)
19989            } else {
19990                buffer
19991                    .file()
19992                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19993            }
19994        })
19995    }
19996
19997    pub fn reveal_in_finder(
19998        &mut self,
19999        _: &RevealInFileManager,
20000        _window: &mut Window,
20001        cx: &mut Context<Self>,
20002    ) {
20003        if let Some(target) = self.target_file(cx) {
20004            cx.reveal_path(&target.abs_path(cx));
20005        }
20006    }
20007
20008    pub fn copy_path(
20009        &mut self,
20010        _: &zed_actions::workspace::CopyPath,
20011        _window: &mut Window,
20012        cx: &mut Context<Self>,
20013    ) {
20014        if let Some(path) = self.target_file_abs_path(cx)
20015            && let Some(path) = path.to_str()
20016        {
20017            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20018        } else {
20019            cx.propagate();
20020        }
20021    }
20022
20023    pub fn copy_relative_path(
20024        &mut self,
20025        _: &zed_actions::workspace::CopyRelativePath,
20026        _window: &mut Window,
20027        cx: &mut Context<Self>,
20028    ) {
20029        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20030            let project = self.project()?.read(cx);
20031            let path = buffer.read(cx).file()?.path();
20032            let path = path.display(project.path_style(cx));
20033            Some(path)
20034        }) {
20035            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20036        } else {
20037            cx.propagate();
20038        }
20039    }
20040
20041    /// Returns the project path for the editor's buffer, if any buffer is
20042    /// opened in the editor.
20043    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20044        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20045            buffer.read(cx).project_path(cx)
20046        } else {
20047            None
20048        }
20049    }
20050
20051    // Returns true if the editor handled a go-to-line request
20052    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20053        maybe!({
20054            let breakpoint_store = self.breakpoint_store.as_ref()?;
20055
20056            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20057            else {
20058                self.clear_row_highlights::<ActiveDebugLine>();
20059                return None;
20060            };
20061
20062            let position = active_stack_frame.position;
20063            let buffer_id = position.buffer_id?;
20064            let snapshot = self
20065                .project
20066                .as_ref()?
20067                .read(cx)
20068                .buffer_for_id(buffer_id, cx)?
20069                .read(cx)
20070                .snapshot();
20071
20072            let mut handled = false;
20073            for (id, ExcerptRange { context, .. }) in
20074                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20075            {
20076                if context.start.cmp(&position, &snapshot).is_ge()
20077                    || context.end.cmp(&position, &snapshot).is_lt()
20078                {
20079                    continue;
20080                }
20081                let snapshot = self.buffer.read(cx).snapshot(cx);
20082                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20083
20084                handled = true;
20085                self.clear_row_highlights::<ActiveDebugLine>();
20086
20087                self.go_to_line::<ActiveDebugLine>(
20088                    multibuffer_anchor,
20089                    Some(cx.theme().colors().editor_debugger_active_line_background),
20090                    window,
20091                    cx,
20092                );
20093
20094                cx.notify();
20095            }
20096
20097            handled.then_some(())
20098        })
20099        .is_some()
20100    }
20101
20102    pub fn copy_file_name_without_extension(
20103        &mut self,
20104        _: &CopyFileNameWithoutExtension,
20105        _: &mut Window,
20106        cx: &mut Context<Self>,
20107    ) {
20108        if let Some(file) = self.target_file(cx)
20109            && let Some(file_stem) = file.path().file_stem()
20110        {
20111            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20112        }
20113    }
20114
20115    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20116        if let Some(file) = self.target_file(cx)
20117            && let Some(name) = file.path().file_name()
20118        {
20119            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20120        }
20121    }
20122
20123    pub fn toggle_git_blame(
20124        &mut self,
20125        _: &::git::Blame,
20126        window: &mut Window,
20127        cx: &mut Context<Self>,
20128    ) {
20129        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20130
20131        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20132            self.start_git_blame(true, window, cx);
20133        }
20134
20135        cx.notify();
20136    }
20137
20138    pub fn toggle_git_blame_inline(
20139        &mut self,
20140        _: &ToggleGitBlameInline,
20141        window: &mut Window,
20142        cx: &mut Context<Self>,
20143    ) {
20144        self.toggle_git_blame_inline_internal(true, window, cx);
20145        cx.notify();
20146    }
20147
20148    pub fn open_git_blame_commit(
20149        &mut self,
20150        _: &OpenGitBlameCommit,
20151        window: &mut Window,
20152        cx: &mut Context<Self>,
20153    ) {
20154        self.open_git_blame_commit_internal(window, cx);
20155    }
20156
20157    fn open_git_blame_commit_internal(
20158        &mut self,
20159        window: &mut Window,
20160        cx: &mut Context<Self>,
20161    ) -> Option<()> {
20162        let blame = self.blame.as_ref()?;
20163        let snapshot = self.snapshot(window, cx);
20164        let cursor = self
20165            .selections
20166            .newest::<Point>(&snapshot.display_snapshot)
20167            .head();
20168        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20169        let (_, blame_entry) = blame
20170            .update(cx, |blame, cx| {
20171                blame
20172                    .blame_for_rows(
20173                        &[RowInfo {
20174                            buffer_id: Some(buffer.remote_id()),
20175                            buffer_row: Some(point.row),
20176                            ..Default::default()
20177                        }],
20178                        cx,
20179                    )
20180                    .next()
20181            })
20182            .flatten()?;
20183        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20184        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20185        let workspace = self.workspace()?.downgrade();
20186        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20187        None
20188    }
20189
20190    pub fn git_blame_inline_enabled(&self) -> bool {
20191        self.git_blame_inline_enabled
20192    }
20193
20194    pub fn toggle_selection_menu(
20195        &mut self,
20196        _: &ToggleSelectionMenu,
20197        _: &mut Window,
20198        cx: &mut Context<Self>,
20199    ) {
20200        self.show_selection_menu = self
20201            .show_selection_menu
20202            .map(|show_selections_menu| !show_selections_menu)
20203            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20204
20205        cx.notify();
20206    }
20207
20208    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20209        self.show_selection_menu
20210            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20211    }
20212
20213    fn start_git_blame(
20214        &mut self,
20215        user_triggered: bool,
20216        window: &mut Window,
20217        cx: &mut Context<Self>,
20218    ) {
20219        if let Some(project) = self.project() {
20220            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20221                && buffer.read(cx).file().is_none()
20222            {
20223                return;
20224            }
20225
20226            let focused = self.focus_handle(cx).contains_focused(window, cx);
20227
20228            let project = project.clone();
20229            let blame = cx
20230                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20231            self.blame_subscription =
20232                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20233            self.blame = Some(blame);
20234        }
20235    }
20236
20237    fn toggle_git_blame_inline_internal(
20238        &mut self,
20239        user_triggered: bool,
20240        window: &mut Window,
20241        cx: &mut Context<Self>,
20242    ) {
20243        if self.git_blame_inline_enabled {
20244            self.git_blame_inline_enabled = false;
20245            self.show_git_blame_inline = false;
20246            self.show_git_blame_inline_delay_task.take();
20247        } else {
20248            self.git_blame_inline_enabled = true;
20249            self.start_git_blame_inline(user_triggered, window, cx);
20250        }
20251
20252        cx.notify();
20253    }
20254
20255    fn start_git_blame_inline(
20256        &mut self,
20257        user_triggered: bool,
20258        window: &mut Window,
20259        cx: &mut Context<Self>,
20260    ) {
20261        self.start_git_blame(user_triggered, window, cx);
20262
20263        if ProjectSettings::get_global(cx)
20264            .git
20265            .inline_blame_delay()
20266            .is_some()
20267        {
20268            self.start_inline_blame_timer(window, cx);
20269        } else {
20270            self.show_git_blame_inline = true
20271        }
20272    }
20273
20274    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20275        self.blame.as_ref()
20276    }
20277
20278    pub fn show_git_blame_gutter(&self) -> bool {
20279        self.show_git_blame_gutter
20280    }
20281
20282    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20283        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20284    }
20285
20286    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20287        self.show_git_blame_inline
20288            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20289            && !self.newest_selection_head_on_empty_line(cx)
20290            && self.has_blame_entries(cx)
20291    }
20292
20293    fn has_blame_entries(&self, cx: &App) -> bool {
20294        self.blame()
20295            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20296    }
20297
20298    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20299        let cursor_anchor = self.selections.newest_anchor().head();
20300
20301        let snapshot = self.buffer.read(cx).snapshot(cx);
20302        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20303
20304        snapshot.line_len(buffer_row) == 0
20305    }
20306
20307    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20308        let buffer_and_selection = maybe!({
20309            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20310            let selection_range = selection.range();
20311
20312            let multi_buffer = self.buffer().read(cx);
20313            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20314            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20315
20316            let (buffer, range, _) = if selection.reversed {
20317                buffer_ranges.first()
20318            } else {
20319                buffer_ranges.last()
20320            }?;
20321
20322            let selection = text::ToPoint::to_point(&range.start, buffer).row
20323                ..text::ToPoint::to_point(&range.end, buffer).row;
20324            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20325        });
20326
20327        let Some((buffer, selection)) = buffer_and_selection else {
20328            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20329        };
20330
20331        let Some(project) = self.project() else {
20332            return Task::ready(Err(anyhow!("editor does not have project")));
20333        };
20334
20335        project.update(cx, |project, cx| {
20336            project.get_permalink_to_line(&buffer, selection, cx)
20337        })
20338    }
20339
20340    pub fn copy_permalink_to_line(
20341        &mut self,
20342        _: &CopyPermalinkToLine,
20343        window: &mut Window,
20344        cx: &mut Context<Self>,
20345    ) {
20346        let permalink_task = self.get_permalink_to_line(cx);
20347        let workspace = self.workspace();
20348
20349        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20350            Ok(permalink) => {
20351                cx.update(|_, cx| {
20352                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20353                })
20354                .ok();
20355            }
20356            Err(err) => {
20357                let message = format!("Failed to copy permalink: {err}");
20358
20359                anyhow::Result::<()>::Err(err).log_err();
20360
20361                if let Some(workspace) = workspace {
20362                    workspace
20363                        .update_in(cx, |workspace, _, cx| {
20364                            struct CopyPermalinkToLine;
20365
20366                            workspace.show_toast(
20367                                Toast::new(
20368                                    NotificationId::unique::<CopyPermalinkToLine>(),
20369                                    message,
20370                                ),
20371                                cx,
20372                            )
20373                        })
20374                        .ok();
20375                }
20376            }
20377        })
20378        .detach();
20379    }
20380
20381    pub fn copy_file_location(
20382        &mut self,
20383        _: &CopyFileLocation,
20384        _: &mut Window,
20385        cx: &mut Context<Self>,
20386    ) {
20387        let selection = self
20388            .selections
20389            .newest::<Point>(&self.display_snapshot(cx))
20390            .start
20391            .row
20392            + 1;
20393        if let Some(file) = self.target_file(cx) {
20394            let path = file.path().display(file.path_style(cx));
20395            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20396        }
20397    }
20398
20399    pub fn open_permalink_to_line(
20400        &mut self,
20401        _: &OpenPermalinkToLine,
20402        window: &mut Window,
20403        cx: &mut Context<Self>,
20404    ) {
20405        let permalink_task = self.get_permalink_to_line(cx);
20406        let workspace = self.workspace();
20407
20408        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20409            Ok(permalink) => {
20410                cx.update(|_, cx| {
20411                    cx.open_url(permalink.as_ref());
20412                })
20413                .ok();
20414            }
20415            Err(err) => {
20416                let message = format!("Failed to open permalink: {err}");
20417
20418                anyhow::Result::<()>::Err(err).log_err();
20419
20420                if let Some(workspace) = workspace {
20421                    workspace
20422                        .update(cx, |workspace, cx| {
20423                            struct OpenPermalinkToLine;
20424
20425                            workspace.show_toast(
20426                                Toast::new(
20427                                    NotificationId::unique::<OpenPermalinkToLine>(),
20428                                    message,
20429                                ),
20430                                cx,
20431                            )
20432                        })
20433                        .ok();
20434                }
20435            }
20436        })
20437        .detach();
20438    }
20439
20440    pub fn insert_uuid_v4(
20441        &mut self,
20442        _: &InsertUuidV4,
20443        window: &mut Window,
20444        cx: &mut Context<Self>,
20445    ) {
20446        self.insert_uuid(UuidVersion::V4, window, cx);
20447    }
20448
20449    pub fn insert_uuid_v7(
20450        &mut self,
20451        _: &InsertUuidV7,
20452        window: &mut Window,
20453        cx: &mut Context<Self>,
20454    ) {
20455        self.insert_uuid(UuidVersion::V7, window, cx);
20456    }
20457
20458    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20459        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20460        self.transact(window, cx, |this, window, cx| {
20461            let edits = this
20462                .selections
20463                .all::<Point>(&this.display_snapshot(cx))
20464                .into_iter()
20465                .map(|selection| {
20466                    let uuid = match version {
20467                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20468                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20469                    };
20470
20471                    (selection.range(), uuid.to_string())
20472                });
20473            this.edit(edits, cx);
20474            this.refresh_edit_prediction(true, false, window, cx);
20475        });
20476    }
20477
20478    pub fn open_selections_in_multibuffer(
20479        &mut self,
20480        _: &OpenSelectionsInMultibuffer,
20481        window: &mut Window,
20482        cx: &mut Context<Self>,
20483    ) {
20484        let multibuffer = self.buffer.read(cx);
20485
20486        let Some(buffer) = multibuffer.as_singleton() else {
20487            return;
20488        };
20489
20490        let Some(workspace) = self.workspace() else {
20491            return;
20492        };
20493
20494        let title = multibuffer.title(cx).to_string();
20495
20496        let locations = self
20497            .selections
20498            .all_anchors(&self.display_snapshot(cx))
20499            .iter()
20500            .map(|selection| {
20501                (
20502                    buffer.clone(),
20503                    (selection.start.text_anchor..selection.end.text_anchor)
20504                        .to_point(buffer.read(cx)),
20505                )
20506            })
20507            .into_group_map();
20508
20509        cx.spawn_in(window, async move |_, cx| {
20510            workspace.update_in(cx, |workspace, window, cx| {
20511                Self::open_locations_in_multibuffer(
20512                    workspace,
20513                    locations,
20514                    format!("Selections for '{title}'"),
20515                    false,
20516                    MultibufferSelectionMode::All,
20517                    window,
20518                    cx,
20519                );
20520            })
20521        })
20522        .detach();
20523    }
20524
20525    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20526    /// last highlight added will be used.
20527    ///
20528    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20529    pub fn highlight_rows<T: 'static>(
20530        &mut self,
20531        range: Range<Anchor>,
20532        color: Hsla,
20533        options: RowHighlightOptions,
20534        cx: &mut Context<Self>,
20535    ) {
20536        let snapshot = self.buffer().read(cx).snapshot(cx);
20537        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20538        let ix = row_highlights.binary_search_by(|highlight| {
20539            Ordering::Equal
20540                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20541                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20542        });
20543
20544        if let Err(mut ix) = ix {
20545            let index = post_inc(&mut self.highlight_order);
20546
20547            // If this range intersects with the preceding highlight, then merge it with
20548            // the preceding highlight. Otherwise insert a new highlight.
20549            let mut merged = false;
20550            if ix > 0 {
20551                let prev_highlight = &mut row_highlights[ix - 1];
20552                if prev_highlight
20553                    .range
20554                    .end
20555                    .cmp(&range.start, &snapshot)
20556                    .is_ge()
20557                {
20558                    ix -= 1;
20559                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20560                        prev_highlight.range.end = range.end;
20561                    }
20562                    merged = true;
20563                    prev_highlight.index = index;
20564                    prev_highlight.color = color;
20565                    prev_highlight.options = options;
20566                }
20567            }
20568
20569            if !merged {
20570                row_highlights.insert(
20571                    ix,
20572                    RowHighlight {
20573                        range,
20574                        index,
20575                        color,
20576                        options,
20577                        type_id: TypeId::of::<T>(),
20578                    },
20579                );
20580            }
20581
20582            // If any of the following highlights intersect with this one, merge them.
20583            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20584                let highlight = &row_highlights[ix];
20585                if next_highlight
20586                    .range
20587                    .start
20588                    .cmp(&highlight.range.end, &snapshot)
20589                    .is_le()
20590                {
20591                    if next_highlight
20592                        .range
20593                        .end
20594                        .cmp(&highlight.range.end, &snapshot)
20595                        .is_gt()
20596                    {
20597                        row_highlights[ix].range.end = next_highlight.range.end;
20598                    }
20599                    row_highlights.remove(ix + 1);
20600                } else {
20601                    break;
20602                }
20603            }
20604        }
20605    }
20606
20607    /// Remove any highlighted row ranges of the given type that intersect the
20608    /// given ranges.
20609    pub fn remove_highlighted_rows<T: 'static>(
20610        &mut self,
20611        ranges_to_remove: Vec<Range<Anchor>>,
20612        cx: &mut Context<Self>,
20613    ) {
20614        let snapshot = self.buffer().read(cx).snapshot(cx);
20615        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20616        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20617        row_highlights.retain(|highlight| {
20618            while let Some(range_to_remove) = ranges_to_remove.peek() {
20619                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20620                    Ordering::Less | Ordering::Equal => {
20621                        ranges_to_remove.next();
20622                    }
20623                    Ordering::Greater => {
20624                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20625                            Ordering::Less | Ordering::Equal => {
20626                                return false;
20627                            }
20628                            Ordering::Greater => break,
20629                        }
20630                    }
20631                }
20632            }
20633
20634            true
20635        })
20636    }
20637
20638    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20639    pub fn clear_row_highlights<T: 'static>(&mut self) {
20640        self.highlighted_rows.remove(&TypeId::of::<T>());
20641    }
20642
20643    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20644    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20645        self.highlighted_rows
20646            .get(&TypeId::of::<T>())
20647            .map_or(&[] as &[_], |vec| vec.as_slice())
20648            .iter()
20649            .map(|highlight| (highlight.range.clone(), highlight.color))
20650    }
20651
20652    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20653    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20654    /// Allows to ignore certain kinds of highlights.
20655    pub fn highlighted_display_rows(
20656        &self,
20657        window: &mut Window,
20658        cx: &mut App,
20659    ) -> BTreeMap<DisplayRow, LineHighlight> {
20660        let snapshot = self.snapshot(window, cx);
20661        let mut used_highlight_orders = HashMap::default();
20662        self.highlighted_rows
20663            .iter()
20664            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20665            .fold(
20666                BTreeMap::<DisplayRow, LineHighlight>::new(),
20667                |mut unique_rows, highlight| {
20668                    let start = highlight.range.start.to_display_point(&snapshot);
20669                    let end = highlight.range.end.to_display_point(&snapshot);
20670                    let start_row = start.row().0;
20671                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20672                        && end.column() == 0
20673                    {
20674                        end.row().0.saturating_sub(1)
20675                    } else {
20676                        end.row().0
20677                    };
20678                    for row in start_row..=end_row {
20679                        let used_index =
20680                            used_highlight_orders.entry(row).or_insert(highlight.index);
20681                        if highlight.index >= *used_index {
20682                            *used_index = highlight.index;
20683                            unique_rows.insert(
20684                                DisplayRow(row),
20685                                LineHighlight {
20686                                    include_gutter: highlight.options.include_gutter,
20687                                    border: None,
20688                                    background: highlight.color.into(),
20689                                    type_id: Some(highlight.type_id),
20690                                },
20691                            );
20692                        }
20693                    }
20694                    unique_rows
20695                },
20696            )
20697    }
20698
20699    pub fn highlighted_display_row_for_autoscroll(
20700        &self,
20701        snapshot: &DisplaySnapshot,
20702    ) -> Option<DisplayRow> {
20703        self.highlighted_rows
20704            .values()
20705            .flat_map(|highlighted_rows| highlighted_rows.iter())
20706            .filter_map(|highlight| {
20707                if highlight.options.autoscroll {
20708                    Some(highlight.range.start.to_display_point(snapshot).row())
20709                } else {
20710                    None
20711                }
20712            })
20713            .min()
20714    }
20715
20716    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20717        self.highlight_background::<SearchWithinRange>(
20718            ranges,
20719            |colors| colors.colors().editor_document_highlight_read_background,
20720            cx,
20721        )
20722    }
20723
20724    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20725        self.breadcrumb_header = Some(new_header);
20726    }
20727
20728    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20729        self.clear_background_highlights::<SearchWithinRange>(cx);
20730    }
20731
20732    pub fn highlight_background<T: 'static>(
20733        &mut self,
20734        ranges: &[Range<Anchor>],
20735        color_fetcher: fn(&Theme) -> Hsla,
20736        cx: &mut Context<Self>,
20737    ) {
20738        self.background_highlights.insert(
20739            HighlightKey::Type(TypeId::of::<T>()),
20740            (color_fetcher, Arc::from(ranges)),
20741        );
20742        self.scrollbar_marker_state.dirty = true;
20743        cx.notify();
20744    }
20745
20746    pub fn highlight_background_key<T: 'static>(
20747        &mut self,
20748        key: usize,
20749        ranges: &[Range<Anchor>],
20750        color_fetcher: fn(&Theme) -> Hsla,
20751        cx: &mut Context<Self>,
20752    ) {
20753        self.background_highlights.insert(
20754            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20755            (color_fetcher, Arc::from(ranges)),
20756        );
20757        self.scrollbar_marker_state.dirty = true;
20758        cx.notify();
20759    }
20760
20761    pub fn clear_background_highlights<T: 'static>(
20762        &mut self,
20763        cx: &mut Context<Self>,
20764    ) -> Option<BackgroundHighlight> {
20765        let text_highlights = self
20766            .background_highlights
20767            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20768        if !text_highlights.1.is_empty() {
20769            self.scrollbar_marker_state.dirty = true;
20770            cx.notify();
20771        }
20772        Some(text_highlights)
20773    }
20774
20775    pub fn highlight_gutter<T: 'static>(
20776        &mut self,
20777        ranges: impl Into<Vec<Range<Anchor>>>,
20778        color_fetcher: fn(&App) -> Hsla,
20779        cx: &mut Context<Self>,
20780    ) {
20781        self.gutter_highlights
20782            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20783        cx.notify();
20784    }
20785
20786    pub fn clear_gutter_highlights<T: 'static>(
20787        &mut self,
20788        cx: &mut Context<Self>,
20789    ) -> Option<GutterHighlight> {
20790        cx.notify();
20791        self.gutter_highlights.remove(&TypeId::of::<T>())
20792    }
20793
20794    pub fn insert_gutter_highlight<T: 'static>(
20795        &mut self,
20796        range: Range<Anchor>,
20797        color_fetcher: fn(&App) -> Hsla,
20798        cx: &mut Context<Self>,
20799    ) {
20800        let snapshot = self.buffer().read(cx).snapshot(cx);
20801        let mut highlights = self
20802            .gutter_highlights
20803            .remove(&TypeId::of::<T>())
20804            .map(|(_, highlights)| highlights)
20805            .unwrap_or_default();
20806        let ix = highlights.binary_search_by(|highlight| {
20807            Ordering::Equal
20808                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20809                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20810        });
20811        if let Err(ix) = ix {
20812            highlights.insert(ix, range);
20813        }
20814        self.gutter_highlights
20815            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20816    }
20817
20818    pub fn remove_gutter_highlights<T: 'static>(
20819        &mut self,
20820        ranges_to_remove: Vec<Range<Anchor>>,
20821        cx: &mut Context<Self>,
20822    ) {
20823        let snapshot = self.buffer().read(cx).snapshot(cx);
20824        let Some((color_fetcher, mut gutter_highlights)) =
20825            self.gutter_highlights.remove(&TypeId::of::<T>())
20826        else {
20827            return;
20828        };
20829        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20830        gutter_highlights.retain(|highlight| {
20831            while let Some(range_to_remove) = ranges_to_remove.peek() {
20832                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20833                    Ordering::Less | Ordering::Equal => {
20834                        ranges_to_remove.next();
20835                    }
20836                    Ordering::Greater => {
20837                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20838                            Ordering::Less | Ordering::Equal => {
20839                                return false;
20840                            }
20841                            Ordering::Greater => break,
20842                        }
20843                    }
20844                }
20845            }
20846
20847            true
20848        });
20849        self.gutter_highlights
20850            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20851    }
20852
20853    #[cfg(feature = "test-support")]
20854    pub fn all_text_highlights(
20855        &self,
20856        window: &mut Window,
20857        cx: &mut Context<Self>,
20858    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20859        let snapshot = self.snapshot(window, cx);
20860        self.display_map.update(cx, |display_map, _| {
20861            display_map
20862                .all_text_highlights()
20863                .map(|highlight| {
20864                    let (style, ranges) = highlight.as_ref();
20865                    (
20866                        *style,
20867                        ranges
20868                            .iter()
20869                            .map(|range| range.clone().to_display_points(&snapshot))
20870                            .collect(),
20871                    )
20872                })
20873                .collect()
20874        })
20875    }
20876
20877    #[cfg(feature = "test-support")]
20878    pub fn all_text_background_highlights(
20879        &self,
20880        window: &mut Window,
20881        cx: &mut Context<Self>,
20882    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20883        let snapshot = self.snapshot(window, cx);
20884        let buffer = &snapshot.buffer_snapshot();
20885        let start = buffer.anchor_before(0);
20886        let end = buffer.anchor_after(buffer.len());
20887        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20888    }
20889
20890    #[cfg(any(test, feature = "test-support"))]
20891    pub fn sorted_background_highlights_in_range(
20892        &self,
20893        search_range: Range<Anchor>,
20894        display_snapshot: &DisplaySnapshot,
20895        theme: &Theme,
20896    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20897        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20898        res.sort_by(|a, b| {
20899            a.0.start
20900                .cmp(&b.0.start)
20901                .then_with(|| a.0.end.cmp(&b.0.end))
20902                .then_with(|| a.1.cmp(&b.1))
20903        });
20904        res
20905    }
20906
20907    #[cfg(feature = "test-support")]
20908    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20909        let snapshot = self.buffer().read(cx).snapshot(cx);
20910
20911        let highlights = self
20912            .background_highlights
20913            .get(&HighlightKey::Type(TypeId::of::<
20914                items::BufferSearchHighlights,
20915            >()));
20916
20917        if let Some((_color, ranges)) = highlights {
20918            ranges
20919                .iter()
20920                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20921                .collect_vec()
20922        } else {
20923            vec![]
20924        }
20925    }
20926
20927    fn document_highlights_for_position<'a>(
20928        &'a self,
20929        position: Anchor,
20930        buffer: &'a MultiBufferSnapshot,
20931    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20932        let read_highlights = self
20933            .background_highlights
20934            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20935            .map(|h| &h.1);
20936        let write_highlights = self
20937            .background_highlights
20938            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20939            .map(|h| &h.1);
20940        let left_position = position.bias_left(buffer);
20941        let right_position = position.bias_right(buffer);
20942        read_highlights
20943            .into_iter()
20944            .chain(write_highlights)
20945            .flat_map(move |ranges| {
20946                let start_ix = match ranges.binary_search_by(|probe| {
20947                    let cmp = probe.end.cmp(&left_position, buffer);
20948                    if cmp.is_ge() {
20949                        Ordering::Greater
20950                    } else {
20951                        Ordering::Less
20952                    }
20953                }) {
20954                    Ok(i) | Err(i) => i,
20955                };
20956
20957                ranges[start_ix..]
20958                    .iter()
20959                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20960            })
20961    }
20962
20963    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20964        self.background_highlights
20965            .get(&HighlightKey::Type(TypeId::of::<T>()))
20966            .is_some_and(|(_, highlights)| !highlights.is_empty())
20967    }
20968
20969    /// Returns all background highlights for a given range.
20970    ///
20971    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20972    pub fn background_highlights_in_range(
20973        &self,
20974        search_range: Range<Anchor>,
20975        display_snapshot: &DisplaySnapshot,
20976        theme: &Theme,
20977    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20978        let mut results = Vec::new();
20979        for (color_fetcher, ranges) in self.background_highlights.values() {
20980            let color = color_fetcher(theme);
20981            let start_ix = match ranges.binary_search_by(|probe| {
20982                let cmp = probe
20983                    .end
20984                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20985                if cmp.is_gt() {
20986                    Ordering::Greater
20987                } else {
20988                    Ordering::Less
20989                }
20990            }) {
20991                Ok(i) | Err(i) => i,
20992            };
20993            for range in &ranges[start_ix..] {
20994                if range
20995                    .start
20996                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20997                    .is_ge()
20998                {
20999                    break;
21000                }
21001
21002                let start = range.start.to_display_point(display_snapshot);
21003                let end = range.end.to_display_point(display_snapshot);
21004                results.push((start..end, color))
21005            }
21006        }
21007        results
21008    }
21009
21010    pub fn gutter_highlights_in_range(
21011        &self,
21012        search_range: Range<Anchor>,
21013        display_snapshot: &DisplaySnapshot,
21014        cx: &App,
21015    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21016        let mut results = Vec::new();
21017        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21018            let color = color_fetcher(cx);
21019            let start_ix = match ranges.binary_search_by(|probe| {
21020                let cmp = probe
21021                    .end
21022                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21023                if cmp.is_gt() {
21024                    Ordering::Greater
21025                } else {
21026                    Ordering::Less
21027                }
21028            }) {
21029                Ok(i) | Err(i) => i,
21030            };
21031            for range in &ranges[start_ix..] {
21032                if range
21033                    .start
21034                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21035                    .is_ge()
21036                {
21037                    break;
21038                }
21039
21040                let start = range.start.to_display_point(display_snapshot);
21041                let end = range.end.to_display_point(display_snapshot);
21042                results.push((start..end, color))
21043            }
21044        }
21045        results
21046    }
21047
21048    /// Get the text ranges corresponding to the redaction query
21049    pub fn redacted_ranges(
21050        &self,
21051        search_range: Range<Anchor>,
21052        display_snapshot: &DisplaySnapshot,
21053        cx: &App,
21054    ) -> Vec<Range<DisplayPoint>> {
21055        display_snapshot
21056            .buffer_snapshot()
21057            .redacted_ranges(search_range, |file| {
21058                if let Some(file) = file {
21059                    file.is_private()
21060                        && EditorSettings::get(
21061                            Some(SettingsLocation {
21062                                worktree_id: file.worktree_id(cx),
21063                                path: file.path().as_ref(),
21064                            }),
21065                            cx,
21066                        )
21067                        .redact_private_values
21068                } else {
21069                    false
21070                }
21071            })
21072            .map(|range| {
21073                range.start.to_display_point(display_snapshot)
21074                    ..range.end.to_display_point(display_snapshot)
21075            })
21076            .collect()
21077    }
21078
21079    pub fn highlight_text_key<T: 'static>(
21080        &mut self,
21081        key: usize,
21082        ranges: Vec<Range<Anchor>>,
21083        style: HighlightStyle,
21084        cx: &mut Context<Self>,
21085    ) {
21086        self.display_map.update(cx, |map, _| {
21087            map.highlight_text(
21088                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21089                ranges,
21090                style,
21091            );
21092        });
21093        cx.notify();
21094    }
21095
21096    pub fn highlight_text<T: 'static>(
21097        &mut self,
21098        ranges: Vec<Range<Anchor>>,
21099        style: HighlightStyle,
21100        cx: &mut Context<Self>,
21101    ) {
21102        self.display_map.update(cx, |map, _| {
21103            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
21104        });
21105        cx.notify();
21106    }
21107
21108    pub fn text_highlights<'a, T: 'static>(
21109        &'a self,
21110        cx: &'a App,
21111    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21112        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21113    }
21114
21115    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21116        let cleared = self
21117            .display_map
21118            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21119        if cleared {
21120            cx.notify();
21121        }
21122    }
21123
21124    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21125        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21126            && self.focus_handle.is_focused(window)
21127    }
21128
21129    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21130        self.show_cursor_when_unfocused = is_enabled;
21131        cx.notify();
21132    }
21133
21134    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21135        cx.notify();
21136    }
21137
21138    fn on_debug_session_event(
21139        &mut self,
21140        _session: Entity<Session>,
21141        event: &SessionEvent,
21142        cx: &mut Context<Self>,
21143    ) {
21144        if let SessionEvent::InvalidateInlineValue = event {
21145            self.refresh_inline_values(cx);
21146        }
21147    }
21148
21149    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21150        let Some(project) = self.project.clone() else {
21151            return;
21152        };
21153
21154        if !self.inline_value_cache.enabled {
21155            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21156            self.splice_inlays(&inlays, Vec::new(), cx);
21157            return;
21158        }
21159
21160        let current_execution_position = self
21161            .highlighted_rows
21162            .get(&TypeId::of::<ActiveDebugLine>())
21163            .and_then(|lines| lines.last().map(|line| line.range.end));
21164
21165        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21166            let inline_values = editor
21167                .update(cx, |editor, cx| {
21168                    let Some(current_execution_position) = current_execution_position else {
21169                        return Some(Task::ready(Ok(Vec::new())));
21170                    };
21171
21172                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21173                        let snapshot = buffer.snapshot(cx);
21174
21175                        let excerpt = snapshot.excerpt_containing(
21176                            current_execution_position..current_execution_position,
21177                        )?;
21178
21179                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21180                    })?;
21181
21182                    let range =
21183                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21184
21185                    project.inline_values(buffer, range, cx)
21186                })
21187                .ok()
21188                .flatten()?
21189                .await
21190                .context("refreshing debugger inlays")
21191                .log_err()?;
21192
21193            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21194
21195            for (buffer_id, inline_value) in inline_values
21196                .into_iter()
21197                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21198            {
21199                buffer_inline_values
21200                    .entry(buffer_id)
21201                    .or_default()
21202                    .push(inline_value);
21203            }
21204
21205            editor
21206                .update(cx, |editor, cx| {
21207                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21208                    let mut new_inlays = Vec::default();
21209
21210                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21211                        let buffer_id = buffer_snapshot.remote_id();
21212                        buffer_inline_values
21213                            .get(&buffer_id)
21214                            .into_iter()
21215                            .flatten()
21216                            .for_each(|hint| {
21217                                let inlay = Inlay::debugger(
21218                                    post_inc(&mut editor.next_inlay_id),
21219                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21220                                    hint.text(),
21221                                );
21222                                if !inlay.text().chars().contains(&'\n') {
21223                                    new_inlays.push(inlay);
21224                                }
21225                            });
21226                    }
21227
21228                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21229                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21230
21231                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21232                })
21233                .ok()?;
21234            Some(())
21235        });
21236    }
21237
21238    fn on_buffer_event(
21239        &mut self,
21240        multibuffer: &Entity<MultiBuffer>,
21241        event: &multi_buffer::Event,
21242        window: &mut Window,
21243        cx: &mut Context<Self>,
21244    ) {
21245        match event {
21246            multi_buffer::Event::Edited { edited_buffer } => {
21247                self.scrollbar_marker_state.dirty = true;
21248                self.active_indent_guides_state.dirty = true;
21249                self.refresh_active_diagnostics(cx);
21250                self.refresh_code_actions(window, cx);
21251                self.refresh_selected_text_highlights(true, window, cx);
21252                self.refresh_single_line_folds(window, cx);
21253                self.refresh_matching_bracket_highlights(window, cx);
21254                if self.has_active_edit_prediction() {
21255                    self.update_visible_edit_prediction(window, cx);
21256                }
21257
21258                if let Some(buffer) = edited_buffer {
21259                    if buffer.read(cx).file().is_none() {
21260                        cx.emit(EditorEvent::TitleChanged);
21261                    }
21262
21263                    if self.project.is_some() {
21264                        let buffer_id = buffer.read(cx).remote_id();
21265                        self.register_buffer(buffer_id, cx);
21266                        self.update_lsp_data(Some(buffer_id), window, cx);
21267                        self.refresh_inlay_hints(
21268                            InlayHintRefreshReason::BufferEdited(buffer_id),
21269                            cx,
21270                        );
21271                    }
21272                }
21273
21274                cx.emit(EditorEvent::BufferEdited);
21275                cx.emit(SearchEvent::MatchesInvalidated);
21276
21277                let Some(project) = &self.project else { return };
21278                let (telemetry, is_via_ssh) = {
21279                    let project = project.read(cx);
21280                    let telemetry = project.client().telemetry().clone();
21281                    let is_via_ssh = project.is_via_remote_server();
21282                    (telemetry, is_via_ssh)
21283                };
21284                telemetry.log_edit_event("editor", is_via_ssh);
21285            }
21286            multi_buffer::Event::ExcerptsAdded {
21287                buffer,
21288                predecessor,
21289                excerpts,
21290            } => {
21291                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21292                let buffer_id = buffer.read(cx).remote_id();
21293                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21294                    && let Some(project) = &self.project
21295                {
21296                    update_uncommitted_diff_for_buffer(
21297                        cx.entity(),
21298                        project,
21299                        [buffer.clone()],
21300                        self.buffer.clone(),
21301                        cx,
21302                    )
21303                    .detach();
21304                }
21305                self.update_lsp_data(Some(buffer_id), window, cx);
21306                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21307                cx.emit(EditorEvent::ExcerptsAdded {
21308                    buffer: buffer.clone(),
21309                    predecessor: *predecessor,
21310                    excerpts: excerpts.clone(),
21311                });
21312            }
21313            multi_buffer::Event::ExcerptsRemoved {
21314                ids,
21315                removed_buffer_ids,
21316            } => {
21317                if let Some(inlay_hints) = &mut self.inlay_hints {
21318                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21319                }
21320                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21321                for buffer_id in removed_buffer_ids {
21322                    self.registered_buffers.remove(buffer_id);
21323                }
21324                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21325                cx.emit(EditorEvent::ExcerptsRemoved {
21326                    ids: ids.clone(),
21327                    removed_buffer_ids: removed_buffer_ids.clone(),
21328                });
21329            }
21330            multi_buffer::Event::ExcerptsEdited {
21331                excerpt_ids,
21332                buffer_ids,
21333            } => {
21334                self.display_map.update(cx, |map, cx| {
21335                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21336                });
21337                cx.emit(EditorEvent::ExcerptsEdited {
21338                    ids: excerpt_ids.clone(),
21339                });
21340            }
21341            multi_buffer::Event::ExcerptsExpanded { ids } => {
21342                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21343                self.refresh_document_highlights(cx);
21344                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21345            }
21346            multi_buffer::Event::Reparsed(buffer_id) => {
21347                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21348                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21349
21350                cx.emit(EditorEvent::Reparsed(*buffer_id));
21351            }
21352            multi_buffer::Event::DiffHunksToggled => {
21353                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21354            }
21355            multi_buffer::Event::LanguageChanged(buffer_id) => {
21356                self.registered_buffers.remove(&buffer_id);
21357                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21358                cx.emit(EditorEvent::Reparsed(*buffer_id));
21359                cx.notify();
21360            }
21361            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21362            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21363            multi_buffer::Event::FileHandleChanged
21364            | multi_buffer::Event::Reloaded
21365            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21366            multi_buffer::Event::DiagnosticsUpdated => {
21367                self.update_diagnostics_state(window, cx);
21368            }
21369            _ => {}
21370        };
21371    }
21372
21373    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21374        if !self.diagnostics_enabled() {
21375            return;
21376        }
21377        self.refresh_active_diagnostics(cx);
21378        self.refresh_inline_diagnostics(true, window, cx);
21379        self.scrollbar_marker_state.dirty = true;
21380        cx.notify();
21381    }
21382
21383    pub fn start_temporary_diff_override(&mut self) {
21384        self.load_diff_task.take();
21385        self.temporary_diff_override = true;
21386    }
21387
21388    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21389        self.temporary_diff_override = false;
21390        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21391        self.buffer.update(cx, |buffer, cx| {
21392            buffer.set_all_diff_hunks_collapsed(cx);
21393        });
21394
21395        if let Some(project) = self.project.clone() {
21396            self.load_diff_task = Some(
21397                update_uncommitted_diff_for_buffer(
21398                    cx.entity(),
21399                    &project,
21400                    self.buffer.read(cx).all_buffers(),
21401                    self.buffer.clone(),
21402                    cx,
21403                )
21404                .shared(),
21405            );
21406        }
21407    }
21408
21409    fn on_display_map_changed(
21410        &mut self,
21411        _: Entity<DisplayMap>,
21412        _: &mut Window,
21413        cx: &mut Context<Self>,
21414    ) {
21415        cx.notify();
21416    }
21417
21418    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21419        if self.diagnostics_enabled() {
21420            let new_severity = EditorSettings::get_global(cx)
21421                .diagnostics_max_severity
21422                .unwrap_or(DiagnosticSeverity::Hint);
21423            self.set_max_diagnostics_severity(new_severity, cx);
21424        }
21425        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21426        self.update_edit_prediction_settings(cx);
21427        self.refresh_edit_prediction(true, false, window, cx);
21428        self.refresh_inline_values(cx);
21429        self.refresh_inlay_hints(
21430            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21431                self.selections.newest_anchor().head(),
21432                &self.buffer.read(cx).snapshot(cx),
21433                cx,
21434            )),
21435            cx,
21436        );
21437
21438        let old_cursor_shape = self.cursor_shape;
21439        let old_show_breadcrumbs = self.show_breadcrumbs;
21440
21441        {
21442            let editor_settings = EditorSettings::get_global(cx);
21443            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21444            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21445            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21446            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21447        }
21448
21449        if old_cursor_shape != self.cursor_shape {
21450            cx.emit(EditorEvent::CursorShapeChanged);
21451        }
21452
21453        if old_show_breadcrumbs != self.show_breadcrumbs {
21454            cx.emit(EditorEvent::BreadcrumbsChanged);
21455        }
21456
21457        let project_settings = ProjectSettings::get_global(cx);
21458        self.buffer_serialization = self
21459            .should_serialize_buffer()
21460            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21461
21462        if self.mode.is_full() {
21463            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21464            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21465            if self.show_inline_diagnostics != show_inline_diagnostics {
21466                self.show_inline_diagnostics = show_inline_diagnostics;
21467                self.refresh_inline_diagnostics(false, window, cx);
21468            }
21469
21470            if self.git_blame_inline_enabled != inline_blame_enabled {
21471                self.toggle_git_blame_inline_internal(false, window, cx);
21472            }
21473
21474            let minimap_settings = EditorSettings::get_global(cx).minimap;
21475            if self.minimap_visibility != MinimapVisibility::Disabled {
21476                if self.minimap_visibility.settings_visibility()
21477                    != minimap_settings.minimap_enabled()
21478                {
21479                    self.set_minimap_visibility(
21480                        MinimapVisibility::for_mode(self.mode(), cx),
21481                        window,
21482                        cx,
21483                    );
21484                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21485                    minimap_entity.update(cx, |minimap_editor, cx| {
21486                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21487                    })
21488                }
21489            }
21490        }
21491
21492        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21493            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21494        }) {
21495            if !inlay_splice.is_empty() {
21496                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21497            }
21498            self.refresh_colors_for_visible_range(None, window, cx);
21499        }
21500
21501        cx.notify();
21502    }
21503
21504    pub fn set_searchable(&mut self, searchable: bool) {
21505        self.searchable = searchable;
21506    }
21507
21508    pub fn searchable(&self) -> bool {
21509        self.searchable
21510    }
21511
21512    pub fn open_excerpts_in_split(
21513        &mut self,
21514        _: &OpenExcerptsSplit,
21515        window: &mut Window,
21516        cx: &mut Context<Self>,
21517    ) {
21518        self.open_excerpts_common(None, true, window, cx)
21519    }
21520
21521    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21522        self.open_excerpts_common(None, false, window, cx)
21523    }
21524
21525    fn open_excerpts_common(
21526        &mut self,
21527        jump_data: Option<JumpData>,
21528        split: bool,
21529        window: &mut Window,
21530        cx: &mut Context<Self>,
21531    ) {
21532        let Some(workspace) = self.workspace() else {
21533            cx.propagate();
21534            return;
21535        };
21536
21537        if self.buffer.read(cx).is_singleton() {
21538            cx.propagate();
21539            return;
21540        }
21541
21542        let mut new_selections_by_buffer = HashMap::default();
21543        match &jump_data {
21544            Some(JumpData::MultiBufferPoint {
21545                excerpt_id,
21546                position,
21547                anchor,
21548                line_offset_from_top,
21549            }) => {
21550                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21551                if let Some(buffer) = multi_buffer_snapshot
21552                    .buffer_id_for_excerpt(*excerpt_id)
21553                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21554                {
21555                    let buffer_snapshot = buffer.read(cx).snapshot();
21556                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21557                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21558                    } else {
21559                        buffer_snapshot.clip_point(*position, Bias::Left)
21560                    };
21561                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21562                    new_selections_by_buffer.insert(
21563                        buffer,
21564                        (
21565                            vec![jump_to_offset..jump_to_offset],
21566                            Some(*line_offset_from_top),
21567                        ),
21568                    );
21569                }
21570            }
21571            Some(JumpData::MultiBufferRow {
21572                row,
21573                line_offset_from_top,
21574            }) => {
21575                let point = MultiBufferPoint::new(row.0, 0);
21576                if let Some((buffer, buffer_point, _)) =
21577                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21578                {
21579                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21580                    new_selections_by_buffer
21581                        .entry(buffer)
21582                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21583                        .0
21584                        .push(buffer_offset..buffer_offset)
21585                }
21586            }
21587            None => {
21588                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21589                let multi_buffer = self.buffer.read(cx);
21590                for selection in selections {
21591                    for (snapshot, range, _, anchor) in multi_buffer
21592                        .snapshot(cx)
21593                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21594                    {
21595                        if let Some(anchor) = anchor {
21596                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21597                            else {
21598                                continue;
21599                            };
21600                            let offset = text::ToOffset::to_offset(
21601                                &anchor.text_anchor,
21602                                &buffer_handle.read(cx).snapshot(),
21603                            );
21604                            let range = offset..offset;
21605                            new_selections_by_buffer
21606                                .entry(buffer_handle)
21607                                .or_insert((Vec::new(), None))
21608                                .0
21609                                .push(range)
21610                        } else {
21611                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21612                            else {
21613                                continue;
21614                            };
21615                            new_selections_by_buffer
21616                                .entry(buffer_handle)
21617                                .or_insert((Vec::new(), None))
21618                                .0
21619                                .push(range)
21620                        }
21621                    }
21622                }
21623            }
21624        }
21625
21626        new_selections_by_buffer
21627            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21628
21629        if new_selections_by_buffer.is_empty() {
21630            return;
21631        }
21632
21633        // We defer the pane interaction because we ourselves are a workspace item
21634        // and activating a new item causes the pane to call a method on us reentrantly,
21635        // which panics if we're on the stack.
21636        window.defer(cx, move |window, cx| {
21637            workspace.update(cx, |workspace, cx| {
21638                let pane = if split {
21639                    workspace.adjacent_pane(window, cx)
21640                } else {
21641                    workspace.active_pane().clone()
21642                };
21643
21644                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21645                    let editor = buffer
21646                        .read(cx)
21647                        .file()
21648                        .is_none()
21649                        .then(|| {
21650                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21651                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21652                            // Instead, we try to activate the existing editor in the pane first.
21653                            let (editor, pane_item_index) =
21654                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21655                                    let editor = item.downcast::<Editor>()?;
21656                                    let singleton_buffer =
21657                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21658                                    if singleton_buffer == buffer {
21659                                        Some((editor, i))
21660                                    } else {
21661                                        None
21662                                    }
21663                                })?;
21664                            pane.update(cx, |pane, cx| {
21665                                pane.activate_item(pane_item_index, true, true, window, cx)
21666                            });
21667                            Some(editor)
21668                        })
21669                        .flatten()
21670                        .unwrap_or_else(|| {
21671                            workspace.open_project_item::<Self>(
21672                                pane.clone(),
21673                                buffer,
21674                                true,
21675                                true,
21676                                window,
21677                                cx,
21678                            )
21679                        });
21680
21681                    editor.update(cx, |editor, cx| {
21682                        let autoscroll = match scroll_offset {
21683                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21684                            None => Autoscroll::newest(),
21685                        };
21686                        let nav_history = editor.nav_history.take();
21687                        editor.change_selections(
21688                            SelectionEffects::scroll(autoscroll),
21689                            window,
21690                            cx,
21691                            |s| {
21692                                s.select_ranges(ranges);
21693                            },
21694                        );
21695                        editor.nav_history = nav_history;
21696                    });
21697                }
21698            })
21699        });
21700    }
21701
21702    // For now, don't allow opening excerpts in buffers that aren't backed by
21703    // regular project files.
21704    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21705        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21706    }
21707
21708    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21709        let snapshot = self.buffer.read(cx).read(cx);
21710        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21711        Some(
21712            ranges
21713                .iter()
21714                .map(move |range| {
21715                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21716                })
21717                .collect(),
21718        )
21719    }
21720
21721    fn selection_replacement_ranges(
21722        &self,
21723        range: Range<OffsetUtf16>,
21724        cx: &mut App,
21725    ) -> Vec<Range<OffsetUtf16>> {
21726        let selections = self
21727            .selections
21728            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21729        let newest_selection = selections
21730            .iter()
21731            .max_by_key(|selection| selection.id)
21732            .unwrap();
21733        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21734        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21735        let snapshot = self.buffer.read(cx).read(cx);
21736        selections
21737            .into_iter()
21738            .map(|mut selection| {
21739                selection.start.0 =
21740                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21741                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21742                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21743                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21744            })
21745            .collect()
21746    }
21747
21748    fn report_editor_event(
21749        &self,
21750        reported_event: ReportEditorEvent,
21751        file_extension: Option<String>,
21752        cx: &App,
21753    ) {
21754        if cfg!(any(test, feature = "test-support")) {
21755            return;
21756        }
21757
21758        let Some(project) = &self.project else { return };
21759
21760        // If None, we are in a file without an extension
21761        let file = self
21762            .buffer
21763            .read(cx)
21764            .as_singleton()
21765            .and_then(|b| b.read(cx).file());
21766        let file_extension = file_extension.or(file
21767            .as_ref()
21768            .and_then(|file| Path::new(file.file_name(cx)).extension())
21769            .and_then(|e| e.to_str())
21770            .map(|a| a.to_string()));
21771
21772        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
21773            .map(|vim_mode| vim_mode.0)
21774            .unwrap_or(false);
21775
21776        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21777        let copilot_enabled = edit_predictions_provider
21778            == language::language_settings::EditPredictionProvider::Copilot;
21779        let copilot_enabled_for_language = self
21780            .buffer
21781            .read(cx)
21782            .language_settings(cx)
21783            .show_edit_predictions;
21784
21785        let project = project.read(cx);
21786        let event_type = reported_event.event_type();
21787
21788        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21789            telemetry::event!(
21790                event_type,
21791                type = if auto_saved {"autosave"} else {"manual"},
21792                file_extension,
21793                vim_mode,
21794                copilot_enabled,
21795                copilot_enabled_for_language,
21796                edit_predictions_provider,
21797                is_via_ssh = project.is_via_remote_server(),
21798            );
21799        } else {
21800            telemetry::event!(
21801                event_type,
21802                file_extension,
21803                vim_mode,
21804                copilot_enabled,
21805                copilot_enabled_for_language,
21806                edit_predictions_provider,
21807                is_via_ssh = project.is_via_remote_server(),
21808            );
21809        };
21810    }
21811
21812    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21813    /// with each line being an array of {text, highlight} objects.
21814    fn copy_highlight_json(
21815        &mut self,
21816        _: &CopyHighlightJson,
21817        window: &mut Window,
21818        cx: &mut Context<Self>,
21819    ) {
21820        #[derive(Serialize)]
21821        struct Chunk<'a> {
21822            text: String,
21823            highlight: Option<&'a str>,
21824        }
21825
21826        let snapshot = self.buffer.read(cx).snapshot(cx);
21827        let range = self
21828            .selected_text_range(false, window, cx)
21829            .and_then(|selection| {
21830                if selection.range.is_empty() {
21831                    None
21832                } else {
21833                    Some(
21834                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21835                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21836                    )
21837                }
21838            })
21839            .unwrap_or_else(|| 0..snapshot.len());
21840
21841        let chunks = snapshot.chunks(range, true);
21842        let mut lines = Vec::new();
21843        let mut line: VecDeque<Chunk> = VecDeque::new();
21844
21845        let Some(style) = self.style.as_ref() else {
21846            return;
21847        };
21848
21849        for chunk in chunks {
21850            let highlight = chunk
21851                .syntax_highlight_id
21852                .and_then(|id| id.name(&style.syntax));
21853            let mut chunk_lines = chunk.text.split('\n').peekable();
21854            while let Some(text) = chunk_lines.next() {
21855                let mut merged_with_last_token = false;
21856                if let Some(last_token) = line.back_mut()
21857                    && last_token.highlight == highlight
21858                {
21859                    last_token.text.push_str(text);
21860                    merged_with_last_token = true;
21861                }
21862
21863                if !merged_with_last_token {
21864                    line.push_back(Chunk {
21865                        text: text.into(),
21866                        highlight,
21867                    });
21868                }
21869
21870                if chunk_lines.peek().is_some() {
21871                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21872                        line.pop_front();
21873                    }
21874                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21875                        line.pop_back();
21876                    }
21877
21878                    lines.push(mem::take(&mut line));
21879                }
21880            }
21881        }
21882
21883        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21884            return;
21885        };
21886        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21887    }
21888
21889    pub fn open_context_menu(
21890        &mut self,
21891        _: &OpenContextMenu,
21892        window: &mut Window,
21893        cx: &mut Context<Self>,
21894    ) {
21895        self.request_autoscroll(Autoscroll::newest(), cx);
21896        let position = self
21897            .selections
21898            .newest_display(&self.display_snapshot(cx))
21899            .start;
21900        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21901    }
21902
21903    pub fn replay_insert_event(
21904        &mut self,
21905        text: &str,
21906        relative_utf16_range: Option<Range<isize>>,
21907        window: &mut Window,
21908        cx: &mut Context<Self>,
21909    ) {
21910        if !self.input_enabled {
21911            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21912            return;
21913        }
21914        if let Some(relative_utf16_range) = relative_utf16_range {
21915            let selections = self
21916                .selections
21917                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21918            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21919                let new_ranges = selections.into_iter().map(|range| {
21920                    let start = OffsetUtf16(
21921                        range
21922                            .head()
21923                            .0
21924                            .saturating_add_signed(relative_utf16_range.start),
21925                    );
21926                    let end = OffsetUtf16(
21927                        range
21928                            .head()
21929                            .0
21930                            .saturating_add_signed(relative_utf16_range.end),
21931                    );
21932                    start..end
21933                });
21934                s.select_ranges(new_ranges);
21935            });
21936        }
21937
21938        self.handle_input(text, window, cx);
21939    }
21940
21941    pub fn is_focused(&self, window: &Window) -> bool {
21942        self.focus_handle.is_focused(window)
21943    }
21944
21945    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21946        cx.emit(EditorEvent::Focused);
21947
21948        if let Some(descendant) = self
21949            .last_focused_descendant
21950            .take()
21951            .and_then(|descendant| descendant.upgrade())
21952        {
21953            window.focus(&descendant);
21954        } else {
21955            if let Some(blame) = self.blame.as_ref() {
21956                blame.update(cx, GitBlame::focus)
21957            }
21958
21959            self.blink_manager.update(cx, BlinkManager::enable);
21960            self.show_cursor_names(window, cx);
21961            self.buffer.update(cx, |buffer, cx| {
21962                buffer.finalize_last_transaction(cx);
21963                if self.leader_id.is_none() {
21964                    buffer.set_active_selections(
21965                        &self.selections.disjoint_anchors_arc(),
21966                        self.selections.line_mode(),
21967                        self.cursor_shape,
21968                        cx,
21969                    );
21970                }
21971            });
21972        }
21973    }
21974
21975    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21976        cx.emit(EditorEvent::FocusedIn)
21977    }
21978
21979    fn handle_focus_out(
21980        &mut self,
21981        event: FocusOutEvent,
21982        _window: &mut Window,
21983        cx: &mut Context<Self>,
21984    ) {
21985        if event.blurred != self.focus_handle {
21986            self.last_focused_descendant = Some(event.blurred);
21987        }
21988        self.selection_drag_state = SelectionDragState::None;
21989        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21990    }
21991
21992    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21993        self.blink_manager.update(cx, BlinkManager::disable);
21994        self.buffer
21995            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21996
21997        if let Some(blame) = self.blame.as_ref() {
21998            blame.update(cx, GitBlame::blur)
21999        }
22000        if !self.hover_state.focused(window, cx) {
22001            hide_hover(self, cx);
22002        }
22003        if !self
22004            .context_menu
22005            .borrow()
22006            .as_ref()
22007            .is_some_and(|context_menu| context_menu.focused(window, cx))
22008        {
22009            self.hide_context_menu(window, cx);
22010        }
22011        self.take_active_edit_prediction(cx);
22012        cx.emit(EditorEvent::Blurred);
22013        cx.notify();
22014    }
22015
22016    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22017        let mut pending: String = window
22018            .pending_input_keystrokes()
22019            .into_iter()
22020            .flatten()
22021            .filter_map(|keystroke| {
22022                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
22023                    keystroke.key_char.clone()
22024                } else {
22025                    None
22026                }
22027            })
22028            .collect();
22029
22030        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22031            pending = "".to_string();
22032        }
22033
22034        let existing_pending = self
22035            .text_highlights::<PendingInput>(cx)
22036            .map(|(_, ranges)| ranges.to_vec());
22037        if existing_pending.is_none() && pending.is_empty() {
22038            return;
22039        }
22040        let transaction =
22041            self.transact(window, cx, |this, window, cx| {
22042                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
22043                let edits = selections
22044                    .iter()
22045                    .map(|selection| (selection.end..selection.end, pending.clone()));
22046                this.edit(edits, cx);
22047                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22048                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22049                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22050                    }));
22051                });
22052                if let Some(existing_ranges) = existing_pending {
22053                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22054                    this.edit(edits, cx);
22055                }
22056            });
22057
22058        let snapshot = self.snapshot(window, cx);
22059        let ranges = self
22060            .selections
22061            .all::<usize>(&snapshot.display_snapshot)
22062            .into_iter()
22063            .map(|selection| {
22064                snapshot.buffer_snapshot().anchor_after(selection.end)
22065                    ..snapshot
22066                        .buffer_snapshot()
22067                        .anchor_before(selection.end + pending.len())
22068            })
22069            .collect();
22070
22071        if pending.is_empty() {
22072            self.clear_highlights::<PendingInput>(cx);
22073        } else {
22074            self.highlight_text::<PendingInput>(
22075                ranges,
22076                HighlightStyle {
22077                    underline: Some(UnderlineStyle {
22078                        thickness: px(1.),
22079                        color: None,
22080                        wavy: false,
22081                    }),
22082                    ..Default::default()
22083                },
22084                cx,
22085            );
22086        }
22087
22088        self.ime_transaction = self.ime_transaction.or(transaction);
22089        if let Some(transaction) = self.ime_transaction {
22090            self.buffer.update(cx, |buffer, cx| {
22091                buffer.group_until_transaction(transaction, cx);
22092            });
22093        }
22094
22095        if self.text_highlights::<PendingInput>(cx).is_none() {
22096            self.ime_transaction.take();
22097        }
22098    }
22099
22100    pub fn register_action_renderer(
22101        &mut self,
22102        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22103    ) -> Subscription {
22104        let id = self.next_editor_action_id.post_inc();
22105        self.editor_actions
22106            .borrow_mut()
22107            .insert(id, Box::new(listener));
22108
22109        let editor_actions = self.editor_actions.clone();
22110        Subscription::new(move || {
22111            editor_actions.borrow_mut().remove(&id);
22112        })
22113    }
22114
22115    pub fn register_action<A: Action>(
22116        &mut self,
22117        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22118    ) -> Subscription {
22119        let id = self.next_editor_action_id.post_inc();
22120        let listener = Arc::new(listener);
22121        self.editor_actions.borrow_mut().insert(
22122            id,
22123            Box::new(move |_, window, _| {
22124                let listener = listener.clone();
22125                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22126                    let action = action.downcast_ref().unwrap();
22127                    if phase == DispatchPhase::Bubble {
22128                        listener(action, window, cx)
22129                    }
22130                })
22131            }),
22132        );
22133
22134        let editor_actions = self.editor_actions.clone();
22135        Subscription::new(move || {
22136            editor_actions.borrow_mut().remove(&id);
22137        })
22138    }
22139
22140    pub fn file_header_size(&self) -> u32 {
22141        FILE_HEADER_HEIGHT
22142    }
22143
22144    pub fn restore(
22145        &mut self,
22146        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22147        window: &mut Window,
22148        cx: &mut Context<Self>,
22149    ) {
22150        let workspace = self.workspace();
22151        let project = self.project();
22152        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22153            let mut tasks = Vec::new();
22154            for (buffer_id, changes) in revert_changes {
22155                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22156                    buffer.update(cx, |buffer, cx| {
22157                        buffer.edit(
22158                            changes
22159                                .into_iter()
22160                                .map(|(range, text)| (range, text.to_string())),
22161                            None,
22162                            cx,
22163                        );
22164                    });
22165
22166                    if let Some(project) =
22167                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22168                    {
22169                        project.update(cx, |project, cx| {
22170                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22171                        })
22172                    }
22173                }
22174            }
22175            tasks
22176        });
22177        cx.spawn_in(window, async move |_, cx| {
22178            for (buffer, task) in save_tasks {
22179                let result = task.await;
22180                if result.is_err() {
22181                    let Some(path) = buffer
22182                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22183                        .ok()
22184                    else {
22185                        continue;
22186                    };
22187                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22188                        let Some(task) = cx
22189                            .update_window_entity(workspace, |workspace, window, cx| {
22190                                workspace
22191                                    .open_path_preview(path, None, false, false, false, window, cx)
22192                            })
22193                            .ok()
22194                        else {
22195                            continue;
22196                        };
22197                        task.await.log_err();
22198                    }
22199                }
22200            }
22201        })
22202        .detach();
22203        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22204            selections.refresh()
22205        });
22206    }
22207
22208    pub fn to_pixel_point(
22209        &self,
22210        source: multi_buffer::Anchor,
22211        editor_snapshot: &EditorSnapshot,
22212        window: &mut Window,
22213    ) -> Option<gpui::Point<Pixels>> {
22214        let source_point = source.to_display_point(editor_snapshot);
22215        self.display_to_pixel_point(source_point, editor_snapshot, window)
22216    }
22217
22218    pub fn display_to_pixel_point(
22219        &self,
22220        source: DisplayPoint,
22221        editor_snapshot: &EditorSnapshot,
22222        window: &mut Window,
22223    ) -> Option<gpui::Point<Pixels>> {
22224        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22225        let text_layout_details = self.text_layout_details(window);
22226        let scroll_top = text_layout_details
22227            .scroll_anchor
22228            .scroll_position(editor_snapshot)
22229            .y;
22230
22231        if source.row().as_f64() < scroll_top.floor() {
22232            return None;
22233        }
22234        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22235        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22236        Some(gpui::Point::new(source_x, source_y))
22237    }
22238
22239    pub fn has_visible_completions_menu(&self) -> bool {
22240        !self.edit_prediction_preview_is_active()
22241            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22242                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22243            })
22244    }
22245
22246    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22247        if self.mode.is_minimap() {
22248            return;
22249        }
22250        self.addons
22251            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22252    }
22253
22254    pub fn unregister_addon<T: Addon>(&mut self) {
22255        self.addons.remove(&std::any::TypeId::of::<T>());
22256    }
22257
22258    pub fn addon<T: Addon>(&self) -> Option<&T> {
22259        let type_id = std::any::TypeId::of::<T>();
22260        self.addons
22261            .get(&type_id)
22262            .and_then(|item| item.to_any().downcast_ref::<T>())
22263    }
22264
22265    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22266        let type_id = std::any::TypeId::of::<T>();
22267        self.addons
22268            .get_mut(&type_id)
22269            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22270    }
22271
22272    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22273        let text_layout_details = self.text_layout_details(window);
22274        let style = &text_layout_details.editor_style;
22275        let font_id = window.text_system().resolve_font(&style.text.font());
22276        let font_size = style.text.font_size.to_pixels(window.rem_size());
22277        let line_height = style.text.line_height_in_pixels(window.rem_size());
22278        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22279        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22280
22281        CharacterDimensions {
22282            em_width,
22283            em_advance,
22284            line_height,
22285        }
22286    }
22287
22288    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22289        self.load_diff_task.clone()
22290    }
22291
22292    fn read_metadata_from_db(
22293        &mut self,
22294        item_id: u64,
22295        workspace_id: WorkspaceId,
22296        window: &mut Window,
22297        cx: &mut Context<Editor>,
22298    ) {
22299        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22300            && !self.mode.is_minimap()
22301            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22302        {
22303            let buffer_snapshot = OnceCell::new();
22304
22305            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22306                && !folds.is_empty()
22307            {
22308                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22309                self.fold_ranges(
22310                    folds
22311                        .into_iter()
22312                        .map(|(start, end)| {
22313                            snapshot.clip_offset(start, Bias::Left)
22314                                ..snapshot.clip_offset(end, Bias::Right)
22315                        })
22316                        .collect(),
22317                    false,
22318                    window,
22319                    cx,
22320                );
22321            }
22322
22323            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22324                && !selections.is_empty()
22325            {
22326                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22327                // skip adding the initial selection to selection history
22328                self.selection_history.mode = SelectionHistoryMode::Skipping;
22329                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22330                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22331                        snapshot.clip_offset(start, Bias::Left)
22332                            ..snapshot.clip_offset(end, Bias::Right)
22333                    }));
22334                });
22335                self.selection_history.mode = SelectionHistoryMode::Normal;
22336            };
22337        }
22338
22339        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22340    }
22341
22342    fn update_lsp_data(
22343        &mut self,
22344        for_buffer: Option<BufferId>,
22345        window: &mut Window,
22346        cx: &mut Context<'_, Self>,
22347    ) {
22348        self.pull_diagnostics(for_buffer, window, cx);
22349        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22350    }
22351
22352    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22353        if self.ignore_lsp_data() {
22354            return;
22355        }
22356        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22357            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22358        }
22359    }
22360
22361    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22362        if self.ignore_lsp_data() {
22363            return;
22364        }
22365
22366        if !self.registered_buffers.contains_key(&buffer_id)
22367            && let Some(project) = self.project.as_ref()
22368        {
22369            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22370                project.update(cx, |project, cx| {
22371                    self.registered_buffers.insert(
22372                        buffer_id,
22373                        project.register_buffer_with_language_servers(&buffer, cx),
22374                    );
22375                });
22376            } else {
22377                self.registered_buffers.remove(&buffer_id);
22378            }
22379        }
22380    }
22381
22382    fn ignore_lsp_data(&self) -> bool {
22383        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22384        // skip any LSP updates for it.
22385        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22386    }
22387}
22388
22389fn edit_for_markdown_paste<'a>(
22390    buffer: &MultiBufferSnapshot,
22391    range: Range<usize>,
22392    to_insert: &'a str,
22393    url: Option<url::Url>,
22394) -> (Range<usize>, Cow<'a, str>) {
22395    if url.is_none() {
22396        return (range, Cow::Borrowed(to_insert));
22397    };
22398
22399    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22400
22401    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22402        Cow::Borrowed(to_insert)
22403    } else {
22404        Cow::Owned(format!("[{old_text}]({to_insert})"))
22405    };
22406    (range, new_text)
22407}
22408
22409fn process_completion_for_edit(
22410    completion: &Completion,
22411    intent: CompletionIntent,
22412    buffer: &Entity<Buffer>,
22413    cursor_position: &text::Anchor,
22414    cx: &mut Context<Editor>,
22415) -> CompletionEdit {
22416    let buffer = buffer.read(cx);
22417    let buffer_snapshot = buffer.snapshot();
22418    let (snippet, new_text) = if completion.is_snippet() {
22419        let mut snippet_source = completion.new_text.clone();
22420        // Workaround for typescript language server issues so that methods don't expand within
22421        // strings and functions with type expressions. The previous point is used because the query
22422        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22423        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22424        let previous_point = if previous_point.column > 0 {
22425            cursor_position.to_previous_offset(&buffer_snapshot)
22426        } else {
22427            cursor_position.to_offset(&buffer_snapshot)
22428        };
22429        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22430            && scope.prefers_label_for_snippet_in_completion()
22431            && let Some(label) = completion.label()
22432            && matches!(
22433                completion.kind(),
22434                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22435            )
22436        {
22437            snippet_source = label;
22438        }
22439        match Snippet::parse(&snippet_source).log_err() {
22440            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22441            None => (None, completion.new_text.clone()),
22442        }
22443    } else {
22444        (None, completion.new_text.clone())
22445    };
22446
22447    let mut range_to_replace = {
22448        let replace_range = &completion.replace_range;
22449        if let CompletionSource::Lsp {
22450            insert_range: Some(insert_range),
22451            ..
22452        } = &completion.source
22453        {
22454            debug_assert_eq!(
22455                insert_range.start, replace_range.start,
22456                "insert_range and replace_range should start at the same position"
22457            );
22458            debug_assert!(
22459                insert_range
22460                    .start
22461                    .cmp(cursor_position, &buffer_snapshot)
22462                    .is_le(),
22463                "insert_range should start before or at cursor position"
22464            );
22465            debug_assert!(
22466                replace_range
22467                    .start
22468                    .cmp(cursor_position, &buffer_snapshot)
22469                    .is_le(),
22470                "replace_range should start before or at cursor position"
22471            );
22472
22473            let should_replace = match intent {
22474                CompletionIntent::CompleteWithInsert => false,
22475                CompletionIntent::CompleteWithReplace => true,
22476                CompletionIntent::Complete | CompletionIntent::Compose => {
22477                    let insert_mode =
22478                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22479                            .completions
22480                            .lsp_insert_mode;
22481                    match insert_mode {
22482                        LspInsertMode::Insert => false,
22483                        LspInsertMode::Replace => true,
22484                        LspInsertMode::ReplaceSubsequence => {
22485                            let mut text_to_replace = buffer.chars_for_range(
22486                                buffer.anchor_before(replace_range.start)
22487                                    ..buffer.anchor_after(replace_range.end),
22488                            );
22489                            let mut current_needle = text_to_replace.next();
22490                            for haystack_ch in completion.label.text.chars() {
22491                                if let Some(needle_ch) = current_needle
22492                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22493                                {
22494                                    current_needle = text_to_replace.next();
22495                                }
22496                            }
22497                            current_needle.is_none()
22498                        }
22499                        LspInsertMode::ReplaceSuffix => {
22500                            if replace_range
22501                                .end
22502                                .cmp(cursor_position, &buffer_snapshot)
22503                                .is_gt()
22504                            {
22505                                let range_after_cursor = *cursor_position..replace_range.end;
22506                                let text_after_cursor = buffer
22507                                    .text_for_range(
22508                                        buffer.anchor_before(range_after_cursor.start)
22509                                            ..buffer.anchor_after(range_after_cursor.end),
22510                                    )
22511                                    .collect::<String>()
22512                                    .to_ascii_lowercase();
22513                                completion
22514                                    .label
22515                                    .text
22516                                    .to_ascii_lowercase()
22517                                    .ends_with(&text_after_cursor)
22518                            } else {
22519                                true
22520                            }
22521                        }
22522                    }
22523                }
22524            };
22525
22526            if should_replace {
22527                replace_range.clone()
22528            } else {
22529                insert_range.clone()
22530            }
22531        } else {
22532            replace_range.clone()
22533        }
22534    };
22535
22536    if range_to_replace
22537        .end
22538        .cmp(cursor_position, &buffer_snapshot)
22539        .is_lt()
22540    {
22541        range_to_replace.end = *cursor_position;
22542    }
22543
22544    CompletionEdit {
22545        new_text,
22546        replace_range: range_to_replace.to_offset(buffer),
22547        snippet,
22548    }
22549}
22550
22551struct CompletionEdit {
22552    new_text: String,
22553    replace_range: Range<usize>,
22554    snippet: Option<Snippet>,
22555}
22556
22557fn insert_extra_newline_brackets(
22558    buffer: &MultiBufferSnapshot,
22559    range: Range<usize>,
22560    language: &language::LanguageScope,
22561) -> bool {
22562    let leading_whitespace_len = buffer
22563        .reversed_chars_at(range.start)
22564        .take_while(|c| c.is_whitespace() && *c != '\n')
22565        .map(|c| c.len_utf8())
22566        .sum::<usize>();
22567    let trailing_whitespace_len = buffer
22568        .chars_at(range.end)
22569        .take_while(|c| c.is_whitespace() && *c != '\n')
22570        .map(|c| c.len_utf8())
22571        .sum::<usize>();
22572    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22573
22574    language.brackets().any(|(pair, enabled)| {
22575        let pair_start = pair.start.trim_end();
22576        let pair_end = pair.end.trim_start();
22577
22578        enabled
22579            && pair.newline
22580            && buffer.contains_str_at(range.end, pair_end)
22581            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22582    })
22583}
22584
22585fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22586    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22587        [(buffer, range, _)] => (*buffer, range.clone()),
22588        _ => return false,
22589    };
22590    let pair = {
22591        let mut result: Option<BracketMatch> = None;
22592
22593        for pair in buffer
22594            .all_bracket_ranges(range.clone())
22595            .filter(move |pair| {
22596                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22597            })
22598        {
22599            let len = pair.close_range.end - pair.open_range.start;
22600
22601            if let Some(existing) = &result {
22602                let existing_len = existing.close_range.end - existing.open_range.start;
22603                if len > existing_len {
22604                    continue;
22605                }
22606            }
22607
22608            result = Some(pair);
22609        }
22610
22611        result
22612    };
22613    let Some(pair) = pair else {
22614        return false;
22615    };
22616    pair.newline_only
22617        && buffer
22618            .chars_for_range(pair.open_range.end..range.start)
22619            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22620            .all(|c| c.is_whitespace() && c != '\n')
22621}
22622
22623fn update_uncommitted_diff_for_buffer(
22624    editor: Entity<Editor>,
22625    project: &Entity<Project>,
22626    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22627    buffer: Entity<MultiBuffer>,
22628    cx: &mut App,
22629) -> Task<()> {
22630    let mut tasks = Vec::new();
22631    project.update(cx, |project, cx| {
22632        for buffer in buffers {
22633            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22634                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22635            }
22636        }
22637    });
22638    cx.spawn(async move |cx| {
22639        let diffs = future::join_all(tasks).await;
22640        if editor
22641            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22642            .unwrap_or(false)
22643        {
22644            return;
22645        }
22646
22647        buffer
22648            .update(cx, |buffer, cx| {
22649                for diff in diffs.into_iter().flatten() {
22650                    buffer.add_diff(diff, cx);
22651                }
22652            })
22653            .ok();
22654    })
22655}
22656
22657fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22658    let tab_size = tab_size.get() as usize;
22659    let mut width = offset;
22660
22661    for ch in text.chars() {
22662        width += if ch == '\t' {
22663            tab_size - (width % tab_size)
22664        } else {
22665            1
22666        };
22667    }
22668
22669    width - offset
22670}
22671
22672#[cfg(test)]
22673mod tests {
22674    use super::*;
22675
22676    #[test]
22677    fn test_string_size_with_expanded_tabs() {
22678        let nz = |val| NonZeroU32::new(val).unwrap();
22679        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22680        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22681        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22682        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22683        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22684        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22685        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22686        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22687    }
22688}
22689
22690/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22691struct WordBreakingTokenizer<'a> {
22692    input: &'a str,
22693}
22694
22695impl<'a> WordBreakingTokenizer<'a> {
22696    fn new(input: &'a str) -> Self {
22697        Self { input }
22698    }
22699}
22700
22701fn is_char_ideographic(ch: char) -> bool {
22702    use unicode_script::Script::*;
22703    use unicode_script::UnicodeScript;
22704    matches!(ch.script(), Han | Tangut | Yi)
22705}
22706
22707fn is_grapheme_ideographic(text: &str) -> bool {
22708    text.chars().any(is_char_ideographic)
22709}
22710
22711fn is_grapheme_whitespace(text: &str) -> bool {
22712    text.chars().any(|x| x.is_whitespace())
22713}
22714
22715fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22716    text.chars()
22717        .next()
22718        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22719}
22720
22721#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22722enum WordBreakToken<'a> {
22723    Word { token: &'a str, grapheme_len: usize },
22724    InlineWhitespace { token: &'a str, grapheme_len: usize },
22725    Newline,
22726}
22727
22728impl<'a> Iterator for WordBreakingTokenizer<'a> {
22729    /// Yields a span, the count of graphemes in the token, and whether it was
22730    /// whitespace. Note that it also breaks at word boundaries.
22731    type Item = WordBreakToken<'a>;
22732
22733    fn next(&mut self) -> Option<Self::Item> {
22734        use unicode_segmentation::UnicodeSegmentation;
22735        if self.input.is_empty() {
22736            return None;
22737        }
22738
22739        let mut iter = self.input.graphemes(true).peekable();
22740        let mut offset = 0;
22741        let mut grapheme_len = 0;
22742        if let Some(first_grapheme) = iter.next() {
22743            let is_newline = first_grapheme == "\n";
22744            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22745            offset += first_grapheme.len();
22746            grapheme_len += 1;
22747            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22748                if let Some(grapheme) = iter.peek().copied()
22749                    && should_stay_with_preceding_ideograph(grapheme)
22750                {
22751                    offset += grapheme.len();
22752                    grapheme_len += 1;
22753                }
22754            } else {
22755                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22756                let mut next_word_bound = words.peek().copied();
22757                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22758                    next_word_bound = words.next();
22759                }
22760                while let Some(grapheme) = iter.peek().copied() {
22761                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22762                        break;
22763                    };
22764                    if is_grapheme_whitespace(grapheme) != is_whitespace
22765                        || (grapheme == "\n") != is_newline
22766                    {
22767                        break;
22768                    };
22769                    offset += grapheme.len();
22770                    grapheme_len += 1;
22771                    iter.next();
22772                }
22773            }
22774            let token = &self.input[..offset];
22775            self.input = &self.input[offset..];
22776            if token == "\n" {
22777                Some(WordBreakToken::Newline)
22778            } else if is_whitespace {
22779                Some(WordBreakToken::InlineWhitespace {
22780                    token,
22781                    grapheme_len,
22782                })
22783            } else {
22784                Some(WordBreakToken::Word {
22785                    token,
22786                    grapheme_len,
22787                })
22788            }
22789        } else {
22790            None
22791        }
22792    }
22793}
22794
22795#[test]
22796fn test_word_breaking_tokenizer() {
22797    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22798        ("", &[]),
22799        ("  ", &[whitespace("  ", 2)]),
22800        ("Ʒ", &[word("Ʒ", 1)]),
22801        ("Ǽ", &[word("Ǽ", 1)]),
22802        ("", &[word("", 1)]),
22803        ("⋑⋑", &[word("⋑⋑", 2)]),
22804        (
22805            "原理,进而",
22806            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22807        ),
22808        (
22809            "hello world",
22810            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22811        ),
22812        (
22813            "hello, world",
22814            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22815        ),
22816        (
22817            "  hello world",
22818            &[
22819                whitespace("  ", 2),
22820                word("hello", 5),
22821                whitespace(" ", 1),
22822                word("world", 5),
22823            ],
22824        ),
22825        (
22826            "这是什么 \n 钢笔",
22827            &[
22828                word("", 1),
22829                word("", 1),
22830                word("", 1),
22831                word("", 1),
22832                whitespace(" ", 1),
22833                newline(),
22834                whitespace(" ", 1),
22835                word("", 1),
22836                word("", 1),
22837            ],
22838        ),
22839        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22840    ];
22841
22842    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22843        WordBreakToken::Word {
22844            token,
22845            grapheme_len,
22846        }
22847    }
22848
22849    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22850        WordBreakToken::InlineWhitespace {
22851            token,
22852            grapheme_len,
22853        }
22854    }
22855
22856    fn newline() -> WordBreakToken<'static> {
22857        WordBreakToken::Newline
22858    }
22859
22860    for (input, result) in tests {
22861        assert_eq!(
22862            WordBreakingTokenizer::new(input)
22863                .collect::<Vec<_>>()
22864                .as_slice(),
22865            *result,
22866        );
22867    }
22868}
22869
22870fn wrap_with_prefix(
22871    first_line_prefix: String,
22872    subsequent_lines_prefix: String,
22873    unwrapped_text: String,
22874    wrap_column: usize,
22875    tab_size: NonZeroU32,
22876    preserve_existing_whitespace: bool,
22877) -> String {
22878    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22879    let subsequent_lines_prefix_len =
22880        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22881    let mut wrapped_text = String::new();
22882    let mut current_line = first_line_prefix;
22883    let mut is_first_line = true;
22884
22885    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22886    let mut current_line_len = first_line_prefix_len;
22887    let mut in_whitespace = false;
22888    for token in tokenizer {
22889        let have_preceding_whitespace = in_whitespace;
22890        match token {
22891            WordBreakToken::Word {
22892                token,
22893                grapheme_len,
22894            } => {
22895                in_whitespace = false;
22896                let current_prefix_len = if is_first_line {
22897                    first_line_prefix_len
22898                } else {
22899                    subsequent_lines_prefix_len
22900                };
22901                if current_line_len + grapheme_len > wrap_column
22902                    && current_line_len != current_prefix_len
22903                {
22904                    wrapped_text.push_str(current_line.trim_end());
22905                    wrapped_text.push('\n');
22906                    is_first_line = false;
22907                    current_line = subsequent_lines_prefix.clone();
22908                    current_line_len = subsequent_lines_prefix_len;
22909                }
22910                current_line.push_str(token);
22911                current_line_len += grapheme_len;
22912            }
22913            WordBreakToken::InlineWhitespace {
22914                mut token,
22915                mut grapheme_len,
22916            } => {
22917                in_whitespace = true;
22918                if have_preceding_whitespace && !preserve_existing_whitespace {
22919                    continue;
22920                }
22921                if !preserve_existing_whitespace {
22922                    // Keep a single whitespace grapheme as-is
22923                    if let Some(first) =
22924                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22925                    {
22926                        token = first;
22927                    } else {
22928                        token = " ";
22929                    }
22930                    grapheme_len = 1;
22931                }
22932                let current_prefix_len = if is_first_line {
22933                    first_line_prefix_len
22934                } else {
22935                    subsequent_lines_prefix_len
22936                };
22937                if current_line_len + grapheme_len > wrap_column {
22938                    wrapped_text.push_str(current_line.trim_end());
22939                    wrapped_text.push('\n');
22940                    is_first_line = false;
22941                    current_line = subsequent_lines_prefix.clone();
22942                    current_line_len = subsequent_lines_prefix_len;
22943                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22944                    current_line.push_str(token);
22945                    current_line_len += grapheme_len;
22946                }
22947            }
22948            WordBreakToken::Newline => {
22949                in_whitespace = true;
22950                let current_prefix_len = if is_first_line {
22951                    first_line_prefix_len
22952                } else {
22953                    subsequent_lines_prefix_len
22954                };
22955                if preserve_existing_whitespace {
22956                    wrapped_text.push_str(current_line.trim_end());
22957                    wrapped_text.push('\n');
22958                    is_first_line = false;
22959                    current_line = subsequent_lines_prefix.clone();
22960                    current_line_len = subsequent_lines_prefix_len;
22961                } else if have_preceding_whitespace {
22962                    continue;
22963                } else if current_line_len + 1 > wrap_column
22964                    && current_line_len != current_prefix_len
22965                {
22966                    wrapped_text.push_str(current_line.trim_end());
22967                    wrapped_text.push('\n');
22968                    is_first_line = false;
22969                    current_line = subsequent_lines_prefix.clone();
22970                    current_line_len = subsequent_lines_prefix_len;
22971                } else if current_line_len != current_prefix_len {
22972                    current_line.push(' ');
22973                    current_line_len += 1;
22974                }
22975            }
22976        }
22977    }
22978
22979    if !current_line.is_empty() {
22980        wrapped_text.push_str(&current_line);
22981    }
22982    wrapped_text
22983}
22984
22985#[test]
22986fn test_wrap_with_prefix() {
22987    assert_eq!(
22988        wrap_with_prefix(
22989            "# ".to_string(),
22990            "# ".to_string(),
22991            "abcdefg".to_string(),
22992            4,
22993            NonZeroU32::new(4).unwrap(),
22994            false,
22995        ),
22996        "# abcdefg"
22997    );
22998    assert_eq!(
22999        wrap_with_prefix(
23000            "".to_string(),
23001            "".to_string(),
23002            "\thello world".to_string(),
23003            8,
23004            NonZeroU32::new(4).unwrap(),
23005            false,
23006        ),
23007        "hello\nworld"
23008    );
23009    assert_eq!(
23010        wrap_with_prefix(
23011            "// ".to_string(),
23012            "// ".to_string(),
23013            "xx \nyy zz aa bb cc".to_string(),
23014            12,
23015            NonZeroU32::new(4).unwrap(),
23016            false,
23017        ),
23018        "// xx yy zz\n// aa bb cc"
23019    );
23020    assert_eq!(
23021        wrap_with_prefix(
23022            String::new(),
23023            String::new(),
23024            "这是什么 \n 钢笔".to_string(),
23025            3,
23026            NonZeroU32::new(4).unwrap(),
23027            false,
23028        ),
23029        "这是什\n么 钢\n"
23030    );
23031    assert_eq!(
23032        wrap_with_prefix(
23033            String::new(),
23034            String::new(),
23035            format!("foo{}bar", '\u{2009}'), // thin space
23036            80,
23037            NonZeroU32::new(4).unwrap(),
23038            false,
23039        ),
23040        format!("foo{}bar", '\u{2009}')
23041    );
23042}
23043
23044pub trait CollaborationHub {
23045    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23046    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23047    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23048}
23049
23050impl CollaborationHub for Entity<Project> {
23051    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23052        self.read(cx).collaborators()
23053    }
23054
23055    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23056        self.read(cx).user_store().read(cx).participant_indices()
23057    }
23058
23059    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23060        let this = self.read(cx);
23061        let user_ids = this.collaborators().values().map(|c| c.user_id);
23062        this.user_store().read(cx).participant_names(user_ids, cx)
23063    }
23064}
23065
23066pub trait SemanticsProvider {
23067    fn hover(
23068        &self,
23069        buffer: &Entity<Buffer>,
23070        position: text::Anchor,
23071        cx: &mut App,
23072    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23073
23074    fn inline_values(
23075        &self,
23076        buffer_handle: Entity<Buffer>,
23077        range: Range<text::Anchor>,
23078        cx: &mut App,
23079    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23080
23081    fn applicable_inlay_chunks(
23082        &self,
23083        buffer: &Entity<Buffer>,
23084        ranges: &[Range<text::Anchor>],
23085        cx: &mut App,
23086    ) -> Vec<Range<BufferRow>>;
23087
23088    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23089
23090    fn inlay_hints(
23091        &self,
23092        invalidate: InvalidationStrategy,
23093        buffer: Entity<Buffer>,
23094        ranges: Vec<Range<text::Anchor>>,
23095        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23096        cx: &mut App,
23097    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23098
23099    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23100
23101    fn document_highlights(
23102        &self,
23103        buffer: &Entity<Buffer>,
23104        position: text::Anchor,
23105        cx: &mut App,
23106    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23107
23108    fn definitions(
23109        &self,
23110        buffer: &Entity<Buffer>,
23111        position: text::Anchor,
23112        kind: GotoDefinitionKind,
23113        cx: &mut App,
23114    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23115
23116    fn range_for_rename(
23117        &self,
23118        buffer: &Entity<Buffer>,
23119        position: text::Anchor,
23120        cx: &mut App,
23121    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23122
23123    fn perform_rename(
23124        &self,
23125        buffer: &Entity<Buffer>,
23126        position: text::Anchor,
23127        new_name: String,
23128        cx: &mut App,
23129    ) -> Option<Task<Result<ProjectTransaction>>>;
23130}
23131
23132pub trait CompletionProvider {
23133    fn completions(
23134        &self,
23135        excerpt_id: ExcerptId,
23136        buffer: &Entity<Buffer>,
23137        buffer_position: text::Anchor,
23138        trigger: CompletionContext,
23139        window: &mut Window,
23140        cx: &mut Context<Editor>,
23141    ) -> Task<Result<Vec<CompletionResponse>>>;
23142
23143    fn resolve_completions(
23144        &self,
23145        _buffer: Entity<Buffer>,
23146        _completion_indices: Vec<usize>,
23147        _completions: Rc<RefCell<Box<[Completion]>>>,
23148        _cx: &mut Context<Editor>,
23149    ) -> Task<Result<bool>> {
23150        Task::ready(Ok(false))
23151    }
23152
23153    fn apply_additional_edits_for_completion(
23154        &self,
23155        _buffer: Entity<Buffer>,
23156        _completions: Rc<RefCell<Box<[Completion]>>>,
23157        _completion_index: usize,
23158        _push_to_history: bool,
23159        _cx: &mut Context<Editor>,
23160    ) -> Task<Result<Option<language::Transaction>>> {
23161        Task::ready(Ok(None))
23162    }
23163
23164    fn is_completion_trigger(
23165        &self,
23166        buffer: &Entity<Buffer>,
23167        position: language::Anchor,
23168        text: &str,
23169        trigger_in_words: bool,
23170        menu_is_open: bool,
23171        cx: &mut Context<Editor>,
23172    ) -> bool;
23173
23174    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23175
23176    fn sort_completions(&self) -> bool {
23177        true
23178    }
23179
23180    fn filter_completions(&self) -> bool {
23181        true
23182    }
23183
23184    fn show_snippets(&self) -> bool {
23185        false
23186    }
23187}
23188
23189pub trait CodeActionProvider {
23190    fn id(&self) -> Arc<str>;
23191
23192    fn code_actions(
23193        &self,
23194        buffer: &Entity<Buffer>,
23195        range: Range<text::Anchor>,
23196        window: &mut Window,
23197        cx: &mut App,
23198    ) -> Task<Result<Vec<CodeAction>>>;
23199
23200    fn apply_code_action(
23201        &self,
23202        buffer_handle: Entity<Buffer>,
23203        action: CodeAction,
23204        excerpt_id: ExcerptId,
23205        push_to_history: bool,
23206        window: &mut Window,
23207        cx: &mut App,
23208    ) -> Task<Result<ProjectTransaction>>;
23209}
23210
23211impl CodeActionProvider for Entity<Project> {
23212    fn id(&self) -> Arc<str> {
23213        "project".into()
23214    }
23215
23216    fn code_actions(
23217        &self,
23218        buffer: &Entity<Buffer>,
23219        range: Range<text::Anchor>,
23220        _window: &mut Window,
23221        cx: &mut App,
23222    ) -> Task<Result<Vec<CodeAction>>> {
23223        self.update(cx, |project, cx| {
23224            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23225            let code_actions = project.code_actions(buffer, range, None, cx);
23226            cx.background_spawn(async move {
23227                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23228                Ok(code_lens_actions
23229                    .context("code lens fetch")?
23230                    .into_iter()
23231                    .flatten()
23232                    .chain(
23233                        code_actions
23234                            .context("code action fetch")?
23235                            .into_iter()
23236                            .flatten(),
23237                    )
23238                    .collect())
23239            })
23240        })
23241    }
23242
23243    fn apply_code_action(
23244        &self,
23245        buffer_handle: Entity<Buffer>,
23246        action: CodeAction,
23247        _excerpt_id: ExcerptId,
23248        push_to_history: bool,
23249        _window: &mut Window,
23250        cx: &mut App,
23251    ) -> Task<Result<ProjectTransaction>> {
23252        self.update(cx, |project, cx| {
23253            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23254        })
23255    }
23256}
23257
23258fn snippet_completions(
23259    project: &Project,
23260    buffer: &Entity<Buffer>,
23261    buffer_anchor: text::Anchor,
23262    classifier: CharClassifier,
23263    cx: &mut App,
23264) -> Task<Result<CompletionResponse>> {
23265    let languages = buffer.read(cx).languages_at(buffer_anchor);
23266    let snippet_store = project.snippets().read(cx);
23267
23268    let scopes: Vec<_> = languages
23269        .iter()
23270        .filter_map(|language| {
23271            let language_name = language.lsp_id();
23272            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23273
23274            if snippets.is_empty() {
23275                None
23276            } else {
23277                Some((language.default_scope(), snippets))
23278            }
23279        })
23280        .collect();
23281
23282    if scopes.is_empty() {
23283        return Task::ready(Ok(CompletionResponse {
23284            completions: vec![],
23285            display_options: CompletionDisplayOptions::default(),
23286            is_incomplete: false,
23287        }));
23288    }
23289
23290    let snapshot = buffer.read(cx).text_snapshot();
23291    let executor = cx.background_executor().clone();
23292
23293    cx.background_spawn(async move {
23294        let is_word_char = |c| classifier.is_word(c);
23295
23296        let mut is_incomplete = false;
23297        let mut completions: Vec<Completion> = Vec::new();
23298
23299        const MAX_PREFIX_LEN: usize = 128;
23300        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23301        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23302        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23303
23304        let max_buffer_window: String = snapshot
23305            .text_for_range(window_start..buffer_offset)
23306            .collect();
23307
23308        if max_buffer_window.is_empty() {
23309            return Ok(CompletionResponse {
23310                completions: vec![],
23311                display_options: CompletionDisplayOptions::default(),
23312                is_incomplete: true,
23313            });
23314        }
23315
23316        for (_scope, snippets) in scopes.into_iter() {
23317            // Sort snippets by word count to match longer snippet prefixes first.
23318            let mut sorted_snippet_candidates = snippets
23319                .iter()
23320                .enumerate()
23321                .flat_map(|(snippet_ix, snippet)| {
23322                    snippet
23323                        .prefix
23324                        .iter()
23325                        .enumerate()
23326                        .map(move |(prefix_ix, prefix)| {
23327                            let word_count =
23328                                snippet_candidate_suffixes(prefix, is_word_char).count();
23329                            ((snippet_ix, prefix_ix), prefix, word_count)
23330                        })
23331                })
23332                .collect_vec();
23333            sorted_snippet_candidates
23334                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23335
23336            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23337
23338            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23339                .take(
23340                    sorted_snippet_candidates
23341                        .first()
23342                        .map(|(_, _, word_count)| *word_count)
23343                        .unwrap_or_default(),
23344                )
23345                .collect_vec();
23346
23347            const MAX_RESULTS: usize = 100;
23348            // Each match also remembers how many characters from the buffer it consumed
23349            let mut matches: Vec<(StringMatch, usize)> = vec![];
23350
23351            let mut snippet_list_cutoff_index = 0;
23352            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23353                let word_count = buffer_index + 1;
23354                // Increase `snippet_list_cutoff_index` until we have all of the
23355                // snippets with sufficiently many words.
23356                while sorted_snippet_candidates
23357                    .get(snippet_list_cutoff_index)
23358                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23359                        *snippet_word_count >= word_count
23360                    })
23361                {
23362                    snippet_list_cutoff_index += 1;
23363                }
23364
23365                // Take only the candidates with at least `word_count` many words
23366                let snippet_candidates_at_word_len =
23367                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23368
23369                let candidates = snippet_candidates_at_word_len
23370                    .iter()
23371                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23372                    .enumerate() // index in `sorted_snippet_candidates`
23373                    // First char must match
23374                    .filter(|(_ix, prefix)| {
23375                        itertools::equal(
23376                            prefix
23377                                .chars()
23378                                .next()
23379                                .into_iter()
23380                                .flat_map(|c| c.to_lowercase()),
23381                            buffer_window
23382                                .chars()
23383                                .next()
23384                                .into_iter()
23385                                .flat_map(|c| c.to_lowercase()),
23386                        )
23387                    })
23388                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23389                    .collect::<Vec<StringMatchCandidate>>();
23390
23391                matches.extend(
23392                    fuzzy::match_strings(
23393                        &candidates,
23394                        &buffer_window,
23395                        buffer_window.chars().any(|c| c.is_uppercase()),
23396                        true,
23397                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23398                        &Default::default(),
23399                        executor.clone(),
23400                    )
23401                    .await
23402                    .into_iter()
23403                    .map(|string_match| (string_match, buffer_window.len())),
23404                );
23405
23406                if matches.len() >= MAX_RESULTS {
23407                    break;
23408                }
23409            }
23410
23411            let to_lsp = |point: &text::Anchor| {
23412                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23413                point_to_lsp(end)
23414            };
23415            let lsp_end = to_lsp(&buffer_anchor);
23416
23417            if matches.len() >= MAX_RESULTS {
23418                is_incomplete = true;
23419            }
23420
23421            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23422                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23423                    sorted_snippet_candidates[string_match.candidate_id];
23424                let snippet = &snippets[snippet_index];
23425                let start = buffer_offset - buffer_window_len;
23426                let start = snapshot.anchor_before(start);
23427                let range = start..buffer_anchor;
23428                let lsp_start = to_lsp(&start);
23429                let lsp_range = lsp::Range {
23430                    start: lsp_start,
23431                    end: lsp_end,
23432                };
23433                Completion {
23434                    replace_range: range,
23435                    new_text: snippet.body.clone(),
23436                    source: CompletionSource::Lsp {
23437                        insert_range: None,
23438                        server_id: LanguageServerId(usize::MAX),
23439                        resolved: true,
23440                        lsp_completion: Box::new(lsp::CompletionItem {
23441                            label: snippet.prefix.first().unwrap().clone(),
23442                            kind: Some(CompletionItemKind::SNIPPET),
23443                            label_details: snippet.description.as_ref().map(|description| {
23444                                lsp::CompletionItemLabelDetails {
23445                                    detail: Some(description.clone()),
23446                                    description: None,
23447                                }
23448                            }),
23449                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23450                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23451                                lsp::InsertReplaceEdit {
23452                                    new_text: snippet.body.clone(),
23453                                    insert: lsp_range,
23454                                    replace: lsp_range,
23455                                },
23456                            )),
23457                            filter_text: Some(snippet.body.clone()),
23458                            sort_text: Some(char::MAX.to_string()),
23459                            ..lsp::CompletionItem::default()
23460                        }),
23461                        lsp_defaults: None,
23462                    },
23463                    label: CodeLabel {
23464                        text: matching_prefix.clone(),
23465                        runs: Vec::new(),
23466                        filter_range: 0..matching_prefix.len(),
23467                    },
23468                    icon_path: None,
23469                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23470                        single_line: snippet.name.clone().into(),
23471                        plain_text: snippet
23472                            .description
23473                            .clone()
23474                            .map(|description| description.into()),
23475                    }),
23476                    insert_text_mode: None,
23477                    confirm: None,
23478                    match_start: Some(start),
23479                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23480                }
23481            }));
23482        }
23483
23484        Ok(CompletionResponse {
23485            completions,
23486            display_options: CompletionDisplayOptions::default(),
23487            is_incomplete,
23488        })
23489    })
23490}
23491
23492impl CompletionProvider for Entity<Project> {
23493    fn completions(
23494        &self,
23495        _excerpt_id: ExcerptId,
23496        buffer: &Entity<Buffer>,
23497        buffer_position: text::Anchor,
23498        options: CompletionContext,
23499        _window: &mut Window,
23500        cx: &mut Context<Editor>,
23501    ) -> Task<Result<Vec<CompletionResponse>>> {
23502        self.update(cx, |project, cx| {
23503            let task = project.completions(buffer, buffer_position, options, cx);
23504            cx.background_spawn(task)
23505        })
23506    }
23507
23508    fn resolve_completions(
23509        &self,
23510        buffer: Entity<Buffer>,
23511        completion_indices: Vec<usize>,
23512        completions: Rc<RefCell<Box<[Completion]>>>,
23513        cx: &mut Context<Editor>,
23514    ) -> Task<Result<bool>> {
23515        self.update(cx, |project, cx| {
23516            project.lsp_store().update(cx, |lsp_store, cx| {
23517                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23518            })
23519        })
23520    }
23521
23522    fn apply_additional_edits_for_completion(
23523        &self,
23524        buffer: Entity<Buffer>,
23525        completions: Rc<RefCell<Box<[Completion]>>>,
23526        completion_index: usize,
23527        push_to_history: bool,
23528        cx: &mut Context<Editor>,
23529    ) -> Task<Result<Option<language::Transaction>>> {
23530        self.update(cx, |project, cx| {
23531            project.lsp_store().update(cx, |lsp_store, cx| {
23532                lsp_store.apply_additional_edits_for_completion(
23533                    buffer,
23534                    completions,
23535                    completion_index,
23536                    push_to_history,
23537                    cx,
23538                )
23539            })
23540        })
23541    }
23542
23543    fn is_completion_trigger(
23544        &self,
23545        buffer: &Entity<Buffer>,
23546        position: language::Anchor,
23547        text: &str,
23548        trigger_in_words: bool,
23549        menu_is_open: bool,
23550        cx: &mut Context<Editor>,
23551    ) -> bool {
23552        let mut chars = text.chars();
23553        let char = if let Some(char) = chars.next() {
23554            char
23555        } else {
23556            return false;
23557        };
23558        if chars.next().is_some() {
23559            return false;
23560        }
23561
23562        let buffer = buffer.read(cx);
23563        let snapshot = buffer.snapshot();
23564        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23565            return false;
23566        }
23567        let classifier = snapshot
23568            .char_classifier_at(position)
23569            .scope_context(Some(CharScopeContext::Completion));
23570        if trigger_in_words && classifier.is_word(char) {
23571            return true;
23572        }
23573
23574        buffer.completion_triggers().contains(text)
23575    }
23576
23577    fn show_snippets(&self) -> bool {
23578        true
23579    }
23580}
23581
23582impl SemanticsProvider for Entity<Project> {
23583    fn hover(
23584        &self,
23585        buffer: &Entity<Buffer>,
23586        position: text::Anchor,
23587        cx: &mut App,
23588    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23589        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23590    }
23591
23592    fn document_highlights(
23593        &self,
23594        buffer: &Entity<Buffer>,
23595        position: text::Anchor,
23596        cx: &mut App,
23597    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23598        Some(self.update(cx, |project, cx| {
23599            project.document_highlights(buffer, position, cx)
23600        }))
23601    }
23602
23603    fn definitions(
23604        &self,
23605        buffer: &Entity<Buffer>,
23606        position: text::Anchor,
23607        kind: GotoDefinitionKind,
23608        cx: &mut App,
23609    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23610        Some(self.update(cx, |project, cx| match kind {
23611            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23612            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23613            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23614            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23615        }))
23616    }
23617
23618    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23619        self.update(cx, |project, cx| {
23620            if project
23621                .active_debug_session(cx)
23622                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23623            {
23624                return true;
23625            }
23626
23627            buffer.update(cx, |buffer, cx| {
23628                project.any_language_server_supports_inlay_hints(buffer, cx)
23629            })
23630        })
23631    }
23632
23633    fn inline_values(
23634        &self,
23635        buffer_handle: Entity<Buffer>,
23636        range: Range<text::Anchor>,
23637        cx: &mut App,
23638    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23639        self.update(cx, |project, cx| {
23640            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23641
23642            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23643        })
23644    }
23645
23646    fn applicable_inlay_chunks(
23647        &self,
23648        buffer: &Entity<Buffer>,
23649        ranges: &[Range<text::Anchor>],
23650        cx: &mut App,
23651    ) -> Vec<Range<BufferRow>> {
23652        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23653            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23654        })
23655    }
23656
23657    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23658        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23659            lsp_store.invalidate_inlay_hints(for_buffers)
23660        });
23661    }
23662
23663    fn inlay_hints(
23664        &self,
23665        invalidate: InvalidationStrategy,
23666        buffer: Entity<Buffer>,
23667        ranges: Vec<Range<text::Anchor>>,
23668        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23669        cx: &mut App,
23670    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23671        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23672            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23673        }))
23674    }
23675
23676    fn range_for_rename(
23677        &self,
23678        buffer: &Entity<Buffer>,
23679        position: text::Anchor,
23680        cx: &mut App,
23681    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23682        Some(self.update(cx, |project, cx| {
23683            let buffer = buffer.clone();
23684            let task = project.prepare_rename(buffer.clone(), position, cx);
23685            cx.spawn(async move |_, cx| {
23686                Ok(match task.await? {
23687                    PrepareRenameResponse::Success(range) => Some(range),
23688                    PrepareRenameResponse::InvalidPosition => None,
23689                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23690                        // Fallback on using TreeSitter info to determine identifier range
23691                        buffer.read_with(cx, |buffer, _| {
23692                            let snapshot = buffer.snapshot();
23693                            let (range, kind) = snapshot.surrounding_word(position, None);
23694                            if kind != Some(CharKind::Word) {
23695                                return None;
23696                            }
23697                            Some(
23698                                snapshot.anchor_before(range.start)
23699                                    ..snapshot.anchor_after(range.end),
23700                            )
23701                        })?
23702                    }
23703                })
23704            })
23705        }))
23706    }
23707
23708    fn perform_rename(
23709        &self,
23710        buffer: &Entity<Buffer>,
23711        position: text::Anchor,
23712        new_name: String,
23713        cx: &mut App,
23714    ) -> Option<Task<Result<ProjectTransaction>>> {
23715        Some(self.update(cx, |project, cx| {
23716            project.perform_rename(buffer.clone(), position, new_name, cx)
23717        }))
23718    }
23719}
23720
23721fn consume_contiguous_rows(
23722    contiguous_row_selections: &mut Vec<Selection<Point>>,
23723    selection: &Selection<Point>,
23724    display_map: &DisplaySnapshot,
23725    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23726) -> (MultiBufferRow, MultiBufferRow) {
23727    contiguous_row_selections.push(selection.clone());
23728    let start_row = starting_row(selection, display_map);
23729    let mut end_row = ending_row(selection, display_map);
23730
23731    while let Some(next_selection) = selections.peek() {
23732        if next_selection.start.row <= end_row.0 {
23733            end_row = ending_row(next_selection, display_map);
23734            contiguous_row_selections.push(selections.next().unwrap().clone());
23735        } else {
23736            break;
23737        }
23738    }
23739    (start_row, end_row)
23740}
23741
23742fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23743    if selection.start.column > 0 {
23744        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23745    } else {
23746        MultiBufferRow(selection.start.row)
23747    }
23748}
23749
23750fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23751    if next_selection.end.column > 0 || next_selection.is_empty() {
23752        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23753    } else {
23754        MultiBufferRow(next_selection.end.row)
23755    }
23756}
23757
23758impl EditorSnapshot {
23759    pub fn remote_selections_in_range<'a>(
23760        &'a self,
23761        range: &'a Range<Anchor>,
23762        collaboration_hub: &dyn CollaborationHub,
23763        cx: &'a App,
23764    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23765        let participant_names = collaboration_hub.user_names(cx);
23766        let participant_indices = collaboration_hub.user_participant_indices(cx);
23767        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23768        let collaborators_by_replica_id = collaborators_by_peer_id
23769            .values()
23770            .map(|collaborator| (collaborator.replica_id, collaborator))
23771            .collect::<HashMap<_, _>>();
23772        self.buffer_snapshot()
23773            .selections_in_range(range, false)
23774            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23775                if replica_id == ReplicaId::AGENT {
23776                    Some(RemoteSelection {
23777                        replica_id,
23778                        selection,
23779                        cursor_shape,
23780                        line_mode,
23781                        collaborator_id: CollaboratorId::Agent,
23782                        user_name: Some("Agent".into()),
23783                        color: cx.theme().players().agent(),
23784                    })
23785                } else {
23786                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23787                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23788                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23789                    Some(RemoteSelection {
23790                        replica_id,
23791                        selection,
23792                        cursor_shape,
23793                        line_mode,
23794                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23795                        user_name,
23796                        color: if let Some(index) = participant_index {
23797                            cx.theme().players().color_for_participant(index.0)
23798                        } else {
23799                            cx.theme().players().absent()
23800                        },
23801                    })
23802                }
23803            })
23804    }
23805
23806    pub fn hunks_for_ranges(
23807        &self,
23808        ranges: impl IntoIterator<Item = Range<Point>>,
23809    ) -> Vec<MultiBufferDiffHunk> {
23810        let mut hunks = Vec::new();
23811        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23812            HashMap::default();
23813        for query_range in ranges {
23814            let query_rows =
23815                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23816            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23817                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23818            ) {
23819                // Include deleted hunks that are adjacent to the query range, because
23820                // otherwise they would be missed.
23821                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23822                if hunk.status().is_deleted() {
23823                    intersects_range |= hunk.row_range.start == query_rows.end;
23824                    intersects_range |= hunk.row_range.end == query_rows.start;
23825                }
23826                if intersects_range {
23827                    if !processed_buffer_rows
23828                        .entry(hunk.buffer_id)
23829                        .or_default()
23830                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23831                    {
23832                        continue;
23833                    }
23834                    hunks.push(hunk);
23835                }
23836            }
23837        }
23838
23839        hunks
23840    }
23841
23842    fn display_diff_hunks_for_rows<'a>(
23843        &'a self,
23844        display_rows: Range<DisplayRow>,
23845        folded_buffers: &'a HashSet<BufferId>,
23846    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23847        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23848        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23849
23850        self.buffer_snapshot()
23851            .diff_hunks_in_range(buffer_start..buffer_end)
23852            .filter_map(|hunk| {
23853                if folded_buffers.contains(&hunk.buffer_id) {
23854                    return None;
23855                }
23856
23857                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23858                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23859
23860                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23861                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23862
23863                let display_hunk = if hunk_display_start.column() != 0 {
23864                    DisplayDiffHunk::Folded {
23865                        display_row: hunk_display_start.row(),
23866                    }
23867                } else {
23868                    let mut end_row = hunk_display_end.row();
23869                    if hunk_display_end.column() > 0 {
23870                        end_row.0 += 1;
23871                    }
23872                    let is_created_file = hunk.is_created_file();
23873                    DisplayDiffHunk::Unfolded {
23874                        status: hunk.status(),
23875                        diff_base_byte_range: hunk.diff_base_byte_range,
23876                        display_row_range: hunk_display_start.row()..end_row,
23877                        multi_buffer_range: Anchor::range_in_buffer(
23878                            hunk.excerpt_id,
23879                            hunk.buffer_id,
23880                            hunk.buffer_range,
23881                        ),
23882                        is_created_file,
23883                    }
23884                };
23885
23886                Some(display_hunk)
23887            })
23888    }
23889
23890    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23891        self.display_snapshot
23892            .buffer_snapshot()
23893            .language_at(position)
23894    }
23895
23896    pub fn is_focused(&self) -> bool {
23897        self.is_focused
23898    }
23899
23900    pub fn placeholder_text(&self) -> Option<String> {
23901        self.placeholder_display_snapshot
23902            .as_ref()
23903            .map(|display_map| display_map.text())
23904    }
23905
23906    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23907        self.scroll_anchor.scroll_position(&self.display_snapshot)
23908    }
23909
23910    fn gutter_dimensions(
23911        &self,
23912        font_id: FontId,
23913        font_size: Pixels,
23914        max_line_number_width: Pixels,
23915        cx: &App,
23916    ) -> Option<GutterDimensions> {
23917        if !self.show_gutter {
23918            return None;
23919        }
23920
23921        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23922        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23923
23924        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23925            matches!(
23926                ProjectSettings::get_global(cx).git.git_gutter,
23927                GitGutterSetting::TrackedFiles
23928            )
23929        });
23930        let gutter_settings = EditorSettings::get_global(cx).gutter;
23931        let show_line_numbers = self
23932            .show_line_numbers
23933            .unwrap_or(gutter_settings.line_numbers);
23934        let line_gutter_width = if show_line_numbers {
23935            // Avoid flicker-like gutter resizes when the line number gains another digit by
23936            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23937            let min_width_for_number_on_gutter =
23938                ch_advance * gutter_settings.min_line_number_digits as f32;
23939            max_line_number_width.max(min_width_for_number_on_gutter)
23940        } else {
23941            0.0.into()
23942        };
23943
23944        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23945        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23946
23947        let git_blame_entries_width =
23948            self.git_blame_gutter_max_author_length
23949                .map(|max_author_length| {
23950                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23951                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23952
23953                    /// The number of characters to dedicate to gaps and margins.
23954                    const SPACING_WIDTH: usize = 4;
23955
23956                    let max_char_count = max_author_length.min(renderer.max_author_length())
23957                        + ::git::SHORT_SHA_LENGTH
23958                        + MAX_RELATIVE_TIMESTAMP.len()
23959                        + SPACING_WIDTH;
23960
23961                    ch_advance * max_char_count
23962                });
23963
23964        let is_singleton = self.buffer_snapshot().is_singleton();
23965
23966        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23967        left_padding += if !is_singleton {
23968            ch_width * 4.0
23969        } else if show_runnables || show_breakpoints {
23970            ch_width * 3.0
23971        } else if show_git_gutter && show_line_numbers {
23972            ch_width * 2.0
23973        } else if show_git_gutter || show_line_numbers {
23974            ch_width
23975        } else {
23976            px(0.)
23977        };
23978
23979        let shows_folds = is_singleton && gutter_settings.folds;
23980
23981        let right_padding = if shows_folds && show_line_numbers {
23982            ch_width * 4.0
23983        } else if shows_folds || (!is_singleton && show_line_numbers) {
23984            ch_width * 3.0
23985        } else if show_line_numbers {
23986            ch_width
23987        } else {
23988            px(0.)
23989        };
23990
23991        Some(GutterDimensions {
23992            left_padding,
23993            right_padding,
23994            width: line_gutter_width + left_padding + right_padding,
23995            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23996            git_blame_entries_width,
23997        })
23998    }
23999
24000    pub fn render_crease_toggle(
24001        &self,
24002        buffer_row: MultiBufferRow,
24003        row_contains_cursor: bool,
24004        editor: Entity<Editor>,
24005        window: &mut Window,
24006        cx: &mut App,
24007    ) -> Option<AnyElement> {
24008        let folded = self.is_line_folded(buffer_row);
24009        let mut is_foldable = false;
24010
24011        if let Some(crease) = self
24012            .crease_snapshot
24013            .query_row(buffer_row, self.buffer_snapshot())
24014        {
24015            is_foldable = true;
24016            match crease {
24017                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24018                    if let Some(render_toggle) = render_toggle {
24019                        let toggle_callback =
24020                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24021                                if folded {
24022                                    editor.update(cx, |editor, cx| {
24023                                        editor.fold_at(buffer_row, window, cx)
24024                                    });
24025                                } else {
24026                                    editor.update(cx, |editor, cx| {
24027                                        editor.unfold_at(buffer_row, window, cx)
24028                                    });
24029                                }
24030                            });
24031                        return Some((render_toggle)(
24032                            buffer_row,
24033                            folded,
24034                            toggle_callback,
24035                            window,
24036                            cx,
24037                        ));
24038                    }
24039                }
24040            }
24041        }
24042
24043        is_foldable |= self.starts_indent(buffer_row);
24044
24045        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24046            Some(
24047                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24048                    .toggle_state(folded)
24049                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24050                        if folded {
24051                            this.unfold_at(buffer_row, window, cx);
24052                        } else {
24053                            this.fold_at(buffer_row, window, cx);
24054                        }
24055                    }))
24056                    .into_any_element(),
24057            )
24058        } else {
24059            None
24060        }
24061    }
24062
24063    pub fn render_crease_trailer(
24064        &self,
24065        buffer_row: MultiBufferRow,
24066        window: &mut Window,
24067        cx: &mut App,
24068    ) -> Option<AnyElement> {
24069        let folded = self.is_line_folded(buffer_row);
24070        if let Crease::Inline { render_trailer, .. } = self
24071            .crease_snapshot
24072            .query_row(buffer_row, self.buffer_snapshot())?
24073        {
24074            let render_trailer = render_trailer.as_ref()?;
24075            Some(render_trailer(buffer_row, folded, window, cx))
24076        } else {
24077            None
24078        }
24079    }
24080}
24081
24082impl Deref for EditorSnapshot {
24083    type Target = DisplaySnapshot;
24084
24085    fn deref(&self) -> &Self::Target {
24086        &self.display_snapshot
24087    }
24088}
24089
24090#[derive(Clone, Debug, PartialEq, Eq)]
24091pub enum EditorEvent {
24092    InputIgnored {
24093        text: Arc<str>,
24094    },
24095    InputHandled {
24096        utf16_range_to_replace: Option<Range<isize>>,
24097        text: Arc<str>,
24098    },
24099    ExcerptsAdded {
24100        buffer: Entity<Buffer>,
24101        predecessor: ExcerptId,
24102        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24103    },
24104    ExcerptsRemoved {
24105        ids: Vec<ExcerptId>,
24106        removed_buffer_ids: Vec<BufferId>,
24107    },
24108    BufferFoldToggled {
24109        ids: Vec<ExcerptId>,
24110        folded: bool,
24111    },
24112    ExcerptsEdited {
24113        ids: Vec<ExcerptId>,
24114    },
24115    ExcerptsExpanded {
24116        ids: Vec<ExcerptId>,
24117    },
24118    BufferEdited,
24119    Edited {
24120        transaction_id: clock::Lamport,
24121    },
24122    Reparsed(BufferId),
24123    Focused,
24124    FocusedIn,
24125    Blurred,
24126    DirtyChanged,
24127    Saved,
24128    TitleChanged,
24129    SelectionsChanged {
24130        local: bool,
24131    },
24132    ScrollPositionChanged {
24133        local: bool,
24134        autoscroll: bool,
24135    },
24136    TransactionUndone {
24137        transaction_id: clock::Lamport,
24138    },
24139    TransactionBegun {
24140        transaction_id: clock::Lamport,
24141    },
24142    CursorShapeChanged,
24143    BreadcrumbsChanged,
24144    PushedToNavHistory {
24145        anchor: Anchor,
24146        is_deactivate: bool,
24147    },
24148}
24149
24150impl EventEmitter<EditorEvent> for Editor {}
24151
24152impl Focusable for Editor {
24153    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24154        self.focus_handle.clone()
24155    }
24156}
24157
24158impl Render for Editor {
24159    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24160        let settings = ThemeSettings::get_global(cx);
24161
24162        let mut text_style = match self.mode {
24163            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24164                color: cx.theme().colors().editor_foreground,
24165                font_family: settings.ui_font.family.clone(),
24166                font_features: settings.ui_font.features.clone(),
24167                font_fallbacks: settings.ui_font.fallbacks.clone(),
24168                font_size: rems(0.875).into(),
24169                font_weight: settings.ui_font.weight,
24170                line_height: relative(settings.buffer_line_height.value()),
24171                ..Default::default()
24172            },
24173            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24174                color: cx.theme().colors().editor_foreground,
24175                font_family: settings.buffer_font.family.clone(),
24176                font_features: settings.buffer_font.features.clone(),
24177                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24178                font_size: settings.buffer_font_size(cx).into(),
24179                font_weight: settings.buffer_font.weight,
24180                line_height: relative(settings.buffer_line_height.value()),
24181                ..Default::default()
24182            },
24183        };
24184        if let Some(text_style_refinement) = &self.text_style_refinement {
24185            text_style.refine(text_style_refinement)
24186        }
24187
24188        let background = match self.mode {
24189            EditorMode::SingleLine => cx.theme().system().transparent,
24190            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24191            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24192            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24193        };
24194
24195        EditorElement::new(
24196            &cx.entity(),
24197            EditorStyle {
24198                background,
24199                border: cx.theme().colors().border,
24200                local_player: cx.theme().players().local(),
24201                text: text_style,
24202                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24203                syntax: cx.theme().syntax().clone(),
24204                status: cx.theme().status().clone(),
24205                inlay_hints_style: make_inlay_hints_style(cx),
24206                edit_prediction_styles: make_suggestion_styles(cx),
24207                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24208                show_underlines: self.diagnostics_enabled(),
24209            },
24210        )
24211    }
24212}
24213
24214impl EntityInputHandler for Editor {
24215    fn text_for_range(
24216        &mut self,
24217        range_utf16: Range<usize>,
24218        adjusted_range: &mut Option<Range<usize>>,
24219        _: &mut Window,
24220        cx: &mut Context<Self>,
24221    ) -> Option<String> {
24222        let snapshot = self.buffer.read(cx).read(cx);
24223        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24224        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24225        if (start.0..end.0) != range_utf16 {
24226            adjusted_range.replace(start.0..end.0);
24227        }
24228        Some(snapshot.text_for_range(start..end).collect())
24229    }
24230
24231    fn selected_text_range(
24232        &mut self,
24233        ignore_disabled_input: bool,
24234        _: &mut Window,
24235        cx: &mut Context<Self>,
24236    ) -> Option<UTF16Selection> {
24237        // Prevent the IME menu from appearing when holding down an alphabetic key
24238        // while input is disabled.
24239        if !ignore_disabled_input && !self.input_enabled {
24240            return None;
24241        }
24242
24243        let selection = self
24244            .selections
24245            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24246        let range = selection.range();
24247
24248        Some(UTF16Selection {
24249            range: range.start.0..range.end.0,
24250            reversed: selection.reversed,
24251        })
24252    }
24253
24254    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24255        let snapshot = self.buffer.read(cx).read(cx);
24256        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24257        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24258    }
24259
24260    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24261        self.clear_highlights::<InputComposition>(cx);
24262        self.ime_transaction.take();
24263    }
24264
24265    fn replace_text_in_range(
24266        &mut self,
24267        range_utf16: Option<Range<usize>>,
24268        text: &str,
24269        window: &mut Window,
24270        cx: &mut Context<Self>,
24271    ) {
24272        if !self.input_enabled {
24273            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24274            return;
24275        }
24276
24277        self.transact(window, cx, |this, window, cx| {
24278            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24279                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24280                Some(this.selection_replacement_ranges(range_utf16, cx))
24281            } else {
24282                this.marked_text_ranges(cx)
24283            };
24284
24285            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24286                let newest_selection_id = this.selections.newest_anchor().id;
24287                this.selections
24288                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24289                    .iter()
24290                    .zip(ranges_to_replace.iter())
24291                    .find_map(|(selection, range)| {
24292                        if selection.id == newest_selection_id {
24293                            Some(
24294                                (range.start.0 as isize - selection.head().0 as isize)
24295                                    ..(range.end.0 as isize - selection.head().0 as isize),
24296                            )
24297                        } else {
24298                            None
24299                        }
24300                    })
24301            });
24302
24303            cx.emit(EditorEvent::InputHandled {
24304                utf16_range_to_replace: range_to_replace,
24305                text: text.into(),
24306            });
24307
24308            if let Some(new_selected_ranges) = new_selected_ranges {
24309                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24310                    selections.select_ranges(new_selected_ranges)
24311                });
24312                this.backspace(&Default::default(), window, cx);
24313            }
24314
24315            this.handle_input(text, window, cx);
24316        });
24317
24318        if let Some(transaction) = self.ime_transaction {
24319            self.buffer.update(cx, |buffer, cx| {
24320                buffer.group_until_transaction(transaction, cx);
24321            });
24322        }
24323
24324        self.unmark_text(window, cx);
24325    }
24326
24327    fn replace_and_mark_text_in_range(
24328        &mut self,
24329        range_utf16: Option<Range<usize>>,
24330        text: &str,
24331        new_selected_range_utf16: Option<Range<usize>>,
24332        window: &mut Window,
24333        cx: &mut Context<Self>,
24334    ) {
24335        if !self.input_enabled {
24336            return;
24337        }
24338
24339        let transaction = self.transact(window, cx, |this, window, cx| {
24340            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24341                let snapshot = this.buffer.read(cx).read(cx);
24342                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24343                    for marked_range in &mut marked_ranges {
24344                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24345                        marked_range.start.0 += relative_range_utf16.start;
24346                        marked_range.start =
24347                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24348                        marked_range.end =
24349                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24350                    }
24351                }
24352                Some(marked_ranges)
24353            } else if let Some(range_utf16) = range_utf16 {
24354                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24355                Some(this.selection_replacement_ranges(range_utf16, cx))
24356            } else {
24357                None
24358            };
24359
24360            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24361                let newest_selection_id = this.selections.newest_anchor().id;
24362                this.selections
24363                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24364                    .iter()
24365                    .zip(ranges_to_replace.iter())
24366                    .find_map(|(selection, range)| {
24367                        if selection.id == newest_selection_id {
24368                            Some(
24369                                (range.start.0 as isize - selection.head().0 as isize)
24370                                    ..(range.end.0 as isize - selection.head().0 as isize),
24371                            )
24372                        } else {
24373                            None
24374                        }
24375                    })
24376            });
24377
24378            cx.emit(EditorEvent::InputHandled {
24379                utf16_range_to_replace: range_to_replace,
24380                text: text.into(),
24381            });
24382
24383            if let Some(ranges) = ranges_to_replace {
24384                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24385                    s.select_ranges(ranges)
24386                });
24387            }
24388
24389            let marked_ranges = {
24390                let snapshot = this.buffer.read(cx).read(cx);
24391                this.selections
24392                    .disjoint_anchors_arc()
24393                    .iter()
24394                    .map(|selection| {
24395                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24396                    })
24397                    .collect::<Vec<_>>()
24398            };
24399
24400            if text.is_empty() {
24401                this.unmark_text(window, cx);
24402            } else {
24403                this.highlight_text::<InputComposition>(
24404                    marked_ranges.clone(),
24405                    HighlightStyle {
24406                        underline: Some(UnderlineStyle {
24407                            thickness: px(1.),
24408                            color: None,
24409                            wavy: false,
24410                        }),
24411                        ..Default::default()
24412                    },
24413                    cx,
24414                );
24415            }
24416
24417            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24418            let use_autoclose = this.use_autoclose;
24419            let use_auto_surround = this.use_auto_surround;
24420            this.set_use_autoclose(false);
24421            this.set_use_auto_surround(false);
24422            this.handle_input(text, window, cx);
24423            this.set_use_autoclose(use_autoclose);
24424            this.set_use_auto_surround(use_auto_surround);
24425
24426            if let Some(new_selected_range) = new_selected_range_utf16 {
24427                let snapshot = this.buffer.read(cx).read(cx);
24428                let new_selected_ranges = marked_ranges
24429                    .into_iter()
24430                    .map(|marked_range| {
24431                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24432                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24433                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24434                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24435                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24436                    })
24437                    .collect::<Vec<_>>();
24438
24439                drop(snapshot);
24440                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24441                    selections.select_ranges(new_selected_ranges)
24442                });
24443            }
24444        });
24445
24446        self.ime_transaction = self.ime_transaction.or(transaction);
24447        if let Some(transaction) = self.ime_transaction {
24448            self.buffer.update(cx, |buffer, cx| {
24449                buffer.group_until_transaction(transaction, cx);
24450            });
24451        }
24452
24453        if self.text_highlights::<InputComposition>(cx).is_none() {
24454            self.ime_transaction.take();
24455        }
24456    }
24457
24458    fn bounds_for_range(
24459        &mut self,
24460        range_utf16: Range<usize>,
24461        element_bounds: gpui::Bounds<Pixels>,
24462        window: &mut Window,
24463        cx: &mut Context<Self>,
24464    ) -> Option<gpui::Bounds<Pixels>> {
24465        let text_layout_details = self.text_layout_details(window);
24466        let CharacterDimensions {
24467            em_width,
24468            em_advance,
24469            line_height,
24470        } = self.character_dimensions(window);
24471
24472        let snapshot = self.snapshot(window, cx);
24473        let scroll_position = snapshot.scroll_position();
24474        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24475
24476        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24477        let x = Pixels::from(
24478            ScrollOffset::from(
24479                snapshot.x_for_display_point(start, &text_layout_details)
24480                    + self.gutter_dimensions.full_width(),
24481            ) - scroll_left,
24482        );
24483        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24484
24485        Some(Bounds {
24486            origin: element_bounds.origin + point(x, y),
24487            size: size(em_width, line_height),
24488        })
24489    }
24490
24491    fn character_index_for_point(
24492        &mut self,
24493        point: gpui::Point<Pixels>,
24494        _window: &mut Window,
24495        _cx: &mut Context<Self>,
24496    ) -> Option<usize> {
24497        let position_map = self.last_position_map.as_ref()?;
24498        if !position_map.text_hitbox.contains(&point) {
24499            return None;
24500        }
24501        let display_point = position_map.point_for_position(point).previous_valid;
24502        let anchor = position_map
24503            .snapshot
24504            .display_point_to_anchor(display_point, Bias::Left);
24505        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24506        Some(utf16_offset.0)
24507    }
24508
24509    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24510        self.input_enabled
24511    }
24512}
24513
24514trait SelectionExt {
24515    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24516    fn spanned_rows(
24517        &self,
24518        include_end_if_at_line_start: bool,
24519        map: &DisplaySnapshot,
24520    ) -> Range<MultiBufferRow>;
24521}
24522
24523impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24524    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24525        let start = self
24526            .start
24527            .to_point(map.buffer_snapshot())
24528            .to_display_point(map);
24529        let end = self
24530            .end
24531            .to_point(map.buffer_snapshot())
24532            .to_display_point(map);
24533        if self.reversed {
24534            end..start
24535        } else {
24536            start..end
24537        }
24538    }
24539
24540    fn spanned_rows(
24541        &self,
24542        include_end_if_at_line_start: bool,
24543        map: &DisplaySnapshot,
24544    ) -> Range<MultiBufferRow> {
24545        let start = self.start.to_point(map.buffer_snapshot());
24546        let mut end = self.end.to_point(map.buffer_snapshot());
24547        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24548            end.row -= 1;
24549        }
24550
24551        let buffer_start = map.prev_line_boundary(start).0;
24552        let buffer_end = map.next_line_boundary(end).0;
24553        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24554    }
24555}
24556
24557impl<T: InvalidationRegion> InvalidationStack<T> {
24558    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24559    where
24560        S: Clone + ToOffset,
24561    {
24562        while let Some(region) = self.last() {
24563            let all_selections_inside_invalidation_ranges =
24564                if selections.len() == region.ranges().len() {
24565                    selections
24566                        .iter()
24567                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24568                        .all(|(selection, invalidation_range)| {
24569                            let head = selection.head().to_offset(buffer);
24570                            invalidation_range.start <= head && invalidation_range.end >= head
24571                        })
24572                } else {
24573                    false
24574                };
24575
24576            if all_selections_inside_invalidation_ranges {
24577                break;
24578            } else {
24579                self.pop();
24580            }
24581        }
24582    }
24583}
24584
24585impl<T> Default for InvalidationStack<T> {
24586    fn default() -> Self {
24587        Self(Default::default())
24588    }
24589}
24590
24591impl<T> Deref for InvalidationStack<T> {
24592    type Target = Vec<T>;
24593
24594    fn deref(&self) -> &Self::Target {
24595        &self.0
24596    }
24597}
24598
24599impl<T> DerefMut for InvalidationStack<T> {
24600    fn deref_mut(&mut self) -> &mut Self::Target {
24601        &mut self.0
24602    }
24603}
24604
24605impl InvalidationRegion for SnippetState {
24606    fn ranges(&self) -> &[Range<Anchor>] {
24607        &self.ranges[self.active_index]
24608    }
24609}
24610
24611fn edit_prediction_edit_text(
24612    current_snapshot: &BufferSnapshot,
24613    edits: &[(Range<Anchor>, impl AsRef<str>)],
24614    edit_preview: &EditPreview,
24615    include_deletions: bool,
24616    cx: &App,
24617) -> HighlightedText {
24618    let edits = edits
24619        .iter()
24620        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24621        .collect::<Vec<_>>();
24622
24623    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24624}
24625
24626fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24627    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24628    // Just show the raw edit text with basic styling
24629    let mut text = String::new();
24630    let mut highlights = Vec::new();
24631
24632    let insertion_highlight_style = HighlightStyle {
24633        color: Some(cx.theme().colors().text),
24634        ..Default::default()
24635    };
24636
24637    for (_, edit_text) in edits {
24638        let start_offset = text.len();
24639        text.push_str(edit_text);
24640        let end_offset = text.len();
24641
24642        if start_offset < end_offset {
24643            highlights.push((start_offset..end_offset, insertion_highlight_style));
24644        }
24645    }
24646
24647    HighlightedText {
24648        text: text.into(),
24649        highlights,
24650    }
24651}
24652
24653pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24654    match severity {
24655        lsp::DiagnosticSeverity::ERROR => colors.error,
24656        lsp::DiagnosticSeverity::WARNING => colors.warning,
24657        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24658        lsp::DiagnosticSeverity::HINT => colors.info,
24659        _ => colors.ignored,
24660    }
24661}
24662
24663pub fn styled_runs_for_code_label<'a>(
24664    label: &'a CodeLabel,
24665    syntax_theme: &'a theme::SyntaxTheme,
24666) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24667    let fade_out = HighlightStyle {
24668        fade_out: Some(0.35),
24669        ..Default::default()
24670    };
24671
24672    let mut prev_end = label.filter_range.end;
24673    label
24674        .runs
24675        .iter()
24676        .enumerate()
24677        .flat_map(move |(ix, (range, highlight_id))| {
24678            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24679                style
24680            } else {
24681                return Default::default();
24682            };
24683            let muted_style = style.highlight(fade_out);
24684
24685            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24686            if range.start >= label.filter_range.end {
24687                if range.start > prev_end {
24688                    runs.push((prev_end..range.start, fade_out));
24689                }
24690                runs.push((range.clone(), muted_style));
24691            } else if range.end <= label.filter_range.end {
24692                runs.push((range.clone(), style));
24693            } else {
24694                runs.push((range.start..label.filter_range.end, style));
24695                runs.push((label.filter_range.end..range.end, muted_style));
24696            }
24697            prev_end = cmp::max(prev_end, range.end);
24698
24699            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24700                runs.push((prev_end..label.text.len(), fade_out));
24701            }
24702
24703            runs
24704        })
24705}
24706
24707pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24708    let mut prev_index = 0;
24709    let mut prev_codepoint: Option<char> = None;
24710    text.char_indices()
24711        .chain([(text.len(), '\0')])
24712        .filter_map(move |(index, codepoint)| {
24713            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24714            let is_boundary = index == text.len()
24715                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24716                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24717            if is_boundary {
24718                let chunk = &text[prev_index..index];
24719                prev_index = index;
24720                Some(chunk)
24721            } else {
24722                None
24723            }
24724        })
24725}
24726
24727/// Given a string of text immediately before the cursor, iterates over possible
24728/// strings a snippet could match to. More precisely: returns an iterator over
24729/// suffixes of `text` created by splitting at word boundaries (before & after
24730/// every non-word character).
24731///
24732/// Shorter suffixes are returned first.
24733pub(crate) fn snippet_candidate_suffixes(
24734    text: &str,
24735    is_word_char: impl Fn(char) -> bool,
24736) -> impl std::iter::Iterator<Item = &str> {
24737    let mut prev_index = text.len();
24738    let mut prev_codepoint = None;
24739    text.char_indices()
24740        .rev()
24741        .chain([(0, '\0')])
24742        .filter_map(move |(index, codepoint)| {
24743            let prev_index = std::mem::replace(&mut prev_index, index);
24744            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24745            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24746                None
24747            } else {
24748                let chunk = &text[prev_index..]; // go to end of string
24749                Some(chunk)
24750            }
24751        })
24752}
24753
24754pub trait RangeToAnchorExt: Sized {
24755    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24756
24757    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24758        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24759        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24760    }
24761}
24762
24763impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24764    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24765        let start_offset = self.start.to_offset(snapshot);
24766        let end_offset = self.end.to_offset(snapshot);
24767        if start_offset == end_offset {
24768            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24769        } else {
24770            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24771        }
24772    }
24773}
24774
24775pub trait RowExt {
24776    fn as_f64(&self) -> f64;
24777
24778    fn next_row(&self) -> Self;
24779
24780    fn previous_row(&self) -> Self;
24781
24782    fn minus(&self, other: Self) -> u32;
24783}
24784
24785impl RowExt for DisplayRow {
24786    fn as_f64(&self) -> f64 {
24787        self.0 as _
24788    }
24789
24790    fn next_row(&self) -> Self {
24791        Self(self.0 + 1)
24792    }
24793
24794    fn previous_row(&self) -> Self {
24795        Self(self.0.saturating_sub(1))
24796    }
24797
24798    fn minus(&self, other: Self) -> u32 {
24799        self.0 - other.0
24800    }
24801}
24802
24803impl RowExt for MultiBufferRow {
24804    fn as_f64(&self) -> f64 {
24805        self.0 as _
24806    }
24807
24808    fn next_row(&self) -> Self {
24809        Self(self.0 + 1)
24810    }
24811
24812    fn previous_row(&self) -> Self {
24813        Self(self.0.saturating_sub(1))
24814    }
24815
24816    fn minus(&self, other: Self) -> u32 {
24817        self.0 - other.0
24818    }
24819}
24820
24821trait RowRangeExt {
24822    type Row;
24823
24824    fn len(&self) -> usize;
24825
24826    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24827}
24828
24829impl RowRangeExt for Range<MultiBufferRow> {
24830    type Row = MultiBufferRow;
24831
24832    fn len(&self) -> usize {
24833        (self.end.0 - self.start.0) as usize
24834    }
24835
24836    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24837        (self.start.0..self.end.0).map(MultiBufferRow)
24838    }
24839}
24840
24841impl RowRangeExt for Range<DisplayRow> {
24842    type Row = DisplayRow;
24843
24844    fn len(&self) -> usize {
24845        (self.end.0 - self.start.0) as usize
24846    }
24847
24848    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24849        (self.start.0..self.end.0).map(DisplayRow)
24850    }
24851}
24852
24853/// If select range has more than one line, we
24854/// just point the cursor to range.start.
24855fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24856    if range.start.row == range.end.row {
24857        range
24858    } else {
24859        range.start..range.start
24860    }
24861}
24862pub struct KillRing(ClipboardItem);
24863impl Global for KillRing {}
24864
24865const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24866
24867enum BreakpointPromptEditAction {
24868    Log,
24869    Condition,
24870    HitCondition,
24871}
24872
24873struct BreakpointPromptEditor {
24874    pub(crate) prompt: Entity<Editor>,
24875    editor: WeakEntity<Editor>,
24876    breakpoint_anchor: Anchor,
24877    breakpoint: Breakpoint,
24878    edit_action: BreakpointPromptEditAction,
24879    block_ids: HashSet<CustomBlockId>,
24880    editor_margins: Arc<Mutex<EditorMargins>>,
24881    _subscriptions: Vec<Subscription>,
24882}
24883
24884impl BreakpointPromptEditor {
24885    const MAX_LINES: u8 = 4;
24886
24887    fn new(
24888        editor: WeakEntity<Editor>,
24889        breakpoint_anchor: Anchor,
24890        breakpoint: Breakpoint,
24891        edit_action: BreakpointPromptEditAction,
24892        window: &mut Window,
24893        cx: &mut Context<Self>,
24894    ) -> Self {
24895        let base_text = match edit_action {
24896            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24897            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24898            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24899        }
24900        .map(|msg| msg.to_string())
24901        .unwrap_or_default();
24902
24903        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24904        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24905
24906        let prompt = cx.new(|cx| {
24907            let mut prompt = Editor::new(
24908                EditorMode::AutoHeight {
24909                    min_lines: 1,
24910                    max_lines: Some(Self::MAX_LINES as usize),
24911                },
24912                buffer,
24913                None,
24914                window,
24915                cx,
24916            );
24917            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24918            prompt.set_show_cursor_when_unfocused(false, cx);
24919            prompt.set_placeholder_text(
24920                match edit_action {
24921                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24922                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24923                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24924                },
24925                window,
24926                cx,
24927            );
24928
24929            prompt
24930        });
24931
24932        Self {
24933            prompt,
24934            editor,
24935            breakpoint_anchor,
24936            breakpoint,
24937            edit_action,
24938            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24939            block_ids: Default::default(),
24940            _subscriptions: vec![],
24941        }
24942    }
24943
24944    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24945        self.block_ids.extend(block_ids)
24946    }
24947
24948    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24949        if let Some(editor) = self.editor.upgrade() {
24950            let message = self
24951                .prompt
24952                .read(cx)
24953                .buffer
24954                .read(cx)
24955                .as_singleton()
24956                .expect("A multi buffer in breakpoint prompt isn't possible")
24957                .read(cx)
24958                .as_rope()
24959                .to_string();
24960
24961            editor.update(cx, |editor, cx| {
24962                editor.edit_breakpoint_at_anchor(
24963                    self.breakpoint_anchor,
24964                    self.breakpoint.clone(),
24965                    match self.edit_action {
24966                        BreakpointPromptEditAction::Log => {
24967                            BreakpointEditAction::EditLogMessage(message.into())
24968                        }
24969                        BreakpointPromptEditAction::Condition => {
24970                            BreakpointEditAction::EditCondition(message.into())
24971                        }
24972                        BreakpointPromptEditAction::HitCondition => {
24973                            BreakpointEditAction::EditHitCondition(message.into())
24974                        }
24975                    },
24976                    cx,
24977                );
24978
24979                editor.remove_blocks(self.block_ids.clone(), None, cx);
24980                cx.focus_self(window);
24981            });
24982        }
24983    }
24984
24985    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24986        self.editor
24987            .update(cx, |editor, cx| {
24988                editor.remove_blocks(self.block_ids.clone(), None, cx);
24989                window.focus(&editor.focus_handle);
24990            })
24991            .log_err();
24992    }
24993
24994    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24995        let settings = ThemeSettings::get_global(cx);
24996        let text_style = TextStyle {
24997            color: if self.prompt.read(cx).read_only(cx) {
24998                cx.theme().colors().text_disabled
24999            } else {
25000                cx.theme().colors().text
25001            },
25002            font_family: settings.buffer_font.family.clone(),
25003            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25004            font_size: settings.buffer_font_size(cx).into(),
25005            font_weight: settings.buffer_font.weight,
25006            line_height: relative(settings.buffer_line_height.value()),
25007            ..Default::default()
25008        };
25009        EditorElement::new(
25010            &self.prompt,
25011            EditorStyle {
25012                background: cx.theme().colors().editor_background,
25013                local_player: cx.theme().players().local(),
25014                text: text_style,
25015                ..Default::default()
25016            },
25017        )
25018    }
25019}
25020
25021impl Render for BreakpointPromptEditor {
25022    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25023        let editor_margins = *self.editor_margins.lock();
25024        let gutter_dimensions = editor_margins.gutter;
25025        h_flex()
25026            .key_context("Editor")
25027            .bg(cx.theme().colors().editor_background)
25028            .border_y_1()
25029            .border_color(cx.theme().status().info_border)
25030            .size_full()
25031            .py(window.line_height() / 2.5)
25032            .on_action(cx.listener(Self::confirm))
25033            .on_action(cx.listener(Self::cancel))
25034            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25035            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25036    }
25037}
25038
25039impl Focusable for BreakpointPromptEditor {
25040    fn focus_handle(&self, cx: &App) -> FocusHandle {
25041        self.prompt.focus_handle(cx)
25042    }
25043}
25044
25045fn all_edits_insertions_or_deletions(
25046    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25047    snapshot: &MultiBufferSnapshot,
25048) -> bool {
25049    let mut all_insertions = true;
25050    let mut all_deletions = true;
25051
25052    for (range, new_text) in edits.iter() {
25053        let range_is_empty = range.to_offset(snapshot).is_empty();
25054        let text_is_empty = new_text.is_empty();
25055
25056        if range_is_empty != text_is_empty {
25057            if range_is_empty {
25058                all_deletions = false;
25059            } else {
25060                all_insertions = false;
25061            }
25062        } else {
25063            return false;
25064        }
25065
25066        if !all_insertions && !all_deletions {
25067            return false;
25068        }
25069    }
25070    all_insertions || all_deletions
25071}
25072
25073struct MissingEditPredictionKeybindingTooltip;
25074
25075impl Render for MissingEditPredictionKeybindingTooltip {
25076    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25077        ui::tooltip_container(cx, |container, cx| {
25078            container
25079                .flex_shrink_0()
25080                .max_w_80()
25081                .min_h(rems_from_px(124.))
25082                .justify_between()
25083                .child(
25084                    v_flex()
25085                        .flex_1()
25086                        .text_ui_sm(cx)
25087                        .child(Label::new("Conflict with Accept Keybinding"))
25088                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25089                )
25090                .child(
25091                    h_flex()
25092                        .pb_1()
25093                        .gap_1()
25094                        .items_end()
25095                        .w_full()
25096                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25097                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25098                        }))
25099                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25100                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25101                        })),
25102                )
25103        })
25104    }
25105}
25106
25107#[derive(Debug, Clone, Copy, PartialEq)]
25108pub struct LineHighlight {
25109    pub background: Background,
25110    pub border: Option<gpui::Hsla>,
25111    pub include_gutter: bool,
25112    pub type_id: Option<TypeId>,
25113}
25114
25115struct LineManipulationResult {
25116    pub new_text: String,
25117    pub line_count_before: usize,
25118    pub line_count_after: usize,
25119}
25120
25121fn render_diff_hunk_controls(
25122    row: u32,
25123    status: &DiffHunkStatus,
25124    hunk_range: Range<Anchor>,
25125    is_created_file: bool,
25126    line_height: Pixels,
25127    editor: &Entity<Editor>,
25128    _window: &mut Window,
25129    cx: &mut App,
25130) -> AnyElement {
25131    h_flex()
25132        .h(line_height)
25133        .mr_1()
25134        .gap_1()
25135        .px_0p5()
25136        .pb_1()
25137        .border_x_1()
25138        .border_b_1()
25139        .border_color(cx.theme().colors().border_variant)
25140        .rounded_b_lg()
25141        .bg(cx.theme().colors().editor_background)
25142        .gap_1()
25143        .block_mouse_except_scroll()
25144        .shadow_md()
25145        .child(if status.has_secondary_hunk() {
25146            Button::new(("stage", row as u64), "Stage")
25147                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25148                .tooltip({
25149                    let focus_handle = editor.focus_handle(cx);
25150                    move |_window, cx| {
25151                        Tooltip::for_action_in(
25152                            "Stage Hunk",
25153                            &::git::ToggleStaged,
25154                            &focus_handle,
25155                            cx,
25156                        )
25157                    }
25158                })
25159                .on_click({
25160                    let editor = editor.clone();
25161                    move |_event, _window, cx| {
25162                        editor.update(cx, |editor, cx| {
25163                            editor.stage_or_unstage_diff_hunks(
25164                                true,
25165                                vec![hunk_range.start..hunk_range.start],
25166                                cx,
25167                            );
25168                        });
25169                    }
25170                })
25171        } else {
25172            Button::new(("unstage", row as u64), "Unstage")
25173                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25174                .tooltip({
25175                    let focus_handle = editor.focus_handle(cx);
25176                    move |_window, cx| {
25177                        Tooltip::for_action_in(
25178                            "Unstage Hunk",
25179                            &::git::ToggleStaged,
25180                            &focus_handle,
25181                            cx,
25182                        )
25183                    }
25184                })
25185                .on_click({
25186                    let editor = editor.clone();
25187                    move |_event, _window, cx| {
25188                        editor.update(cx, |editor, cx| {
25189                            editor.stage_or_unstage_diff_hunks(
25190                                false,
25191                                vec![hunk_range.start..hunk_range.start],
25192                                cx,
25193                            );
25194                        });
25195                    }
25196                })
25197        })
25198        .child(
25199            Button::new(("restore", row as u64), "Restore")
25200                .tooltip({
25201                    let focus_handle = editor.focus_handle(cx);
25202                    move |_window, cx| {
25203                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25204                    }
25205                })
25206                .on_click({
25207                    let editor = editor.clone();
25208                    move |_event, window, cx| {
25209                        editor.update(cx, |editor, cx| {
25210                            let snapshot = editor.snapshot(window, cx);
25211                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25212                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25213                        });
25214                    }
25215                })
25216                .disabled(is_created_file),
25217        )
25218        .when(
25219            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25220            |el| {
25221                el.child(
25222                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25223                        .shape(IconButtonShape::Square)
25224                        .icon_size(IconSize::Small)
25225                        // .disabled(!has_multiple_hunks)
25226                        .tooltip({
25227                            let focus_handle = editor.focus_handle(cx);
25228                            move |_window, cx| {
25229                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25230                            }
25231                        })
25232                        .on_click({
25233                            let editor = editor.clone();
25234                            move |_event, window, cx| {
25235                                editor.update(cx, |editor, cx| {
25236                                    let snapshot = editor.snapshot(window, cx);
25237                                    let position =
25238                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25239                                    editor.go_to_hunk_before_or_after_position(
25240                                        &snapshot,
25241                                        position,
25242                                        Direction::Next,
25243                                        window,
25244                                        cx,
25245                                    );
25246                                    editor.expand_selected_diff_hunks(cx);
25247                                });
25248                            }
25249                        }),
25250                )
25251                .child(
25252                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25253                        .shape(IconButtonShape::Square)
25254                        .icon_size(IconSize::Small)
25255                        // .disabled(!has_multiple_hunks)
25256                        .tooltip({
25257                            let focus_handle = editor.focus_handle(cx);
25258                            move |_window, cx| {
25259                                Tooltip::for_action_in(
25260                                    "Previous Hunk",
25261                                    &GoToPreviousHunk,
25262                                    &focus_handle,
25263                                    cx,
25264                                )
25265                            }
25266                        })
25267                        .on_click({
25268                            let editor = editor.clone();
25269                            move |_event, window, cx| {
25270                                editor.update(cx, |editor, cx| {
25271                                    let snapshot = editor.snapshot(window, cx);
25272                                    let point =
25273                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25274                                    editor.go_to_hunk_before_or_after_position(
25275                                        &snapshot,
25276                                        point,
25277                                        Direction::Prev,
25278                                        window,
25279                                        cx,
25280                                    );
25281                                    editor.expand_selected_diff_hunks(cx);
25282                                });
25283                            }
25284                        }),
25285                )
25286            },
25287        )
25288        .into_any_element()
25289}
25290
25291pub fn multibuffer_context_lines(cx: &App) -> u32 {
25292    EditorSettings::try_get(cx)
25293        .map(|settings| settings.excerpt_context_lines)
25294        .unwrap_or(2)
25295        .min(32)
25296}