editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, LanguageRegistry, OffsetRangeExt, OutlineItem, Point, Runnable,
  121    RunnableRange, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  122    WordsQuery,
  123    language_settings::{
  124        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  125        language_settings,
  126    },
  127    point_from_lsp, point_to_lsp, text_diff_with_options,
  128};
  129use linked_editing_ranges::refresh_linked_ranges;
  130use lsp::{
  131    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  132    LanguageServerId,
  133};
  134use lsp_colors::LspColorData;
  135use markdown::Markdown;
  136use mouse_context_menu::MouseContextMenu;
  137use movement::TextLayoutDetails;
  138use multi_buffer::{
  139    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  140};
  141use parking_lot::Mutex;
  142use persistence::DB;
  143use project::{
  144    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  145    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  146    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  147    ProjectPath, ProjectTransaction, TaskSourceKind,
  148    debugger::{
  149        breakpoint_store::{
  150            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  151            BreakpointStore, BreakpointStoreEvent,
  152        },
  153        session::{Session, SessionEvent},
  154    },
  155    git_store::GitStoreEvent,
  156    lsp_store::{
  157        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  158        OpenLspBufferHandle,
  159    },
  160    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  161};
  162use rand::seq::SliceRandom;
  163use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  164use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  165use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  166use serde::{Deserialize, Serialize};
  167use settings::{
  168    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  169    update_settings_file,
  170};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    inlays::{
  212        InlineValueCache,
  213        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  214    },
  215    scroll::{ScrollOffset, ScrollPixelOffset},
  216    selections_collection::resolve_selections_wrapping_blocks,
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    Closed,
  257}
  258
  259impl ReportEditorEvent {
  260    pub fn event_type(&self) -> &'static str {
  261        match self {
  262            Self::Saved { .. } => "Editor Saved",
  263            Self::EditorOpened => "Editor Opened",
  264            Self::Closed => "Editor Closed",
  265        }
  266    }
  267}
  268
  269pub enum ActiveDebugLine {}
  270pub enum DebugStackFrameLine {}
  271enum DocumentHighlightRead {}
  272enum DocumentHighlightWrite {}
  273enum InputComposition {}
  274pub enum PendingInput {}
  275enum SelectedTextHighlight {}
  276
  277pub enum ConflictsOuter {}
  278pub enum ConflictsOurs {}
  279pub enum ConflictsTheirs {}
  280pub enum ConflictsOursMarker {}
  281pub enum ConflictsTheirsMarker {}
  282
  283#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  284pub enum Navigated {
  285    Yes,
  286    No,
  287}
  288
  289impl Navigated {
  290    pub fn from_bool(yes: bool) -> Navigated {
  291        if yes { Navigated::Yes } else { Navigated::No }
  292    }
  293}
  294
  295#[derive(Debug, Clone, PartialEq, Eq)]
  296enum DisplayDiffHunk {
  297    Folded {
  298        display_row: DisplayRow,
  299    },
  300    Unfolded {
  301        is_created_file: bool,
  302        diff_base_byte_range: Range<usize>,
  303        display_row_range: Range<DisplayRow>,
  304        multi_buffer_range: Range<Anchor>,
  305        status: DiffHunkStatus,
  306    },
  307}
  308
  309pub enum HideMouseCursorOrigin {
  310    TypingAction,
  311    MovementAction,
  312}
  313
  314pub fn init(cx: &mut App) {
  315    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  316
  317    workspace::register_project_item::<Editor>(cx);
  318    workspace::FollowableViewRegistry::register::<Editor>(cx);
  319    workspace::register_serializable_item::<Editor>(cx);
  320
  321    cx.observe_new(
  322        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  323            workspace.register_action(Editor::new_file);
  324            workspace.register_action(Editor::new_file_split);
  325            workspace.register_action(Editor::new_file_vertical);
  326            workspace.register_action(Editor::new_file_horizontal);
  327            workspace.register_action(Editor::cancel_language_server_work);
  328            workspace.register_action(Editor::toggle_focus);
  329        },
  330    )
  331    .detach();
  332
  333    cx.on_action(move |_: &workspace::NewFile, cx| {
  334        let app_state = workspace::AppState::global(cx);
  335        if let Some(app_state) = app_state.upgrade() {
  336            workspace::open_new(
  337                Default::default(),
  338                app_state,
  339                cx,
  340                |workspace, window, cx| {
  341                    Editor::new_file(workspace, &Default::default(), window, cx)
  342                },
  343            )
  344            .detach();
  345        }
  346    });
  347    cx.on_action(move |_: &workspace::NewWindow, cx| {
  348        let app_state = workspace::AppState::global(cx);
  349        if let Some(app_state) = app_state.upgrade() {
  350            workspace::open_new(
  351                Default::default(),
  352                app_state,
  353                cx,
  354                |workspace, window, cx| {
  355                    cx.activate(true);
  356                    Editor::new_file(workspace, &Default::default(), window, cx)
  357                },
  358            )
  359            .detach();
  360        }
  361    });
  362}
  363
  364pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  365    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  366}
  367
  368pub trait DiagnosticRenderer {
  369    fn render_group(
  370        &self,
  371        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  372        buffer_id: BufferId,
  373        snapshot: EditorSnapshot,
  374        editor: WeakEntity<Editor>,
  375        language_registry: Option<Arc<LanguageRegistry>>,
  376        cx: &mut App,
  377    ) -> Vec<BlockProperties<Anchor>>;
  378
  379    fn render_hover(
  380        &self,
  381        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  382        range: Range<Point>,
  383        buffer_id: BufferId,
  384        language_registry: Option<Arc<LanguageRegistry>>,
  385        cx: &mut App,
  386    ) -> Option<Entity<markdown::Markdown>>;
  387
  388    fn open_link(
  389        &self,
  390        editor: &mut Editor,
  391        link: SharedString,
  392        window: &mut Window,
  393        cx: &mut Context<Editor>,
  394    );
  395}
  396
  397pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  398
  399impl GlobalDiagnosticRenderer {
  400    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  401        cx.try_global::<Self>().map(|g| g.0.clone())
  402    }
  403}
  404
  405impl gpui::Global for GlobalDiagnosticRenderer {}
  406pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  408}
  409
  410pub struct SearchWithinRange;
  411
  412trait InvalidationRegion {
  413    fn ranges(&self) -> &[Range<Anchor>];
  414}
  415
  416#[derive(Clone, Debug, PartialEq)]
  417pub enum SelectPhase {
  418    Begin {
  419        position: DisplayPoint,
  420        add: bool,
  421        click_count: usize,
  422    },
  423    BeginColumnar {
  424        position: DisplayPoint,
  425        reset: bool,
  426        mode: ColumnarMode,
  427        goal_column: u32,
  428    },
  429    Extend {
  430        position: DisplayPoint,
  431        click_count: usize,
  432    },
  433    Update {
  434        position: DisplayPoint,
  435        goal_column: u32,
  436        scroll_delta: gpui::Point<f32>,
  437    },
  438    End,
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum ColumnarMode {
  443    FromMouse,
  444    FromSelection,
  445}
  446
  447#[derive(Clone, Debug)]
  448pub enum SelectMode {
  449    Character,
  450    Word(Range<Anchor>),
  451    Line(Range<Anchor>),
  452    All,
  453}
  454
  455#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  456pub enum SizingBehavior {
  457    /// The editor will layout itself using `size_full` and will include the vertical
  458    /// scroll margin as requested by user settings.
  459    #[default]
  460    Default,
  461    /// The editor will layout itself using `size_full`, but will not have any
  462    /// vertical overscroll.
  463    ExcludeOverscrollMargin,
  464    /// The editor will request a vertical size according to its content and will be
  465    /// layouted without a vertical scroll margin.
  466    SizeByContent,
  467}
  468
  469#[derive(Clone, PartialEq, Eq, Debug)]
  470pub enum EditorMode {
  471    SingleLine,
  472    AutoHeight {
  473        min_lines: usize,
  474        max_lines: Option<usize>,
  475    },
  476    Full {
  477        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  478        scale_ui_elements_with_buffer_font_size: bool,
  479        /// When set to `true`, the editor will render a background for the active line.
  480        show_active_line_background: bool,
  481        /// Determines the sizing behavior for this editor
  482        sizing_behavior: SizingBehavior,
  483    },
  484    Minimap {
  485        parent: WeakEntity<Editor>,
  486    },
  487}
  488
  489impl EditorMode {
  490    pub fn full() -> Self {
  491        Self::Full {
  492            scale_ui_elements_with_buffer_font_size: true,
  493            show_active_line_background: true,
  494            sizing_behavior: SizingBehavior::Default,
  495        }
  496    }
  497
  498    #[inline]
  499    pub fn is_full(&self) -> bool {
  500        matches!(self, Self::Full { .. })
  501    }
  502
  503    #[inline]
  504    pub fn is_single_line(&self) -> bool {
  505        matches!(self, Self::SingleLine { .. })
  506    }
  507
  508    #[inline]
  509    fn is_minimap(&self) -> bool {
  510        matches!(self, Self::Minimap { .. })
  511    }
  512}
  513
  514#[derive(Copy, Clone, Debug)]
  515pub enum SoftWrap {
  516    /// Prefer not to wrap at all.
  517    ///
  518    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  519    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  520    GitDiff,
  521    /// Prefer a single line generally, unless an overly long line is encountered.
  522    None,
  523    /// Soft wrap lines that exceed the editor width.
  524    EditorWidth,
  525    /// Soft wrap lines at the preferred line length.
  526    Column(u32),
  527    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  528    Bounded(u32),
  529}
  530
  531#[derive(Clone)]
  532pub struct EditorStyle {
  533    pub background: Hsla,
  534    pub border: Hsla,
  535    pub local_player: PlayerColor,
  536    pub text: TextStyle,
  537    pub scrollbar_width: Pixels,
  538    pub syntax: Arc<SyntaxTheme>,
  539    pub status: StatusColors,
  540    pub inlay_hints_style: HighlightStyle,
  541    pub edit_prediction_styles: EditPredictionStyles,
  542    pub unnecessary_code_fade: f32,
  543    pub show_underlines: bool,
  544}
  545
  546impl Default for EditorStyle {
  547    fn default() -> Self {
  548        Self {
  549            background: Hsla::default(),
  550            border: Hsla::default(),
  551            local_player: PlayerColor::default(),
  552            text: TextStyle::default(),
  553            scrollbar_width: Pixels::default(),
  554            syntax: Default::default(),
  555            // HACK: Status colors don't have a real default.
  556            // We should look into removing the status colors from the editor
  557            // style and retrieve them directly from the theme.
  558            status: StatusColors::dark(),
  559            inlay_hints_style: HighlightStyle::default(),
  560            edit_prediction_styles: EditPredictionStyles {
  561                insertion: HighlightStyle::default(),
  562                whitespace: HighlightStyle::default(),
  563            },
  564            unnecessary_code_fade: Default::default(),
  565            show_underlines: true,
  566        }
  567    }
  568}
  569
  570pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  571    let show_background = language_settings::language_settings(None, None, cx)
  572        .inlay_hints
  573        .show_background;
  574
  575    let mut style = cx.theme().syntax().get("hint");
  576
  577    if style.color.is_none() {
  578        style.color = Some(cx.theme().status().hint);
  579    }
  580
  581    if !show_background {
  582        style.background_color = None;
  583        return style;
  584    }
  585
  586    if style.background_color.is_none() {
  587        style.background_color = Some(cx.theme().status().hint_background);
  588    }
  589
  590    style
  591}
  592
  593pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  594    EditPredictionStyles {
  595        insertion: HighlightStyle {
  596            color: Some(cx.theme().status().predictive),
  597            ..HighlightStyle::default()
  598        },
  599        whitespace: HighlightStyle {
  600            background_color: Some(cx.theme().status().created_background),
  601            ..HighlightStyle::default()
  602        },
  603    }
  604}
  605
  606type CompletionId = usize;
  607
  608pub(crate) enum EditDisplayMode {
  609    TabAccept,
  610    DiffPopover,
  611    Inline,
  612}
  613
  614enum EditPrediction {
  615    Edit {
  616        edits: Vec<(Range<Anchor>, Arc<str>)>,
  617        edit_preview: Option<EditPreview>,
  618        display_mode: EditDisplayMode,
  619        snapshot: BufferSnapshot,
  620    },
  621    /// Move to a specific location in the active editor
  622    MoveWithin {
  623        target: Anchor,
  624        snapshot: BufferSnapshot,
  625    },
  626    /// Move to a specific location in a different editor (not the active one)
  627    MoveOutside {
  628        target: language::Anchor,
  629        snapshot: BufferSnapshot,
  630    },
  631}
  632
  633struct EditPredictionState {
  634    inlay_ids: Vec<InlayId>,
  635    completion: EditPrediction,
  636    completion_id: Option<SharedString>,
  637    invalidation_range: Option<Range<Anchor>>,
  638}
  639
  640enum EditPredictionSettings {
  641    Disabled,
  642    Enabled {
  643        show_in_menu: bool,
  644        preview_requires_modifier: bool,
  645    },
  646}
  647
  648enum EditPredictionHighlight {}
  649
  650#[derive(Debug, Clone)]
  651struct InlineDiagnostic {
  652    message: SharedString,
  653    group_id: usize,
  654    is_primary: bool,
  655    start: Point,
  656    severity: lsp::DiagnosticSeverity,
  657}
  658
  659pub enum MenuEditPredictionsPolicy {
  660    Never,
  661    ByProvider,
  662}
  663
  664pub enum EditPredictionPreview {
  665    /// Modifier is not pressed
  666    Inactive { released_too_fast: bool },
  667    /// Modifier pressed
  668    Active {
  669        since: Instant,
  670        previous_scroll_position: Option<ScrollAnchor>,
  671    },
  672}
  673
  674impl EditPredictionPreview {
  675    pub fn released_too_fast(&self) -> bool {
  676        match self {
  677            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  678            EditPredictionPreview::Active { .. } => false,
  679        }
  680    }
  681
  682    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  683        if let EditPredictionPreview::Active {
  684            previous_scroll_position,
  685            ..
  686        } = self
  687        {
  688            *previous_scroll_position = scroll_position;
  689        }
  690    }
  691}
  692
  693pub struct ContextMenuOptions {
  694    pub min_entries_visible: usize,
  695    pub max_entries_visible: usize,
  696    pub placement: Option<ContextMenuPlacement>,
  697}
  698
  699#[derive(Debug, Clone, PartialEq, Eq)]
  700pub enum ContextMenuPlacement {
  701    Above,
  702    Below,
  703}
  704
  705#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  706struct EditorActionId(usize);
  707
  708impl EditorActionId {
  709    pub fn post_inc(&mut self) -> Self {
  710        let answer = self.0;
  711
  712        *self = Self(answer + 1);
  713
  714        Self(answer)
  715    }
  716}
  717
  718// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  719// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  720
  721type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  722type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  723
  724#[derive(Default)]
  725struct ScrollbarMarkerState {
  726    scrollbar_size: Size<Pixels>,
  727    dirty: bool,
  728    markers: Arc<[PaintQuad]>,
  729    pending_refresh: Option<Task<Result<()>>>,
  730}
  731
  732impl ScrollbarMarkerState {
  733    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  734        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  735    }
  736}
  737
  738#[derive(Clone, Copy, PartialEq, Eq)]
  739pub enum MinimapVisibility {
  740    Disabled,
  741    Enabled {
  742        /// The configuration currently present in the users settings.
  743        setting_configuration: bool,
  744        /// Whether to override the currently set visibility from the users setting.
  745        toggle_override: bool,
  746    },
  747}
  748
  749impl MinimapVisibility {
  750    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  751        if mode.is_full() {
  752            Self::Enabled {
  753                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  754                toggle_override: false,
  755            }
  756        } else {
  757            Self::Disabled
  758        }
  759    }
  760
  761    fn hidden(&self) -> Self {
  762        match *self {
  763            Self::Enabled {
  764                setting_configuration,
  765                ..
  766            } => Self::Enabled {
  767                setting_configuration,
  768                toggle_override: setting_configuration,
  769            },
  770            Self::Disabled => Self::Disabled,
  771        }
  772    }
  773
  774    fn disabled(&self) -> bool {
  775        matches!(*self, Self::Disabled)
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  813pub enum BufferSerialization {
  814    All,
  815    NonDirtyBuffers,
  816}
  817
  818impl BufferSerialization {
  819    fn new(restore_unsaved_buffers: bool) -> Self {
  820        if restore_unsaved_buffers {
  821            Self::All
  822        } else {
  823            Self::NonDirtyBuffers
  824        }
  825    }
  826}
  827
  828#[derive(Clone, Debug)]
  829struct RunnableTasks {
  830    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  831    offset: multi_buffer::Anchor,
  832    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  833    column: u32,
  834    // Values of all named captures, including those starting with '_'
  835    extra_variables: HashMap<String, String>,
  836    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  837    context_range: Range<BufferOffset>,
  838}
  839
  840impl RunnableTasks {
  841    fn resolve<'a>(
  842        &'a self,
  843        cx: &'a task::TaskContext,
  844    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  845        self.templates.iter().filter_map(|(kind, template)| {
  846            template
  847                .resolve_task(&kind.to_id_base(), cx)
  848                .map(|task| (kind.clone(), task))
  849        })
  850    }
  851}
  852
  853#[derive(Clone)]
  854pub struct ResolvedTasks {
  855    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  856    position: Anchor,
  857}
  858
  859#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  860struct BufferOffset(usize);
  861
  862/// Addons allow storing per-editor state in other crates (e.g. Vim)
  863pub trait Addon: 'static {
  864    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  865
  866    fn render_buffer_header_controls(
  867        &self,
  868        _: &ExcerptInfo,
  869        _: &Window,
  870        _: &App,
  871    ) -> Option<AnyElement> {
  872        None
  873    }
  874
  875    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    next_inlay_id: usize,
 1126    next_color_inlay_id: usize,
 1127    _subscriptions: Vec<Subscription>,
 1128    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1129    gutter_dimensions: GutterDimensions,
 1130    style: Option<EditorStyle>,
 1131    text_style_refinement: Option<TextStyleRefinement>,
 1132    next_editor_action_id: EditorActionId,
 1133    editor_actions: Rc<
 1134        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1135    >,
 1136    use_autoclose: bool,
 1137    use_auto_surround: bool,
 1138    auto_replace_emoji_shortcode: bool,
 1139    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1140    show_git_blame_gutter: bool,
 1141    show_git_blame_inline: bool,
 1142    show_git_blame_inline_delay_task: Option<Task<()>>,
 1143    git_blame_inline_enabled: bool,
 1144    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1145    buffer_serialization: Option<BufferSerialization>,
 1146    show_selection_menu: Option<bool>,
 1147    blame: Option<Entity<GitBlame>>,
 1148    blame_subscription: Option<Subscription>,
 1149    custom_context_menu: Option<
 1150        Box<
 1151            dyn 'static
 1152                + Fn(
 1153                    &mut Self,
 1154                    DisplayPoint,
 1155                    &mut Window,
 1156                    &mut Context<Self>,
 1157                ) -> Option<Entity<ui::ContextMenu>>,
 1158        >,
 1159    >,
 1160    last_bounds: Option<Bounds<Pixels>>,
 1161    last_position_map: Option<Rc<PositionMap>>,
 1162    expect_bounds_change: Option<Bounds<Pixels>>,
 1163    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1164    tasks_update_task: Option<Task<()>>,
 1165    breakpoint_store: Option<Entity<BreakpointStore>>,
 1166    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1167    hovered_diff_hunk_row: Option<DisplayRow>,
 1168    pull_diagnostics_task: Task<()>,
 1169    in_project_search: bool,
 1170    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1171    breadcrumb_header: Option<String>,
 1172    focused_block: Option<FocusedBlock>,
 1173    next_scroll_position: NextScrollCursorCenterTopBottom,
 1174    addons: HashMap<TypeId, Box<dyn Addon>>,
 1175    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1176    load_diff_task: Option<Shared<Task<()>>>,
 1177    /// Whether we are temporarily displaying a diff other than git's
 1178    temporary_diff_override: bool,
 1179    selection_mark_mode: bool,
 1180    toggle_fold_multiple_buffers: Task<()>,
 1181    _scroll_cursor_center_top_bottom_task: Task<()>,
 1182    serialize_selections: Task<()>,
 1183    serialize_folds: Task<()>,
 1184    mouse_cursor_hidden: bool,
 1185    minimap: Option<Entity<Self>>,
 1186    hide_mouse_mode: HideMouseMode,
 1187    pub change_list: ChangeList,
 1188    inline_value_cache: InlineValueCache,
 1189
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    post_scroll_update: Task<()>,
 1193    refresh_colors_task: Task<()>,
 1194    inlay_hints: Option<LspInlayHintData>,
 1195    folding_newlines: Task<()>,
 1196    select_next_is_case_sensitive: Option<bool>,
 1197    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1198}
 1199
 1200fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1201    if debounce_ms > 0 {
 1202        Some(Duration::from_millis(debounce_ms))
 1203    } else {
 1204        None
 1205    }
 1206}
 1207
 1208#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1209enum NextScrollCursorCenterTopBottom {
 1210    #[default]
 1211    Center,
 1212    Top,
 1213    Bottom,
 1214}
 1215
 1216impl NextScrollCursorCenterTopBottom {
 1217    fn next(&self) -> Self {
 1218        match self {
 1219            Self::Center => Self::Top,
 1220            Self::Top => Self::Bottom,
 1221            Self::Bottom => Self::Center,
 1222        }
 1223    }
 1224}
 1225
 1226#[derive(Clone)]
 1227pub struct EditorSnapshot {
 1228    pub mode: EditorMode,
 1229    show_gutter: bool,
 1230    show_line_numbers: Option<bool>,
 1231    show_git_diff_gutter: Option<bool>,
 1232    show_code_actions: Option<bool>,
 1233    show_runnables: Option<bool>,
 1234    show_breakpoints: Option<bool>,
 1235    git_blame_gutter_max_author_length: Option<usize>,
 1236    pub display_snapshot: DisplaySnapshot,
 1237    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1238    is_focused: bool,
 1239    scroll_anchor: ScrollAnchor,
 1240    ongoing_scroll: OngoingScroll,
 1241    current_line_highlight: CurrentLineHighlight,
 1242    gutter_hovered: bool,
 1243}
 1244
 1245#[derive(Default, Debug, Clone, Copy)]
 1246pub struct GutterDimensions {
 1247    pub left_padding: Pixels,
 1248    pub right_padding: Pixels,
 1249    pub width: Pixels,
 1250    pub margin: Pixels,
 1251    pub git_blame_entries_width: Option<Pixels>,
 1252}
 1253
 1254impl GutterDimensions {
 1255    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1256        Self {
 1257            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1258            ..Default::default()
 1259        }
 1260    }
 1261
 1262    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1263        -cx.text_system().descent(font_id, font_size)
 1264    }
 1265    /// The full width of the space taken up by the gutter.
 1266    pub fn full_width(&self) -> Pixels {
 1267        self.margin + self.width
 1268    }
 1269
 1270    /// The width of the space reserved for the fold indicators,
 1271    /// use alongside 'justify_end' and `gutter_width` to
 1272    /// right align content with the line numbers
 1273    pub fn fold_area_width(&self) -> Pixels {
 1274        self.margin + self.right_padding
 1275    }
 1276}
 1277
 1278struct CharacterDimensions {
 1279    em_width: Pixels,
 1280    em_advance: Pixels,
 1281    line_height: Pixels,
 1282}
 1283
 1284#[derive(Debug)]
 1285pub struct RemoteSelection {
 1286    pub replica_id: ReplicaId,
 1287    pub selection: Selection<Anchor>,
 1288    pub cursor_shape: CursorShape,
 1289    pub collaborator_id: CollaboratorId,
 1290    pub line_mode: bool,
 1291    pub user_name: Option<SharedString>,
 1292    pub color: PlayerColor,
 1293}
 1294
 1295#[derive(Clone, Debug)]
 1296struct SelectionHistoryEntry {
 1297    selections: Arc<[Selection<Anchor>]>,
 1298    select_next_state: Option<SelectNextState>,
 1299    select_prev_state: Option<SelectNextState>,
 1300    add_selections_state: Option<AddSelectionsState>,
 1301}
 1302
 1303#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1304enum SelectionHistoryMode {
 1305    #[default]
 1306    Normal,
 1307    Undoing,
 1308    Redoing,
 1309    Skipping,
 1310}
 1311
 1312#[derive(Clone, PartialEq, Eq, Hash)]
 1313struct HoveredCursor {
 1314    replica_id: ReplicaId,
 1315    selection_id: usize,
 1316}
 1317
 1318#[derive(Debug)]
 1319/// SelectionEffects controls the side-effects of updating the selection.
 1320///
 1321/// The default behaviour does "what you mostly want":
 1322/// - it pushes to the nav history if the cursor moved by >10 lines
 1323/// - it re-triggers completion requests
 1324/// - it scrolls to fit
 1325///
 1326/// You might want to modify these behaviours. For example when doing a "jump"
 1327/// like go to definition, we always want to add to nav history; but when scrolling
 1328/// in vim mode we never do.
 1329///
 1330/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1331/// move.
 1332#[derive(Clone)]
 1333pub struct SelectionEffects {
 1334    nav_history: Option<bool>,
 1335    completions: bool,
 1336    scroll: Option<Autoscroll>,
 1337}
 1338
 1339impl Default for SelectionEffects {
 1340    fn default() -> Self {
 1341        Self {
 1342            nav_history: None,
 1343            completions: true,
 1344            scroll: Some(Autoscroll::fit()),
 1345        }
 1346    }
 1347}
 1348impl SelectionEffects {
 1349    pub fn scroll(scroll: Autoscroll) -> Self {
 1350        Self {
 1351            scroll: Some(scroll),
 1352            ..Default::default()
 1353        }
 1354    }
 1355
 1356    pub fn no_scroll() -> Self {
 1357        Self {
 1358            scroll: None,
 1359            ..Default::default()
 1360        }
 1361    }
 1362
 1363    pub fn completions(self, completions: bool) -> Self {
 1364        Self {
 1365            completions,
 1366            ..self
 1367        }
 1368    }
 1369
 1370    pub fn nav_history(self, nav_history: bool) -> Self {
 1371        Self {
 1372            nav_history: Some(nav_history),
 1373            ..self
 1374        }
 1375    }
 1376}
 1377
 1378struct DeferredSelectionEffectsState {
 1379    changed: bool,
 1380    effects: SelectionEffects,
 1381    old_cursor_position: Anchor,
 1382    history_entry: SelectionHistoryEntry,
 1383}
 1384
 1385#[derive(Default)]
 1386struct SelectionHistory {
 1387    #[allow(clippy::type_complexity)]
 1388    selections_by_transaction:
 1389        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1390    mode: SelectionHistoryMode,
 1391    undo_stack: VecDeque<SelectionHistoryEntry>,
 1392    redo_stack: VecDeque<SelectionHistoryEntry>,
 1393}
 1394
 1395impl SelectionHistory {
 1396    #[track_caller]
 1397    fn insert_transaction(
 1398        &mut self,
 1399        transaction_id: TransactionId,
 1400        selections: Arc<[Selection<Anchor>]>,
 1401    ) {
 1402        if selections.is_empty() {
 1403            log::error!(
 1404                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1405                std::panic::Location::caller()
 1406            );
 1407            return;
 1408        }
 1409        self.selections_by_transaction
 1410            .insert(transaction_id, (selections, None));
 1411    }
 1412
 1413    #[allow(clippy::type_complexity)]
 1414    fn transaction(
 1415        &self,
 1416        transaction_id: TransactionId,
 1417    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1418        self.selections_by_transaction.get(&transaction_id)
 1419    }
 1420
 1421    #[allow(clippy::type_complexity)]
 1422    fn transaction_mut(
 1423        &mut self,
 1424        transaction_id: TransactionId,
 1425    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1426        self.selections_by_transaction.get_mut(&transaction_id)
 1427    }
 1428
 1429    fn push(&mut self, entry: SelectionHistoryEntry) {
 1430        if !entry.selections.is_empty() {
 1431            match self.mode {
 1432                SelectionHistoryMode::Normal => {
 1433                    self.push_undo(entry);
 1434                    self.redo_stack.clear();
 1435                }
 1436                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1437                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1438                SelectionHistoryMode::Skipping => {}
 1439            }
 1440        }
 1441    }
 1442
 1443    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1444        if self
 1445            .undo_stack
 1446            .back()
 1447            .is_none_or(|e| e.selections != entry.selections)
 1448        {
 1449            self.undo_stack.push_back(entry);
 1450            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1451                self.undo_stack.pop_front();
 1452            }
 1453        }
 1454    }
 1455
 1456    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1457        if self
 1458            .redo_stack
 1459            .back()
 1460            .is_none_or(|e| e.selections != entry.selections)
 1461        {
 1462            self.redo_stack.push_back(entry);
 1463            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1464                self.redo_stack.pop_front();
 1465            }
 1466        }
 1467    }
 1468}
 1469
 1470#[derive(Clone, Copy)]
 1471pub struct RowHighlightOptions {
 1472    pub autoscroll: bool,
 1473    pub include_gutter: bool,
 1474}
 1475
 1476impl Default for RowHighlightOptions {
 1477    fn default() -> Self {
 1478        Self {
 1479            autoscroll: Default::default(),
 1480            include_gutter: true,
 1481        }
 1482    }
 1483}
 1484
 1485struct RowHighlight {
 1486    index: usize,
 1487    range: Range<Anchor>,
 1488    color: Hsla,
 1489    options: RowHighlightOptions,
 1490    type_id: TypeId,
 1491}
 1492
 1493#[derive(Clone, Debug)]
 1494struct AddSelectionsState {
 1495    groups: Vec<AddSelectionsGroup>,
 1496}
 1497
 1498#[derive(Clone, Debug)]
 1499struct AddSelectionsGroup {
 1500    above: bool,
 1501    stack: Vec<usize>,
 1502}
 1503
 1504#[derive(Clone)]
 1505struct SelectNextState {
 1506    query: AhoCorasick,
 1507    wordwise: bool,
 1508    done: bool,
 1509}
 1510
 1511impl std::fmt::Debug for SelectNextState {
 1512    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1513        f.debug_struct(std::any::type_name::<Self>())
 1514            .field("wordwise", &self.wordwise)
 1515            .field("done", &self.done)
 1516            .finish()
 1517    }
 1518}
 1519
 1520#[derive(Debug)]
 1521struct AutocloseRegion {
 1522    selection_id: usize,
 1523    range: Range<Anchor>,
 1524    pair: BracketPair,
 1525}
 1526
 1527#[derive(Debug)]
 1528struct SnippetState {
 1529    ranges: Vec<Vec<Range<Anchor>>>,
 1530    active_index: usize,
 1531    choices: Vec<Option<Vec<String>>>,
 1532}
 1533
 1534#[doc(hidden)]
 1535pub struct RenameState {
 1536    pub range: Range<Anchor>,
 1537    pub old_name: Arc<str>,
 1538    pub editor: Entity<Editor>,
 1539    block_id: CustomBlockId,
 1540}
 1541
 1542struct InvalidationStack<T>(Vec<T>);
 1543
 1544struct RegisteredEditPredictionProvider {
 1545    provider: Arc<dyn EditPredictionProviderHandle>,
 1546    _subscription: Subscription,
 1547}
 1548
 1549#[derive(Debug, PartialEq, Eq)]
 1550pub struct ActiveDiagnosticGroup {
 1551    pub active_range: Range<Anchor>,
 1552    pub active_message: String,
 1553    pub group_id: usize,
 1554    pub blocks: HashSet<CustomBlockId>,
 1555}
 1556
 1557#[derive(Debug, PartialEq, Eq)]
 1558
 1559pub(crate) enum ActiveDiagnostic {
 1560    None,
 1561    All,
 1562    Group(ActiveDiagnosticGroup),
 1563}
 1564
 1565#[derive(Serialize, Deserialize, Clone, Debug)]
 1566pub struct ClipboardSelection {
 1567    /// The number of bytes in this selection.
 1568    pub len: usize,
 1569    /// Whether this was a full-line selection.
 1570    pub is_entire_line: bool,
 1571    /// The indentation of the first line when this content was originally copied.
 1572    pub first_line_indent: u32,
 1573}
 1574
 1575// selections, scroll behavior, was newest selection reversed
 1576type SelectSyntaxNodeHistoryState = (
 1577    Box<[Selection<usize>]>,
 1578    SelectSyntaxNodeScrollBehavior,
 1579    bool,
 1580);
 1581
 1582#[derive(Default)]
 1583struct SelectSyntaxNodeHistory {
 1584    stack: Vec<SelectSyntaxNodeHistoryState>,
 1585    // disable temporarily to allow changing selections without losing the stack
 1586    pub disable_clearing: bool,
 1587}
 1588
 1589impl SelectSyntaxNodeHistory {
 1590    pub fn try_clear(&mut self) {
 1591        if !self.disable_clearing {
 1592            self.stack.clear();
 1593        }
 1594    }
 1595
 1596    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1597        self.stack.push(selection);
 1598    }
 1599
 1600    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1601        self.stack.pop()
 1602    }
 1603}
 1604
 1605enum SelectSyntaxNodeScrollBehavior {
 1606    CursorTop,
 1607    FitSelection,
 1608    CursorBottom,
 1609}
 1610
 1611#[derive(Debug)]
 1612pub(crate) struct NavigationData {
 1613    cursor_anchor: Anchor,
 1614    cursor_position: Point,
 1615    scroll_anchor: ScrollAnchor,
 1616    scroll_top_row: u32,
 1617}
 1618
 1619#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1620pub enum GotoDefinitionKind {
 1621    Symbol,
 1622    Declaration,
 1623    Type,
 1624    Implementation,
 1625}
 1626
 1627pub enum FormatTarget {
 1628    Buffers(HashSet<Entity<Buffer>>),
 1629    Ranges(Vec<Range<MultiBufferPoint>>),
 1630}
 1631
 1632pub(crate) struct FocusedBlock {
 1633    id: BlockId,
 1634    focus_handle: WeakFocusHandle,
 1635}
 1636
 1637#[derive(Clone)]
 1638enum JumpData {
 1639    MultiBufferRow {
 1640        row: MultiBufferRow,
 1641        line_offset_from_top: u32,
 1642    },
 1643    MultiBufferPoint {
 1644        excerpt_id: ExcerptId,
 1645        position: Point,
 1646        anchor: text::Anchor,
 1647        line_offset_from_top: u32,
 1648    },
 1649}
 1650
 1651pub enum MultibufferSelectionMode {
 1652    First,
 1653    All,
 1654}
 1655
 1656#[derive(Clone, Copy, Debug, Default)]
 1657pub struct RewrapOptions {
 1658    pub override_language_settings: bool,
 1659    pub preserve_existing_whitespace: bool,
 1660}
 1661
 1662impl Editor {
 1663    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::full(), buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn auto_height(
 1676        min_lines: usize,
 1677        max_lines: usize,
 1678        window: &mut Window,
 1679        cx: &mut Context<Self>,
 1680    ) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::AutoHeight {
 1685                min_lines,
 1686                max_lines: Some(max_lines),
 1687            },
 1688            buffer,
 1689            None,
 1690            window,
 1691            cx,
 1692        )
 1693    }
 1694
 1695    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1696    /// The editor grows as tall as needed to fit its content.
 1697    pub fn auto_height_unbounded(
 1698        min_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: None,
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    pub fn for_buffer(
 1717        buffer: Entity<Buffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1723        Self::new(EditorMode::full(), buffer, project, window, cx)
 1724    }
 1725
 1726    pub fn for_multibuffer(
 1727        buffer: Entity<MultiBuffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        Self::new(EditorMode::full(), buffer, project, window, cx)
 1733    }
 1734
 1735    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1736        let mut clone = Self::new(
 1737            self.mode.clone(),
 1738            self.buffer.clone(),
 1739            self.project.clone(),
 1740            window,
 1741            cx,
 1742        );
 1743        self.display_map.update(cx, |display_map, cx| {
 1744            let snapshot = display_map.snapshot(cx);
 1745            clone.display_map.update(cx, |display_map, cx| {
 1746                display_map.set_state(&snapshot, cx);
 1747            });
 1748        });
 1749        clone.folds_did_change(cx);
 1750        clone.selections.clone_state(&self.selections);
 1751        clone.scroll_manager.clone_state(&self.scroll_manager);
 1752        clone.searchable = self.searchable;
 1753        clone.read_only = self.read_only;
 1754        clone
 1755    }
 1756
 1757    pub fn new(
 1758        mode: EditorMode,
 1759        buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        Editor::new_internal(mode, buffer, project, None, window, cx)
 1765    }
 1766
 1767    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1768        let multi_buffer = self.buffer().read(cx);
 1769        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1770        let multi_buffer_visible_start = self
 1771            .scroll_manager
 1772            .anchor()
 1773            .anchor
 1774            .to_point(&multi_buffer_snapshot);
 1775        let max_row = multi_buffer_snapshot.max_point().row;
 1776
 1777        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1778        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1779
 1780        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1781            let outline_items = buffer
 1782                .outline_items_containing(
 1783                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1784                    true,
 1785                    self.style().map(|style| style.syntax.as_ref()),
 1786                )
 1787                .into_iter()
 1788                .map(|outline_item| OutlineItem {
 1789                    depth: outline_item.depth,
 1790                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1791                    source_range_for_text: Anchor::range_in_buffer(
 1792                        *excerpt_id,
 1793                        buffer_id,
 1794                        outline_item.source_range_for_text,
 1795                    ),
 1796                    text: outline_item.text,
 1797                    highlight_ranges: outline_item.highlight_ranges,
 1798                    name_ranges: outline_item.name_ranges,
 1799                    body_range: outline_item
 1800                        .body_range
 1801                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1802                    annotation_range: outline_item
 1803                        .annotation_range
 1804                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1805                });
 1806            return Some(outline_items.collect());
 1807        }
 1808
 1809        None
 1810    }
 1811
 1812    fn new_internal(
 1813        mode: EditorMode,
 1814        multi_buffer: Entity<MultiBuffer>,
 1815        project: Option<Entity<Project>>,
 1816        display_map: Option<Entity<DisplayMap>>,
 1817        window: &mut Window,
 1818        cx: &mut Context<Self>,
 1819    ) -> Self {
 1820        debug_assert!(
 1821            display_map.is_none() || mode.is_minimap(),
 1822            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1823        );
 1824
 1825        let full_mode = mode.is_full();
 1826        let is_minimap = mode.is_minimap();
 1827        let diagnostics_max_severity = if full_mode {
 1828            EditorSettings::get_global(cx)
 1829                .diagnostics_max_severity
 1830                .unwrap_or(DiagnosticSeverity::Hint)
 1831        } else {
 1832            DiagnosticSeverity::Off
 1833        };
 1834        let style = window.text_style();
 1835        let font_size = style.font_size.to_pixels(window.rem_size());
 1836        let editor = cx.entity().downgrade();
 1837        let fold_placeholder = FoldPlaceholder {
 1838            constrain_width: false,
 1839            render: Arc::new(move |fold_id, fold_range, cx| {
 1840                let editor = editor.clone();
 1841                div()
 1842                    .id(fold_id)
 1843                    .bg(cx.theme().colors().ghost_element_background)
 1844                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1845                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1846                    .rounded_xs()
 1847                    .size_full()
 1848                    .cursor_pointer()
 1849                    .child("")
 1850                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1851                    .on_click(move |_, _window, cx| {
 1852                        editor
 1853                            .update(cx, |editor, cx| {
 1854                                editor.unfold_ranges(
 1855                                    &[fold_range.start..fold_range.end],
 1856                                    true,
 1857                                    false,
 1858                                    cx,
 1859                                );
 1860                                cx.stop_propagation();
 1861                            })
 1862                            .ok();
 1863                    })
 1864                    .into_any()
 1865            }),
 1866            merge_adjacent: true,
 1867            ..FoldPlaceholder::default()
 1868        };
 1869        let display_map = display_map.unwrap_or_else(|| {
 1870            cx.new(|cx| {
 1871                DisplayMap::new(
 1872                    multi_buffer.clone(),
 1873                    style.font(),
 1874                    font_size,
 1875                    None,
 1876                    FILE_HEADER_HEIGHT,
 1877                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1878                    fold_placeholder,
 1879                    diagnostics_max_severity,
 1880                    cx,
 1881                )
 1882            })
 1883        });
 1884
 1885        let selections = SelectionsCollection::new();
 1886
 1887        let blink_manager = cx.new(|cx| {
 1888            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1889            if is_minimap {
 1890                blink_manager.disable(cx);
 1891            }
 1892            blink_manager
 1893        });
 1894
 1895        let soft_wrap_mode_override =
 1896            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1897
 1898        let mut project_subscriptions = Vec::new();
 1899        if full_mode && let Some(project) = project.as_ref() {
 1900            project_subscriptions.push(cx.subscribe_in(
 1901                project,
 1902                window,
 1903                |editor, _, event, window, cx| match event {
 1904                    project::Event::RefreshCodeLens => {
 1905                        // we always query lens with actions, without storing them, always refreshing them
 1906                    }
 1907                    project::Event::RefreshInlayHints {
 1908                        server_id,
 1909                        request_id,
 1910                    } => {
 1911                        editor.refresh_inlay_hints(
 1912                            InlayHintRefreshReason::RefreshRequested {
 1913                                server_id: *server_id,
 1914                                request_id: *request_id,
 1915                            },
 1916                            cx,
 1917                        );
 1918                    }
 1919                    project::Event::LanguageServerRemoved(..) => {
 1920                        if editor.tasks_update_task.is_none() {
 1921                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1922                        }
 1923                        editor.registered_buffers.clear();
 1924                        editor.register_visible_buffers(cx);
 1925                    }
 1926                    project::Event::LanguageServerAdded(..) => {
 1927                        if editor.tasks_update_task.is_none() {
 1928                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1929                        }
 1930                    }
 1931                    project::Event::SnippetEdit(id, snippet_edits) => {
 1932                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1933                            let focus_handle = editor.focus_handle(cx);
 1934                            if focus_handle.is_focused(window) {
 1935                                let snapshot = buffer.read(cx).snapshot();
 1936                                for (range, snippet) in snippet_edits {
 1937                                    let editor_range =
 1938                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1939                                    editor
 1940                                        .insert_snippet(
 1941                                            &[editor_range],
 1942                                            snippet.clone(),
 1943                                            window,
 1944                                            cx,
 1945                                        )
 1946                                        .ok();
 1947                                }
 1948                            }
 1949                        }
 1950                    }
 1951                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1952                        let buffer_id = *buffer_id;
 1953                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1954                            editor.register_buffer(buffer_id, cx);
 1955                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1956                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1957                            refresh_linked_ranges(editor, window, cx);
 1958                            editor.refresh_code_actions(window, cx);
 1959                            editor.refresh_document_highlights(cx);
 1960                        }
 1961                    }
 1962
 1963                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1964                        let Some(workspace) = editor.workspace() else {
 1965                            return;
 1966                        };
 1967                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1968                        else {
 1969                            return;
 1970                        };
 1971
 1972                        if active_editor.entity_id() == cx.entity_id() {
 1973                            let entity_id = cx.entity_id();
 1974                            workspace.update(cx, |this, cx| {
 1975                                this.panes_mut()
 1976                                    .iter_mut()
 1977                                    .filter(|pane| pane.entity_id() != entity_id)
 1978                                    .for_each(|p| {
 1979                                        p.update(cx, |pane, _| {
 1980                                            pane.nav_history_mut().rename_item(
 1981                                                entity_id,
 1982                                                project_path.clone(),
 1983                                                abs_path.clone().into(),
 1984                                            );
 1985                                        })
 1986                                    });
 1987                            });
 1988                            let edited_buffers_already_open = {
 1989                                let other_editors: Vec<Entity<Editor>> = workspace
 1990                                    .read(cx)
 1991                                    .panes()
 1992                                    .iter()
 1993                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1994                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1995                                    .collect();
 1996
 1997                                transaction.0.keys().all(|buffer| {
 1998                                    other_editors.iter().any(|editor| {
 1999                                        let multi_buffer = editor.read(cx).buffer();
 2000                                        multi_buffer.read(cx).is_singleton()
 2001                                            && multi_buffer.read(cx).as_singleton().map_or(
 2002                                                false,
 2003                                                |singleton| {
 2004                                                    singleton.entity_id() == buffer.entity_id()
 2005                                                },
 2006                                            )
 2007                                    })
 2008                                })
 2009                            };
 2010                            if !edited_buffers_already_open {
 2011                                let workspace = workspace.downgrade();
 2012                                let transaction = transaction.clone();
 2013                                cx.defer_in(window, move |_, window, cx| {
 2014                                    cx.spawn_in(window, async move |editor, cx| {
 2015                                        Self::open_project_transaction(
 2016                                            &editor,
 2017                                            workspace,
 2018                                            transaction,
 2019                                            "Rename".to_string(),
 2020                                            cx,
 2021                                        )
 2022                                        .await
 2023                                        .ok()
 2024                                    })
 2025                                    .detach();
 2026                                });
 2027                            }
 2028                        }
 2029                    }
 2030
 2031                    _ => {}
 2032                },
 2033            ));
 2034            if let Some(task_inventory) = project
 2035                .read(cx)
 2036                .task_store()
 2037                .read(cx)
 2038                .task_inventory()
 2039                .cloned()
 2040            {
 2041                project_subscriptions.push(cx.observe_in(
 2042                    &task_inventory,
 2043                    window,
 2044                    |editor, _, window, cx| {
 2045                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2046                    },
 2047                ));
 2048            };
 2049
 2050            project_subscriptions.push(cx.subscribe_in(
 2051                &project.read(cx).breakpoint_store(),
 2052                window,
 2053                |editor, _, event, window, cx| match event {
 2054                    BreakpointStoreEvent::ClearDebugLines => {
 2055                        editor.clear_row_highlights::<ActiveDebugLine>();
 2056                        editor.refresh_inline_values(cx);
 2057                    }
 2058                    BreakpointStoreEvent::SetDebugLine => {
 2059                        if editor.go_to_active_debug_line(window, cx) {
 2060                            cx.stop_propagation();
 2061                        }
 2062
 2063                        editor.refresh_inline_values(cx);
 2064                    }
 2065                    _ => {}
 2066                },
 2067            ));
 2068            let git_store = project.read(cx).git_store().clone();
 2069            let project = project.clone();
 2070            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2071                if let GitStoreEvent::RepositoryAdded = event {
 2072                    this.load_diff_task = Some(
 2073                        update_uncommitted_diff_for_buffer(
 2074                            cx.entity(),
 2075                            &project,
 2076                            this.buffer.read(cx).all_buffers(),
 2077                            this.buffer.clone(),
 2078                            cx,
 2079                        )
 2080                        .shared(),
 2081                    );
 2082                }
 2083            }));
 2084        }
 2085
 2086        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2087
 2088        let inlay_hint_settings =
 2089            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2090        let focus_handle = cx.focus_handle();
 2091        if !is_minimap {
 2092            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2093                .detach();
 2094            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2095                .detach();
 2096            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2097                .detach();
 2098            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2099                .detach();
 2100            cx.observe_pending_input(window, Self::observe_pending_input)
 2101                .detach();
 2102        }
 2103
 2104        let show_indent_guides =
 2105            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2106                Some(false)
 2107            } else {
 2108                None
 2109            };
 2110
 2111        let breakpoint_store = match (&mode, project.as_ref()) {
 2112            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2113            _ => None,
 2114        };
 2115
 2116        let mut code_action_providers = Vec::new();
 2117        let mut load_uncommitted_diff = None;
 2118        if let Some(project) = project.clone() {
 2119            load_uncommitted_diff = Some(
 2120                update_uncommitted_diff_for_buffer(
 2121                    cx.entity(),
 2122                    &project,
 2123                    multi_buffer.read(cx).all_buffers(),
 2124                    multi_buffer.clone(),
 2125                    cx,
 2126                )
 2127                .shared(),
 2128            );
 2129            code_action_providers.push(Rc::new(project) as Rc<_>);
 2130        }
 2131
 2132        let mut editor = Self {
 2133            focus_handle,
 2134            show_cursor_when_unfocused: false,
 2135            last_focused_descendant: None,
 2136            buffer: multi_buffer.clone(),
 2137            display_map: display_map.clone(),
 2138            placeholder_display_map: None,
 2139            selections,
 2140            scroll_manager: ScrollManager::new(cx),
 2141            columnar_selection_state: None,
 2142            add_selections_state: None,
 2143            select_next_state: None,
 2144            select_prev_state: None,
 2145            selection_history: SelectionHistory::default(),
 2146            defer_selection_effects: false,
 2147            deferred_selection_effects_state: None,
 2148            autoclose_regions: Vec::new(),
 2149            snippet_stack: InvalidationStack::default(),
 2150            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2151            ime_transaction: None,
 2152            active_diagnostics: ActiveDiagnostic::None,
 2153            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2154            inline_diagnostics_update: Task::ready(()),
 2155            inline_diagnostics: Vec::new(),
 2156            soft_wrap_mode_override,
 2157            diagnostics_max_severity,
 2158            hard_wrap: None,
 2159            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2160            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2161            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2162            project,
 2163            blink_manager: blink_manager.clone(),
 2164            show_local_selections: true,
 2165            show_scrollbars: ScrollbarAxes {
 2166                horizontal: full_mode,
 2167                vertical: full_mode,
 2168            },
 2169            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2170            offset_content: !matches!(mode, EditorMode::SingleLine),
 2171            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2172            show_gutter: full_mode,
 2173            show_line_numbers: (!full_mode).then_some(false),
 2174            use_relative_line_numbers: None,
 2175            disable_expand_excerpt_buttons: !full_mode,
 2176            show_git_diff_gutter: None,
 2177            show_code_actions: None,
 2178            show_runnables: None,
 2179            show_breakpoints: None,
 2180            show_wrap_guides: None,
 2181            show_indent_guides,
 2182            highlight_order: 0,
 2183            highlighted_rows: HashMap::default(),
 2184            background_highlights: HashMap::default(),
 2185            gutter_highlights: HashMap::default(),
 2186            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2187            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2188            nav_history: None,
 2189            context_menu: RefCell::new(None),
 2190            context_menu_options: None,
 2191            mouse_context_menu: None,
 2192            completion_tasks: Vec::new(),
 2193            inline_blame_popover: None,
 2194            inline_blame_popover_show_task: None,
 2195            signature_help_state: SignatureHelpState::default(),
 2196            auto_signature_help: None,
 2197            find_all_references_task_sources: Vec::new(),
 2198            next_completion_id: 0,
 2199            next_inlay_id: 0,
 2200            code_action_providers,
 2201            available_code_actions: None,
 2202            code_actions_task: None,
 2203            quick_selection_highlight_task: None,
 2204            debounced_selection_highlight_task: None,
 2205            document_highlights_task: None,
 2206            linked_editing_range_task: None,
 2207            pending_rename: None,
 2208            searchable: !is_minimap,
 2209            cursor_shape: EditorSettings::get_global(cx)
 2210                .cursor_shape
 2211                .unwrap_or_default(),
 2212            current_line_highlight: None,
 2213            autoindent_mode: Some(AutoindentMode::EachLine),
 2214
 2215            workspace: None,
 2216            input_enabled: !is_minimap,
 2217            use_modal_editing: full_mode,
 2218            read_only: is_minimap,
 2219            use_autoclose: true,
 2220            use_auto_surround: true,
 2221            auto_replace_emoji_shortcode: false,
 2222            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2223            leader_id: None,
 2224            remote_id: None,
 2225            hover_state: HoverState::default(),
 2226            pending_mouse_down: None,
 2227            hovered_link_state: None,
 2228            edit_prediction_provider: None,
 2229            active_edit_prediction: None,
 2230            stale_edit_prediction_in_menu: None,
 2231            edit_prediction_preview: EditPredictionPreview::Inactive {
 2232                released_too_fast: false,
 2233            },
 2234            inline_diagnostics_enabled: full_mode,
 2235            diagnostics_enabled: full_mode,
 2236            word_completions_enabled: full_mode,
 2237            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2238            gutter_hovered: false,
 2239            pixel_position_of_newest_cursor: None,
 2240            last_bounds: None,
 2241            last_position_map: None,
 2242            expect_bounds_change: None,
 2243            gutter_dimensions: GutterDimensions::default(),
 2244            style: None,
 2245            show_cursor_names: false,
 2246            hovered_cursors: HashMap::default(),
 2247            next_editor_action_id: EditorActionId::default(),
 2248            editor_actions: Rc::default(),
 2249            edit_predictions_hidden_for_vim_mode: false,
 2250            show_edit_predictions_override: None,
 2251            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2252            edit_prediction_settings: EditPredictionSettings::Disabled,
 2253            edit_prediction_indent_conflict: false,
 2254            edit_prediction_requires_modifier_in_indent_conflict: true,
 2255            custom_context_menu: None,
 2256            show_git_blame_gutter: false,
 2257            show_git_blame_inline: false,
 2258            show_selection_menu: None,
 2259            show_git_blame_inline_delay_task: None,
 2260            git_blame_inline_enabled: full_mode
 2261                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2262            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2263            buffer_serialization: is_minimap.not().then(|| {
 2264                BufferSerialization::new(
 2265                    ProjectSettings::get_global(cx)
 2266                        .session
 2267                        .restore_unsaved_buffers,
 2268                )
 2269            }),
 2270            blame: None,
 2271            blame_subscription: None,
 2272            tasks: BTreeMap::default(),
 2273
 2274            breakpoint_store,
 2275            gutter_breakpoint_indicator: (None, None),
 2276            hovered_diff_hunk_row: None,
 2277            _subscriptions: (!is_minimap)
 2278                .then(|| {
 2279                    vec![
 2280                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2281                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2282                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2283                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2284                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2285                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2286                        cx.observe_window_activation(window, |editor, window, cx| {
 2287                            let active = window.is_window_active();
 2288                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2289                                if active {
 2290                                    blink_manager.enable(cx);
 2291                                } else {
 2292                                    blink_manager.disable(cx);
 2293                                }
 2294                            });
 2295                            if active {
 2296                                editor.show_mouse_cursor(cx);
 2297                            }
 2298                        }),
 2299                    ]
 2300                })
 2301                .unwrap_or_default(),
 2302            tasks_update_task: None,
 2303            pull_diagnostics_task: Task::ready(()),
 2304            colors: None,
 2305            refresh_colors_task: Task::ready(()),
 2306            inlay_hints: None,
 2307            next_color_inlay_id: 0,
 2308            post_scroll_update: Task::ready(()),
 2309            linked_edit_ranges: Default::default(),
 2310            in_project_search: false,
 2311            previous_search_ranges: None,
 2312            breadcrumb_header: None,
 2313            focused_block: None,
 2314            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2315            addons: HashMap::default(),
 2316            registered_buffers: HashMap::default(),
 2317            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2318            selection_mark_mode: false,
 2319            toggle_fold_multiple_buffers: Task::ready(()),
 2320            serialize_selections: Task::ready(()),
 2321            serialize_folds: Task::ready(()),
 2322            text_style_refinement: None,
 2323            load_diff_task: load_uncommitted_diff,
 2324            temporary_diff_override: false,
 2325            mouse_cursor_hidden: false,
 2326            minimap: None,
 2327            hide_mouse_mode: EditorSettings::get_global(cx)
 2328                .hide_mouse
 2329                .unwrap_or_default(),
 2330            change_list: ChangeList::new(),
 2331            mode,
 2332            selection_drag_state: SelectionDragState::None,
 2333            folding_newlines: Task::ready(()),
 2334            lookup_key: None,
 2335            select_next_is_case_sensitive: None,
 2336        };
 2337
 2338        if is_minimap {
 2339            return editor;
 2340        }
 2341
 2342        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2343            editor
 2344                ._subscriptions
 2345                .push(cx.observe(breakpoints, |_, _, cx| {
 2346                    cx.notify();
 2347                }));
 2348        }
 2349        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2350        editor._subscriptions.extend(project_subscriptions);
 2351
 2352        editor._subscriptions.push(cx.subscribe_in(
 2353            &cx.entity(),
 2354            window,
 2355            |editor, _, e: &EditorEvent, window, cx| match e {
 2356                EditorEvent::ScrollPositionChanged { local, .. } => {
 2357                    if *local {
 2358                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2359                        editor.inline_blame_popover.take();
 2360                        let new_anchor = editor.scroll_manager.anchor();
 2361                        let snapshot = editor.snapshot(window, cx);
 2362                        editor.update_restoration_data(cx, move |data| {
 2363                            data.scroll_position = (
 2364                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2365                                new_anchor.offset,
 2366                            );
 2367                        });
 2368
 2369                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2370                            cx.background_executor()
 2371                                .timer(Duration::from_millis(50))
 2372                                .await;
 2373                            editor
 2374                                .update_in(cx, |editor, window, cx| {
 2375                                    editor.register_visible_buffers(cx);
 2376                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2377                                    editor.refresh_inlay_hints(
 2378                                        InlayHintRefreshReason::NewLinesShown,
 2379                                        cx,
 2380                                    );
 2381                                })
 2382                                .ok();
 2383                        });
 2384                    }
 2385                }
 2386                EditorEvent::Edited { .. } => {
 2387                    if vim_flavor(cx).is_none() {
 2388                        let display_map = editor.display_snapshot(cx);
 2389                        let selections = editor.selections.all_adjusted_display(&display_map);
 2390                        let pop_state = editor
 2391                            .change_list
 2392                            .last()
 2393                            .map(|previous| {
 2394                                previous.len() == selections.len()
 2395                                    && previous.iter().enumerate().all(|(ix, p)| {
 2396                                        p.to_display_point(&display_map).row()
 2397                                            == selections[ix].head().row()
 2398                                    })
 2399                            })
 2400                            .unwrap_or(false);
 2401                        let new_positions = selections
 2402                            .into_iter()
 2403                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2404                            .collect();
 2405                        editor
 2406                            .change_list
 2407                            .push_to_change_list(pop_state, new_positions);
 2408                    }
 2409                }
 2410                _ => (),
 2411            },
 2412        ));
 2413
 2414        if let Some(dap_store) = editor
 2415            .project
 2416            .as_ref()
 2417            .map(|project| project.read(cx).dap_store())
 2418        {
 2419            let weak_editor = cx.weak_entity();
 2420
 2421            editor
 2422                ._subscriptions
 2423                .push(
 2424                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2425                        let session_entity = cx.entity();
 2426                        weak_editor
 2427                            .update(cx, |editor, cx| {
 2428                                editor._subscriptions.push(
 2429                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2430                                );
 2431                            })
 2432                            .ok();
 2433                    }),
 2434                );
 2435
 2436            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2437                editor
 2438                    ._subscriptions
 2439                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2440            }
 2441        }
 2442
 2443        // skip adding the initial selection to selection history
 2444        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2445        editor.end_selection(window, cx);
 2446        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2447
 2448        editor.scroll_manager.show_scrollbars(window, cx);
 2449        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2450
 2451        if full_mode {
 2452            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2453            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2454
 2455            if editor.git_blame_inline_enabled {
 2456                editor.start_git_blame_inline(false, window, cx);
 2457            }
 2458
 2459            editor.go_to_active_debug_line(window, cx);
 2460
 2461            editor.minimap =
 2462                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2463            editor.colors = Some(LspColorData::new(cx));
 2464            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2465
 2466            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2467                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2468            }
 2469            editor.update_lsp_data(None, window, cx);
 2470            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2471        }
 2472
 2473        editor
 2474    }
 2475
 2476    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2477        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2478    }
 2479
 2480    pub fn deploy_mouse_context_menu(
 2481        &mut self,
 2482        position: gpui::Point<Pixels>,
 2483        context_menu: Entity<ContextMenu>,
 2484        window: &mut Window,
 2485        cx: &mut Context<Self>,
 2486    ) {
 2487        self.mouse_context_menu = Some(MouseContextMenu::new(
 2488            self,
 2489            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2490            context_menu,
 2491            window,
 2492            cx,
 2493        ));
 2494    }
 2495
 2496    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2497        self.mouse_context_menu
 2498            .as_ref()
 2499            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2500    }
 2501
 2502    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2503        if self
 2504            .selections
 2505            .pending_anchor()
 2506            .is_some_and(|pending_selection| {
 2507                let snapshot = self.buffer().read(cx).snapshot(cx);
 2508                pending_selection.range().includes(range, &snapshot)
 2509            })
 2510        {
 2511            return true;
 2512        }
 2513
 2514        self.selections
 2515            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2516            .into_iter()
 2517            .any(|selection| {
 2518                // This is needed to cover a corner case, if we just check for an existing
 2519                // selection in the fold range, having a cursor at the start of the fold
 2520                // marks it as selected. Non-empty selections don't cause this.
 2521                let length = selection.end - selection.start;
 2522                length > 0
 2523            })
 2524    }
 2525
 2526    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2527        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2528    }
 2529
 2530    fn key_context_internal(
 2531        &self,
 2532        has_active_edit_prediction: bool,
 2533        window: &mut Window,
 2534        cx: &mut App,
 2535    ) -> KeyContext {
 2536        let mut key_context = KeyContext::new_with_defaults();
 2537        key_context.add("Editor");
 2538        let mode = match self.mode {
 2539            EditorMode::SingleLine => "single_line",
 2540            EditorMode::AutoHeight { .. } => "auto_height",
 2541            EditorMode::Minimap { .. } => "minimap",
 2542            EditorMode::Full { .. } => "full",
 2543        };
 2544
 2545        if EditorSettings::jupyter_enabled(cx) {
 2546            key_context.add("jupyter");
 2547        }
 2548
 2549        key_context.set("mode", mode);
 2550        if self.pending_rename.is_some() {
 2551            key_context.add("renaming");
 2552        }
 2553
 2554        if let Some(snippet_stack) = self.snippet_stack.last() {
 2555            key_context.add("in_snippet");
 2556
 2557            if snippet_stack.active_index > 0 {
 2558                key_context.add("has_previous_tabstop");
 2559            }
 2560
 2561            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2562                key_context.add("has_next_tabstop");
 2563            }
 2564        }
 2565
 2566        match self.context_menu.borrow().as_ref() {
 2567            Some(CodeContextMenu::Completions(menu)) => {
 2568                if menu.visible() {
 2569                    key_context.add("menu");
 2570                    key_context.add("showing_completions");
 2571                }
 2572            }
 2573            Some(CodeContextMenu::CodeActions(menu)) => {
 2574                if menu.visible() {
 2575                    key_context.add("menu");
 2576                    key_context.add("showing_code_actions")
 2577                }
 2578            }
 2579            None => {}
 2580        }
 2581
 2582        if self.signature_help_state.has_multiple_signatures() {
 2583            key_context.add("showing_signature_help");
 2584        }
 2585
 2586        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2587        if !self.focus_handle(cx).contains_focused(window, cx)
 2588            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2589        {
 2590            for addon in self.addons.values() {
 2591                addon.extend_key_context(&mut key_context, cx)
 2592            }
 2593        }
 2594
 2595        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2596            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2597                Some(
 2598                    file.full_path(cx)
 2599                        .extension()?
 2600                        .to_string_lossy()
 2601                        .into_owned(),
 2602                )
 2603            }) {
 2604                key_context.set("extension", extension);
 2605            }
 2606        } else {
 2607            key_context.add("multibuffer");
 2608        }
 2609
 2610        if has_active_edit_prediction {
 2611            if self.edit_prediction_in_conflict() {
 2612                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2613            } else {
 2614                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2615                key_context.add("copilot_suggestion");
 2616            }
 2617        }
 2618
 2619        if self.selection_mark_mode {
 2620            key_context.add("selection_mode");
 2621        }
 2622
 2623        let disjoint = self.selections.disjoint_anchors();
 2624        let snapshot = self.snapshot(window, cx);
 2625        let snapshot = snapshot.buffer_snapshot();
 2626        if self.mode == EditorMode::SingleLine
 2627            && let [selection] = disjoint
 2628            && selection.start == selection.end
 2629            && selection.end.to_offset(snapshot) == snapshot.len()
 2630        {
 2631            key_context.add("end_of_input");
 2632        }
 2633
 2634        if self.has_any_expanded_diff_hunks(cx) {
 2635            key_context.add("diffs_expanded");
 2636        }
 2637
 2638        key_context
 2639    }
 2640
 2641    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2642        self.last_bounds.as_ref()
 2643    }
 2644
 2645    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2646        if self.mouse_cursor_hidden {
 2647            self.mouse_cursor_hidden = false;
 2648            cx.notify();
 2649        }
 2650    }
 2651
 2652    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2653        let hide_mouse_cursor = match origin {
 2654            HideMouseCursorOrigin::TypingAction => {
 2655                matches!(
 2656                    self.hide_mouse_mode,
 2657                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2658                )
 2659            }
 2660            HideMouseCursorOrigin::MovementAction => {
 2661                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2662            }
 2663        };
 2664        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2665            self.mouse_cursor_hidden = hide_mouse_cursor;
 2666            cx.notify();
 2667        }
 2668    }
 2669
 2670    pub fn edit_prediction_in_conflict(&self) -> bool {
 2671        if !self.show_edit_predictions_in_menu() {
 2672            return false;
 2673        }
 2674
 2675        let showing_completions = self
 2676            .context_menu
 2677            .borrow()
 2678            .as_ref()
 2679            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2680
 2681        showing_completions
 2682            || self.edit_prediction_requires_modifier()
 2683            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2684            // bindings to insert tab characters.
 2685            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2686    }
 2687
 2688    pub fn accept_edit_prediction_keybind(
 2689        &self,
 2690        accept_partial: bool,
 2691        window: &mut Window,
 2692        cx: &mut App,
 2693    ) -> AcceptEditPredictionBinding {
 2694        let key_context = self.key_context_internal(true, window, cx);
 2695        let in_conflict = self.edit_prediction_in_conflict();
 2696
 2697        let bindings = if accept_partial {
 2698            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2699        } else {
 2700            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2701        };
 2702
 2703        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2704        // just the first one.
 2705        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2706            !in_conflict
 2707                || binding
 2708                    .keystrokes()
 2709                    .first()
 2710                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2711        }))
 2712    }
 2713
 2714    pub fn new_file(
 2715        workspace: &mut Workspace,
 2716        _: &workspace::NewFile,
 2717        window: &mut Window,
 2718        cx: &mut Context<Workspace>,
 2719    ) {
 2720        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2721            "Failed to create buffer",
 2722            window,
 2723            cx,
 2724            |e, _, _| match e.error_code() {
 2725                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2726                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2727                e.error_tag("required").unwrap_or("the latest version")
 2728            )),
 2729                _ => None,
 2730            },
 2731        );
 2732    }
 2733
 2734    pub fn new_in_workspace(
 2735        workspace: &mut Workspace,
 2736        window: &mut Window,
 2737        cx: &mut Context<Workspace>,
 2738    ) -> Task<Result<Entity<Editor>>> {
 2739        let project = workspace.project().clone();
 2740        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2741
 2742        cx.spawn_in(window, async move |workspace, cx| {
 2743            let buffer = create.await?;
 2744            workspace.update_in(cx, |workspace, window, cx| {
 2745                let editor =
 2746                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2747                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2748                editor
 2749            })
 2750        })
 2751    }
 2752
 2753    fn new_file_vertical(
 2754        workspace: &mut Workspace,
 2755        _: &workspace::NewFileSplitVertical,
 2756        window: &mut Window,
 2757        cx: &mut Context<Workspace>,
 2758    ) {
 2759        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2760    }
 2761
 2762    fn new_file_horizontal(
 2763        workspace: &mut Workspace,
 2764        _: &workspace::NewFileSplitHorizontal,
 2765        window: &mut Window,
 2766        cx: &mut Context<Workspace>,
 2767    ) {
 2768        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2769    }
 2770
 2771    fn new_file_split(
 2772        workspace: &mut Workspace,
 2773        action: &workspace::NewFileSplit,
 2774        window: &mut Window,
 2775        cx: &mut Context<Workspace>,
 2776    ) {
 2777        Self::new_file_in_direction(workspace, action.0, window, cx)
 2778    }
 2779
 2780    fn new_file_in_direction(
 2781        workspace: &mut Workspace,
 2782        direction: SplitDirection,
 2783        window: &mut Window,
 2784        cx: &mut Context<Workspace>,
 2785    ) {
 2786        let project = workspace.project().clone();
 2787        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2788
 2789        cx.spawn_in(window, async move |workspace, cx| {
 2790            let buffer = create.await?;
 2791            workspace.update_in(cx, move |workspace, window, cx| {
 2792                workspace.split_item(
 2793                    direction,
 2794                    Box::new(
 2795                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2796                    ),
 2797                    window,
 2798                    cx,
 2799                )
 2800            })?;
 2801            anyhow::Ok(())
 2802        })
 2803        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2804            match e.error_code() {
 2805                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2806                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2807                e.error_tag("required").unwrap_or("the latest version")
 2808            )),
 2809                _ => None,
 2810            }
 2811        });
 2812    }
 2813
 2814    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2815        self.leader_id
 2816    }
 2817
 2818    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2819        &self.buffer
 2820    }
 2821
 2822    pub fn project(&self) -> Option<&Entity<Project>> {
 2823        self.project.as_ref()
 2824    }
 2825
 2826    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2827        self.workspace.as_ref()?.0.upgrade()
 2828    }
 2829
 2830    /// Returns the workspace serialization ID if this editor should be serialized.
 2831    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2832        self.workspace
 2833            .as_ref()
 2834            .filter(|_| self.should_serialize_buffer())
 2835            .and_then(|workspace| workspace.1)
 2836    }
 2837
 2838    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2839        self.buffer().read(cx).title(cx)
 2840    }
 2841
 2842    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2843        let git_blame_gutter_max_author_length = self
 2844            .render_git_blame_gutter(cx)
 2845            .then(|| {
 2846                if let Some(blame) = self.blame.as_ref() {
 2847                    let max_author_length =
 2848                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2849                    Some(max_author_length)
 2850                } else {
 2851                    None
 2852                }
 2853            })
 2854            .flatten();
 2855
 2856        EditorSnapshot {
 2857            mode: self.mode.clone(),
 2858            show_gutter: self.show_gutter,
 2859            show_line_numbers: self.show_line_numbers,
 2860            show_git_diff_gutter: self.show_git_diff_gutter,
 2861            show_code_actions: self.show_code_actions,
 2862            show_runnables: self.show_runnables,
 2863            show_breakpoints: self.show_breakpoints,
 2864            git_blame_gutter_max_author_length,
 2865            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2866            placeholder_display_snapshot: self
 2867                .placeholder_display_map
 2868                .as_ref()
 2869                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2870            scroll_anchor: self.scroll_manager.anchor(),
 2871            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2872            is_focused: self.focus_handle.is_focused(window),
 2873            current_line_highlight: self
 2874                .current_line_highlight
 2875                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2876            gutter_hovered: self.gutter_hovered,
 2877        }
 2878    }
 2879
 2880    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2881        self.buffer.read(cx).language_at(point, cx)
 2882    }
 2883
 2884    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2885        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2886    }
 2887
 2888    pub fn active_excerpt(
 2889        &self,
 2890        cx: &App,
 2891    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2892        self.buffer
 2893            .read(cx)
 2894            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2895    }
 2896
 2897    pub fn mode(&self) -> &EditorMode {
 2898        &self.mode
 2899    }
 2900
 2901    pub fn set_mode(&mut self, mode: EditorMode) {
 2902        self.mode = mode;
 2903    }
 2904
 2905    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2906        self.collaboration_hub.as_deref()
 2907    }
 2908
 2909    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2910        self.collaboration_hub = Some(hub);
 2911    }
 2912
 2913    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2914        self.in_project_search = in_project_search;
 2915    }
 2916
 2917    pub fn set_custom_context_menu(
 2918        &mut self,
 2919        f: impl 'static
 2920        + Fn(
 2921            &mut Self,
 2922            DisplayPoint,
 2923            &mut Window,
 2924            &mut Context<Self>,
 2925        ) -> Option<Entity<ui::ContextMenu>>,
 2926    ) {
 2927        self.custom_context_menu = Some(Box::new(f))
 2928    }
 2929
 2930    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2931        self.completion_provider = provider;
 2932    }
 2933
 2934    #[cfg(any(test, feature = "test-support"))]
 2935    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2936        self.completion_provider.clone()
 2937    }
 2938
 2939    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2940        self.semantics_provider.clone()
 2941    }
 2942
 2943    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2944        self.semantics_provider = provider;
 2945    }
 2946
 2947    pub fn set_edit_prediction_provider<T>(
 2948        &mut self,
 2949        provider: Option<Entity<T>>,
 2950        window: &mut Window,
 2951        cx: &mut Context<Self>,
 2952    ) where
 2953        T: EditPredictionProvider,
 2954    {
 2955        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2956            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2957                if this.focus_handle.is_focused(window) {
 2958                    this.update_visible_edit_prediction(window, cx);
 2959                }
 2960            }),
 2961            provider: Arc::new(provider),
 2962        });
 2963        self.update_edit_prediction_settings(cx);
 2964        self.refresh_edit_prediction(false, false, window, cx);
 2965    }
 2966
 2967    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2968        self.placeholder_display_map
 2969            .as_ref()
 2970            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2971    }
 2972
 2973    pub fn set_placeholder_text(
 2974        &mut self,
 2975        placeholder_text: &str,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        let multibuffer = cx
 2980            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2981
 2982        let style = window.text_style();
 2983
 2984        self.placeholder_display_map = Some(cx.new(|cx| {
 2985            DisplayMap::new(
 2986                multibuffer,
 2987                style.font(),
 2988                style.font_size.to_pixels(window.rem_size()),
 2989                None,
 2990                FILE_HEADER_HEIGHT,
 2991                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2992                Default::default(),
 2993                DiagnosticSeverity::Off,
 2994                cx,
 2995            )
 2996        }));
 2997        cx.notify();
 2998    }
 2999
 3000    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3001        self.cursor_shape = cursor_shape;
 3002
 3003        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3004        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3005
 3006        cx.notify();
 3007    }
 3008
 3009    pub fn set_current_line_highlight(
 3010        &mut self,
 3011        current_line_highlight: Option<CurrentLineHighlight>,
 3012    ) {
 3013        self.current_line_highlight = current_line_highlight;
 3014    }
 3015
 3016    pub fn range_for_match<T: std::marker::Copy>(
 3017        &self,
 3018        range: &Range<T>,
 3019        collapse: bool,
 3020    ) -> Range<T> {
 3021        if collapse {
 3022            return range.start..range.start;
 3023        }
 3024        range.clone()
 3025    }
 3026
 3027    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3028        if self.display_map.read(cx).clip_at_line_ends != clip {
 3029            self.display_map
 3030                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3031        }
 3032    }
 3033
 3034    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3035        self.input_enabled = input_enabled;
 3036    }
 3037
 3038    pub fn set_edit_predictions_hidden_for_vim_mode(
 3039        &mut self,
 3040        hidden: bool,
 3041        window: &mut Window,
 3042        cx: &mut Context<Self>,
 3043    ) {
 3044        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3045            self.edit_predictions_hidden_for_vim_mode = hidden;
 3046            if hidden {
 3047                self.update_visible_edit_prediction(window, cx);
 3048            } else {
 3049                self.refresh_edit_prediction(true, false, window, cx);
 3050            }
 3051        }
 3052    }
 3053
 3054    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3055        self.menu_edit_predictions_policy = value;
 3056    }
 3057
 3058    pub fn set_autoindent(&mut self, autoindent: bool) {
 3059        if autoindent {
 3060            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3061        } else {
 3062            self.autoindent_mode = None;
 3063        }
 3064    }
 3065
 3066    pub fn read_only(&self, cx: &App) -> bool {
 3067        self.read_only || self.buffer.read(cx).read_only()
 3068    }
 3069
 3070    pub fn set_read_only(&mut self, read_only: bool) {
 3071        self.read_only = read_only;
 3072    }
 3073
 3074    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3075        self.use_autoclose = autoclose;
 3076    }
 3077
 3078    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3079        self.use_auto_surround = auto_surround;
 3080    }
 3081
 3082    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3083        self.auto_replace_emoji_shortcode = auto_replace;
 3084    }
 3085
 3086    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3087        self.buffer_serialization = should_serialize.then(|| {
 3088            BufferSerialization::new(
 3089                ProjectSettings::get_global(cx)
 3090                    .session
 3091                    .restore_unsaved_buffers,
 3092            )
 3093        })
 3094    }
 3095
 3096    fn should_serialize_buffer(&self) -> bool {
 3097        self.buffer_serialization.is_some()
 3098    }
 3099
 3100    pub fn toggle_edit_predictions(
 3101        &mut self,
 3102        _: &ToggleEditPrediction,
 3103        window: &mut Window,
 3104        cx: &mut Context<Self>,
 3105    ) {
 3106        if self.show_edit_predictions_override.is_some() {
 3107            self.set_show_edit_predictions(None, window, cx);
 3108        } else {
 3109            let show_edit_predictions = !self.edit_predictions_enabled();
 3110            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3111        }
 3112    }
 3113
 3114    pub fn set_show_edit_predictions(
 3115        &mut self,
 3116        show_edit_predictions: Option<bool>,
 3117        window: &mut Window,
 3118        cx: &mut Context<Self>,
 3119    ) {
 3120        self.show_edit_predictions_override = show_edit_predictions;
 3121        self.update_edit_prediction_settings(cx);
 3122
 3123        if let Some(false) = show_edit_predictions {
 3124            self.discard_edit_prediction(false, cx);
 3125        } else {
 3126            self.refresh_edit_prediction(false, true, window, cx);
 3127        }
 3128    }
 3129
 3130    fn edit_predictions_disabled_in_scope(
 3131        &self,
 3132        buffer: &Entity<Buffer>,
 3133        buffer_position: language::Anchor,
 3134        cx: &App,
 3135    ) -> bool {
 3136        let snapshot = buffer.read(cx).snapshot();
 3137        let settings = snapshot.settings_at(buffer_position, cx);
 3138
 3139        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3140            return false;
 3141        };
 3142
 3143        scope.override_name().is_some_and(|scope_name| {
 3144            settings
 3145                .edit_predictions_disabled_in
 3146                .iter()
 3147                .any(|s| s == scope_name)
 3148        })
 3149    }
 3150
 3151    pub fn set_use_modal_editing(&mut self, to: bool) {
 3152        self.use_modal_editing = to;
 3153    }
 3154
 3155    pub fn use_modal_editing(&self) -> bool {
 3156        self.use_modal_editing
 3157    }
 3158
 3159    fn selections_did_change(
 3160        &mut self,
 3161        local: bool,
 3162        old_cursor_position: &Anchor,
 3163        effects: SelectionEffects,
 3164        window: &mut Window,
 3165        cx: &mut Context<Self>,
 3166    ) {
 3167        window.invalidate_character_coordinates();
 3168
 3169        // Copy selections to primary selection buffer
 3170        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3171        if local {
 3172            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3173            let buffer_handle = self.buffer.read(cx).read(cx);
 3174
 3175            let mut text = String::new();
 3176            for (index, selection) in selections.iter().enumerate() {
 3177                let text_for_selection = buffer_handle
 3178                    .text_for_range(selection.start..selection.end)
 3179                    .collect::<String>();
 3180
 3181                text.push_str(&text_for_selection);
 3182                if index != selections.len() - 1 {
 3183                    text.push('\n');
 3184                }
 3185            }
 3186
 3187            if !text.is_empty() {
 3188                cx.write_to_primary(ClipboardItem::new_string(text));
 3189            }
 3190        }
 3191
 3192        let selection_anchors = self.selections.disjoint_anchors_arc();
 3193
 3194        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3195            self.buffer.update(cx, |buffer, cx| {
 3196                buffer.set_active_selections(
 3197                    &selection_anchors,
 3198                    self.selections.line_mode(),
 3199                    self.cursor_shape,
 3200                    cx,
 3201                )
 3202            });
 3203        }
 3204        let display_map = self
 3205            .display_map
 3206            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3207        let buffer = display_map.buffer_snapshot();
 3208        if self.selections.count() == 1 {
 3209            self.add_selections_state = None;
 3210        }
 3211        self.select_next_state = None;
 3212        self.select_prev_state = None;
 3213        self.select_syntax_node_history.try_clear();
 3214        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3215        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3216        self.take_rename(false, window, cx);
 3217
 3218        let newest_selection = self.selections.newest_anchor();
 3219        let new_cursor_position = newest_selection.head();
 3220        let selection_start = newest_selection.start;
 3221
 3222        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3223            self.push_to_nav_history(
 3224                *old_cursor_position,
 3225                Some(new_cursor_position.to_point(buffer)),
 3226                false,
 3227                effects.nav_history == Some(true),
 3228                cx,
 3229            );
 3230        }
 3231
 3232        if local {
 3233            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3234                self.register_buffer(buffer_id, cx);
 3235            }
 3236
 3237            let mut context_menu = self.context_menu.borrow_mut();
 3238            let completion_menu = match context_menu.as_ref() {
 3239                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3240                Some(CodeContextMenu::CodeActions(_)) => {
 3241                    *context_menu = None;
 3242                    None
 3243                }
 3244                None => None,
 3245            };
 3246            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3247            drop(context_menu);
 3248
 3249            if effects.completions
 3250                && let Some(completion_position) = completion_position
 3251            {
 3252                let start_offset = selection_start.to_offset(buffer);
 3253                let position_matches = start_offset == completion_position.to_offset(buffer);
 3254                let continue_showing = if position_matches {
 3255                    if self.snippet_stack.is_empty() {
 3256                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3257                            == Some(CharKind::Word)
 3258                    } else {
 3259                        // Snippet choices can be shown even when the cursor is in whitespace.
 3260                        // Dismissing the menu with actions like backspace is handled by
 3261                        // invalidation regions.
 3262                        true
 3263                    }
 3264                } else {
 3265                    false
 3266                };
 3267
 3268                if continue_showing {
 3269                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3270                } else {
 3271                    self.hide_context_menu(window, cx);
 3272                }
 3273            }
 3274
 3275            hide_hover(self, cx);
 3276
 3277            if old_cursor_position.to_display_point(&display_map).row()
 3278                != new_cursor_position.to_display_point(&display_map).row()
 3279            {
 3280                self.available_code_actions.take();
 3281            }
 3282            self.refresh_code_actions(window, cx);
 3283            self.refresh_document_highlights(cx);
 3284            refresh_linked_ranges(self, window, cx);
 3285
 3286            self.refresh_selected_text_highlights(false, window, cx);
 3287            self.refresh_matching_bracket_highlights(window, cx);
 3288            self.update_visible_edit_prediction(window, cx);
 3289            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3290            self.inline_blame_popover.take();
 3291            if self.git_blame_inline_enabled {
 3292                self.start_inline_blame_timer(window, cx);
 3293            }
 3294        }
 3295
 3296        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3297        cx.emit(EditorEvent::SelectionsChanged { local });
 3298
 3299        let selections = &self.selections.disjoint_anchors_arc();
 3300        if selections.len() == 1 {
 3301            cx.emit(SearchEvent::ActiveMatchChanged)
 3302        }
 3303        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3304            let inmemory_selections = selections
 3305                .iter()
 3306                .map(|s| {
 3307                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3308                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3309                })
 3310                .collect();
 3311            self.update_restoration_data(cx, |data| {
 3312                data.selections = inmemory_selections;
 3313            });
 3314
 3315            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3316                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3317            {
 3318                let snapshot = self.buffer().read(cx).snapshot(cx);
 3319                let selections = selections.clone();
 3320                let background_executor = cx.background_executor().clone();
 3321                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3322                self.serialize_selections = cx.background_spawn(async move {
 3323                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3324                    let db_selections = selections
 3325                        .iter()
 3326                        .map(|selection| {
 3327                            (
 3328                                selection.start.to_offset(&snapshot),
 3329                                selection.end.to_offset(&snapshot),
 3330                            )
 3331                        })
 3332                        .collect();
 3333
 3334                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3335                        .await
 3336                        .with_context(|| {
 3337                            format!(
 3338                                "persisting editor selections for editor {editor_id}, \
 3339                                workspace {workspace_id:?}"
 3340                            )
 3341                        })
 3342                        .log_err();
 3343                });
 3344            }
 3345        }
 3346
 3347        cx.notify();
 3348    }
 3349
 3350    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3351        use text::ToOffset as _;
 3352        use text::ToPoint as _;
 3353
 3354        if self.mode.is_minimap()
 3355            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3356        {
 3357            return;
 3358        }
 3359
 3360        if !self.buffer().read(cx).is_singleton() {
 3361            return;
 3362        }
 3363
 3364        let display_snapshot = self
 3365            .display_map
 3366            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3367        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3368            return;
 3369        };
 3370        let inmemory_folds = display_snapshot
 3371            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3372            .map(|fold| {
 3373                fold.range.start.text_anchor.to_point(&snapshot)
 3374                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3375            })
 3376            .collect();
 3377        self.update_restoration_data(cx, |data| {
 3378            data.folds = inmemory_folds;
 3379        });
 3380
 3381        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3382            return;
 3383        };
 3384        let background_executor = cx.background_executor().clone();
 3385        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3386        let db_folds = display_snapshot
 3387            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3388            .map(|fold| {
 3389                (
 3390                    fold.range.start.text_anchor.to_offset(&snapshot),
 3391                    fold.range.end.text_anchor.to_offset(&snapshot),
 3392                )
 3393            })
 3394            .collect();
 3395        self.serialize_folds = cx.background_spawn(async move {
 3396            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3397            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3398                .await
 3399                .with_context(|| {
 3400                    format!(
 3401                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3402                    )
 3403                })
 3404                .log_err();
 3405        });
 3406    }
 3407
 3408    pub fn sync_selections(
 3409        &mut self,
 3410        other: Entity<Editor>,
 3411        cx: &mut Context<Self>,
 3412    ) -> gpui::Subscription {
 3413        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3414        if !other_selections.is_empty() {
 3415            self.selections
 3416                .change_with(&self.display_snapshot(cx), |selections| {
 3417                    selections.select_anchors(other_selections);
 3418                });
 3419        }
 3420
 3421        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3422            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3423                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3424                if other_selections.is_empty() {
 3425                    return;
 3426                }
 3427                let snapshot = this.display_snapshot(cx);
 3428                this.selections.change_with(&snapshot, |selections| {
 3429                    selections.select_anchors(other_selections);
 3430                });
 3431            }
 3432        });
 3433
 3434        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3435            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3436                let these_selections = this.selections.disjoint_anchors().to_vec();
 3437                if these_selections.is_empty() {
 3438                    return;
 3439                }
 3440                other.update(cx, |other_editor, cx| {
 3441                    let snapshot = other_editor.display_snapshot(cx);
 3442                    other_editor
 3443                        .selections
 3444                        .change_with(&snapshot, |selections| {
 3445                            selections.select_anchors(these_selections);
 3446                        })
 3447                });
 3448            }
 3449        });
 3450
 3451        Subscription::join(other_subscription, this_subscription)
 3452    }
 3453
 3454    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3455        if self.buffer().read(cx).is_singleton() {
 3456            return;
 3457        }
 3458        let snapshot = self.buffer.read(cx).snapshot(cx);
 3459        let buffer_ids: HashSet<BufferId> = self
 3460            .selections
 3461            .disjoint_anchor_ranges()
 3462            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3463            .collect();
 3464        for buffer_id in buffer_ids {
 3465            self.unfold_buffer(buffer_id, cx);
 3466        }
 3467    }
 3468
 3469    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3470    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3471    /// effects of selection change occur at the end of the transaction.
 3472    pub fn change_selections<R>(
 3473        &mut self,
 3474        effects: SelectionEffects,
 3475        window: &mut Window,
 3476        cx: &mut Context<Self>,
 3477        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3478    ) -> R {
 3479        let snapshot = self.display_snapshot(cx);
 3480        if let Some(state) = &mut self.deferred_selection_effects_state {
 3481            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3482            state.effects.completions = effects.completions;
 3483            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3484            let (changed, result) = self.selections.change_with(&snapshot, change);
 3485            state.changed |= changed;
 3486            return result;
 3487        }
 3488        let mut state = DeferredSelectionEffectsState {
 3489            changed: false,
 3490            effects,
 3491            old_cursor_position: self.selections.newest_anchor().head(),
 3492            history_entry: SelectionHistoryEntry {
 3493                selections: self.selections.disjoint_anchors_arc(),
 3494                select_next_state: self.select_next_state.clone(),
 3495                select_prev_state: self.select_prev_state.clone(),
 3496                add_selections_state: self.add_selections_state.clone(),
 3497            },
 3498        };
 3499        let (changed, result) = self.selections.change_with(&snapshot, change);
 3500        state.changed = state.changed || changed;
 3501        if self.defer_selection_effects {
 3502            self.deferred_selection_effects_state = Some(state);
 3503        } else {
 3504            self.apply_selection_effects(state, window, cx);
 3505        }
 3506        result
 3507    }
 3508
 3509    /// Defers the effects of selection change, so that the effects of multiple calls to
 3510    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3511    /// to selection history and the state of popovers based on selection position aren't
 3512    /// erroneously updated.
 3513    pub fn with_selection_effects_deferred<R>(
 3514        &mut self,
 3515        window: &mut Window,
 3516        cx: &mut Context<Self>,
 3517        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3518    ) -> R {
 3519        let already_deferred = self.defer_selection_effects;
 3520        self.defer_selection_effects = true;
 3521        let result = update(self, window, cx);
 3522        if !already_deferred {
 3523            self.defer_selection_effects = false;
 3524            if let Some(state) = self.deferred_selection_effects_state.take() {
 3525                self.apply_selection_effects(state, window, cx);
 3526            }
 3527        }
 3528        result
 3529    }
 3530
 3531    fn apply_selection_effects(
 3532        &mut self,
 3533        state: DeferredSelectionEffectsState,
 3534        window: &mut Window,
 3535        cx: &mut Context<Self>,
 3536    ) {
 3537        if state.changed {
 3538            self.selection_history.push(state.history_entry);
 3539
 3540            if let Some(autoscroll) = state.effects.scroll {
 3541                self.request_autoscroll(autoscroll, cx);
 3542            }
 3543
 3544            let old_cursor_position = &state.old_cursor_position;
 3545
 3546            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3547
 3548            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3549                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3550            }
 3551        }
 3552    }
 3553
 3554    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3555    where
 3556        I: IntoIterator<Item = (Range<S>, T)>,
 3557        S: ToOffset,
 3558        T: Into<Arc<str>>,
 3559    {
 3560        if self.read_only(cx) {
 3561            return;
 3562        }
 3563
 3564        self.buffer
 3565            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3566    }
 3567
 3568    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3569    where
 3570        I: IntoIterator<Item = (Range<S>, T)>,
 3571        S: ToOffset,
 3572        T: Into<Arc<str>>,
 3573    {
 3574        if self.read_only(cx) {
 3575            return;
 3576        }
 3577
 3578        self.buffer.update(cx, |buffer, cx| {
 3579            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3580        });
 3581    }
 3582
 3583    pub fn edit_with_block_indent<I, S, T>(
 3584        &mut self,
 3585        edits: I,
 3586        original_indent_columns: Vec<Option<u32>>,
 3587        cx: &mut Context<Self>,
 3588    ) where
 3589        I: IntoIterator<Item = (Range<S>, T)>,
 3590        S: ToOffset,
 3591        T: Into<Arc<str>>,
 3592    {
 3593        if self.read_only(cx) {
 3594            return;
 3595        }
 3596
 3597        self.buffer.update(cx, |buffer, cx| {
 3598            buffer.edit(
 3599                edits,
 3600                Some(AutoindentMode::Block {
 3601                    original_indent_columns,
 3602                }),
 3603                cx,
 3604            )
 3605        });
 3606    }
 3607
 3608    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3609        self.hide_context_menu(window, cx);
 3610
 3611        match phase {
 3612            SelectPhase::Begin {
 3613                position,
 3614                add,
 3615                click_count,
 3616            } => self.begin_selection(position, add, click_count, window, cx),
 3617            SelectPhase::BeginColumnar {
 3618                position,
 3619                goal_column,
 3620                reset,
 3621                mode,
 3622            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3623            SelectPhase::Extend {
 3624                position,
 3625                click_count,
 3626            } => self.extend_selection(position, click_count, window, cx),
 3627            SelectPhase::Update {
 3628                position,
 3629                goal_column,
 3630                scroll_delta,
 3631            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3632            SelectPhase::End => self.end_selection(window, cx),
 3633        }
 3634    }
 3635
 3636    fn extend_selection(
 3637        &mut self,
 3638        position: DisplayPoint,
 3639        click_count: usize,
 3640        window: &mut Window,
 3641        cx: &mut Context<Self>,
 3642    ) {
 3643        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3644        let tail = self.selections.newest::<usize>(&display_map).tail();
 3645        let click_count = click_count.max(match self.selections.select_mode() {
 3646            SelectMode::Character => 1,
 3647            SelectMode::Word(_) => 2,
 3648            SelectMode::Line(_) => 3,
 3649            SelectMode::All => 4,
 3650        });
 3651        self.begin_selection(position, false, click_count, window, cx);
 3652
 3653        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3654
 3655        let current_selection = match self.selections.select_mode() {
 3656            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3657            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3658        };
 3659
 3660        let mut pending_selection = self
 3661            .selections
 3662            .pending_anchor()
 3663            .cloned()
 3664            .expect("extend_selection not called with pending selection");
 3665
 3666        if pending_selection
 3667            .start
 3668            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3669            == Ordering::Greater
 3670        {
 3671            pending_selection.start = current_selection.start;
 3672        }
 3673        if pending_selection
 3674            .end
 3675            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3676            == Ordering::Less
 3677        {
 3678            pending_selection.end = current_selection.end;
 3679            pending_selection.reversed = true;
 3680        }
 3681
 3682        let mut pending_mode = self.selections.pending_mode().unwrap();
 3683        match &mut pending_mode {
 3684            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3685            _ => {}
 3686        }
 3687
 3688        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3689            SelectionEffects::scroll(Autoscroll::fit())
 3690        } else {
 3691            SelectionEffects::no_scroll()
 3692        };
 3693
 3694        self.change_selections(effects, window, cx, |s| {
 3695            s.set_pending(pending_selection.clone(), pending_mode);
 3696            s.set_is_extending(true);
 3697        });
 3698    }
 3699
 3700    fn begin_selection(
 3701        &mut self,
 3702        position: DisplayPoint,
 3703        add: bool,
 3704        click_count: usize,
 3705        window: &mut Window,
 3706        cx: &mut Context<Self>,
 3707    ) {
 3708        if !self.focus_handle.is_focused(window) {
 3709            self.last_focused_descendant = None;
 3710            window.focus(&self.focus_handle);
 3711        }
 3712
 3713        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3714        let buffer = display_map.buffer_snapshot();
 3715        let position = display_map.clip_point(position, Bias::Left);
 3716
 3717        let start;
 3718        let end;
 3719        let mode;
 3720        let mut auto_scroll;
 3721        match click_count {
 3722            1 => {
 3723                start = buffer.anchor_before(position.to_point(&display_map));
 3724                end = start;
 3725                mode = SelectMode::Character;
 3726                auto_scroll = true;
 3727            }
 3728            2 => {
 3729                let position = display_map
 3730                    .clip_point(position, Bias::Left)
 3731                    .to_offset(&display_map, Bias::Left);
 3732                let (range, _) = buffer.surrounding_word(position, None);
 3733                start = buffer.anchor_before(range.start);
 3734                end = buffer.anchor_before(range.end);
 3735                mode = SelectMode::Word(start..end);
 3736                auto_scroll = true;
 3737            }
 3738            3 => {
 3739                let position = display_map
 3740                    .clip_point(position, Bias::Left)
 3741                    .to_point(&display_map);
 3742                let line_start = display_map.prev_line_boundary(position).0;
 3743                let next_line_start = buffer.clip_point(
 3744                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3745                    Bias::Left,
 3746                );
 3747                start = buffer.anchor_before(line_start);
 3748                end = buffer.anchor_before(next_line_start);
 3749                mode = SelectMode::Line(start..end);
 3750                auto_scroll = true;
 3751            }
 3752            _ => {
 3753                start = buffer.anchor_before(0);
 3754                end = buffer.anchor_before(buffer.len());
 3755                mode = SelectMode::All;
 3756                auto_scroll = false;
 3757            }
 3758        }
 3759        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3760
 3761        let point_to_delete: Option<usize> = {
 3762            let selected_points: Vec<Selection<Point>> =
 3763                self.selections.disjoint_in_range(start..end, &display_map);
 3764
 3765            if !add || click_count > 1 {
 3766                None
 3767            } else if !selected_points.is_empty() {
 3768                Some(selected_points[0].id)
 3769            } else {
 3770                let clicked_point_already_selected =
 3771                    self.selections.disjoint_anchors().iter().find(|selection| {
 3772                        selection.start.to_point(buffer) == start.to_point(buffer)
 3773                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3774                    });
 3775
 3776                clicked_point_already_selected.map(|selection| selection.id)
 3777            }
 3778        };
 3779
 3780        let selections_count = self.selections.count();
 3781        let effects = if auto_scroll {
 3782            SelectionEffects::default()
 3783        } else {
 3784            SelectionEffects::no_scroll()
 3785        };
 3786
 3787        self.change_selections(effects, window, cx, |s| {
 3788            if let Some(point_to_delete) = point_to_delete {
 3789                s.delete(point_to_delete);
 3790
 3791                if selections_count == 1 {
 3792                    s.set_pending_anchor_range(start..end, mode);
 3793                }
 3794            } else {
 3795                if !add {
 3796                    s.clear_disjoint();
 3797                }
 3798
 3799                s.set_pending_anchor_range(start..end, mode);
 3800            }
 3801        });
 3802    }
 3803
 3804    fn begin_columnar_selection(
 3805        &mut self,
 3806        position: DisplayPoint,
 3807        goal_column: u32,
 3808        reset: bool,
 3809        mode: ColumnarMode,
 3810        window: &mut Window,
 3811        cx: &mut Context<Self>,
 3812    ) {
 3813        if !self.focus_handle.is_focused(window) {
 3814            self.last_focused_descendant = None;
 3815            window.focus(&self.focus_handle);
 3816        }
 3817
 3818        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3819
 3820        if reset {
 3821            let pointer_position = display_map
 3822                .buffer_snapshot()
 3823                .anchor_before(position.to_point(&display_map));
 3824
 3825            self.change_selections(
 3826                SelectionEffects::scroll(Autoscroll::newest()),
 3827                window,
 3828                cx,
 3829                |s| {
 3830                    s.clear_disjoint();
 3831                    s.set_pending_anchor_range(
 3832                        pointer_position..pointer_position,
 3833                        SelectMode::Character,
 3834                    );
 3835                },
 3836            );
 3837        };
 3838
 3839        let tail = self.selections.newest::<Point>(&display_map).tail();
 3840        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3841        self.columnar_selection_state = match mode {
 3842            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3843                selection_tail: selection_anchor,
 3844                display_point: if reset {
 3845                    if position.column() != goal_column {
 3846                        Some(DisplayPoint::new(position.row(), goal_column))
 3847                    } else {
 3848                        None
 3849                    }
 3850                } else {
 3851                    None
 3852                },
 3853            }),
 3854            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3855                selection_tail: selection_anchor,
 3856            }),
 3857        };
 3858
 3859        if !reset {
 3860            self.select_columns(position, goal_column, &display_map, window, cx);
 3861        }
 3862    }
 3863
 3864    fn update_selection(
 3865        &mut self,
 3866        position: DisplayPoint,
 3867        goal_column: u32,
 3868        scroll_delta: gpui::Point<f32>,
 3869        window: &mut Window,
 3870        cx: &mut Context<Self>,
 3871    ) {
 3872        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3873
 3874        if self.columnar_selection_state.is_some() {
 3875            self.select_columns(position, goal_column, &display_map, window, cx);
 3876        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3877            let buffer = display_map.buffer_snapshot();
 3878            let head;
 3879            let tail;
 3880            let mode = self.selections.pending_mode().unwrap();
 3881            match &mode {
 3882                SelectMode::Character => {
 3883                    head = position.to_point(&display_map);
 3884                    tail = pending.tail().to_point(buffer);
 3885                }
 3886                SelectMode::Word(original_range) => {
 3887                    let offset = display_map
 3888                        .clip_point(position, Bias::Left)
 3889                        .to_offset(&display_map, Bias::Left);
 3890                    let original_range = original_range.to_offset(buffer);
 3891
 3892                    let head_offset = if buffer.is_inside_word(offset, None)
 3893                        || original_range.contains(&offset)
 3894                    {
 3895                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3896                        if word_range.start < original_range.start {
 3897                            word_range.start
 3898                        } else {
 3899                            word_range.end
 3900                        }
 3901                    } else {
 3902                        offset
 3903                    };
 3904
 3905                    head = head_offset.to_point(buffer);
 3906                    if head_offset <= original_range.start {
 3907                        tail = original_range.end.to_point(buffer);
 3908                    } else {
 3909                        tail = original_range.start.to_point(buffer);
 3910                    }
 3911                }
 3912                SelectMode::Line(original_range) => {
 3913                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3914
 3915                    let position = display_map
 3916                        .clip_point(position, Bias::Left)
 3917                        .to_point(&display_map);
 3918                    let line_start = display_map.prev_line_boundary(position).0;
 3919                    let next_line_start = buffer.clip_point(
 3920                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3921                        Bias::Left,
 3922                    );
 3923
 3924                    if line_start < original_range.start {
 3925                        head = line_start
 3926                    } else {
 3927                        head = next_line_start
 3928                    }
 3929
 3930                    if head <= original_range.start {
 3931                        tail = original_range.end;
 3932                    } else {
 3933                        tail = original_range.start;
 3934                    }
 3935                }
 3936                SelectMode::All => {
 3937                    return;
 3938                }
 3939            };
 3940
 3941            if head < tail {
 3942                pending.start = buffer.anchor_before(head);
 3943                pending.end = buffer.anchor_before(tail);
 3944                pending.reversed = true;
 3945            } else {
 3946                pending.start = buffer.anchor_before(tail);
 3947                pending.end = buffer.anchor_before(head);
 3948                pending.reversed = false;
 3949            }
 3950
 3951            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3952                s.set_pending(pending.clone(), mode);
 3953            });
 3954        } else {
 3955            log::error!("update_selection dispatched with no pending selection");
 3956            return;
 3957        }
 3958
 3959        self.apply_scroll_delta(scroll_delta, window, cx);
 3960        cx.notify();
 3961    }
 3962
 3963    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3964        self.columnar_selection_state.take();
 3965        if let Some(pending_mode) = self.selections.pending_mode() {
 3966            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3967            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3968                s.select(selections);
 3969                s.clear_pending();
 3970                if s.is_extending() {
 3971                    s.set_is_extending(false);
 3972                } else {
 3973                    s.set_select_mode(pending_mode);
 3974                }
 3975            });
 3976        }
 3977    }
 3978
 3979    fn select_columns(
 3980        &mut self,
 3981        head: DisplayPoint,
 3982        goal_column: u32,
 3983        display_map: &DisplaySnapshot,
 3984        window: &mut Window,
 3985        cx: &mut Context<Self>,
 3986    ) {
 3987        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3988            return;
 3989        };
 3990
 3991        let tail = match columnar_state {
 3992            ColumnarSelectionState::FromMouse {
 3993                selection_tail,
 3994                display_point,
 3995            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3996            ColumnarSelectionState::FromSelection { selection_tail } => {
 3997                selection_tail.to_display_point(display_map)
 3998            }
 3999        };
 4000
 4001        let start_row = cmp::min(tail.row(), head.row());
 4002        let end_row = cmp::max(tail.row(), head.row());
 4003        let start_column = cmp::min(tail.column(), goal_column);
 4004        let end_column = cmp::max(tail.column(), goal_column);
 4005        let reversed = start_column < tail.column();
 4006
 4007        let selection_ranges = (start_row.0..=end_row.0)
 4008            .map(DisplayRow)
 4009            .filter_map(|row| {
 4010                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4011                    || start_column <= display_map.line_len(row))
 4012                    && !display_map.is_block_line(row)
 4013                {
 4014                    let start = display_map
 4015                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4016                        .to_point(display_map);
 4017                    let end = display_map
 4018                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4019                        .to_point(display_map);
 4020                    if reversed {
 4021                        Some(end..start)
 4022                    } else {
 4023                        Some(start..end)
 4024                    }
 4025                } else {
 4026                    None
 4027                }
 4028            })
 4029            .collect::<Vec<_>>();
 4030        if selection_ranges.is_empty() {
 4031            return;
 4032        }
 4033
 4034        let ranges = match columnar_state {
 4035            ColumnarSelectionState::FromMouse { .. } => {
 4036                let mut non_empty_ranges = selection_ranges
 4037                    .iter()
 4038                    .filter(|selection_range| selection_range.start != selection_range.end)
 4039                    .peekable();
 4040                if non_empty_ranges.peek().is_some() {
 4041                    non_empty_ranges.cloned().collect()
 4042                } else {
 4043                    selection_ranges
 4044                }
 4045            }
 4046            _ => selection_ranges,
 4047        };
 4048
 4049        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4050            s.select_ranges(ranges);
 4051        });
 4052        cx.notify();
 4053    }
 4054
 4055    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4056        self.selections
 4057            .all_adjusted(snapshot)
 4058            .iter()
 4059            .any(|selection| !selection.is_empty())
 4060    }
 4061
 4062    pub fn has_pending_nonempty_selection(&self) -> bool {
 4063        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4064            Some(Selection { start, end, .. }) => start != end,
 4065            None => false,
 4066        };
 4067
 4068        pending_nonempty_selection
 4069            || (self.columnar_selection_state.is_some()
 4070                && self.selections.disjoint_anchors().len() > 1)
 4071    }
 4072
 4073    pub fn has_pending_selection(&self) -> bool {
 4074        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4075    }
 4076
 4077    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4078        self.selection_mark_mode = false;
 4079        self.selection_drag_state = SelectionDragState::None;
 4080
 4081        if self.dismiss_menus_and_popups(true, window, cx) {
 4082            cx.notify();
 4083            return;
 4084        }
 4085        if self.clear_expanded_diff_hunks(cx) {
 4086            cx.notify();
 4087            return;
 4088        }
 4089        if self.show_git_blame_gutter {
 4090            self.show_git_blame_gutter = false;
 4091            cx.notify();
 4092            return;
 4093        }
 4094
 4095        if self.mode.is_full()
 4096            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4097        {
 4098            cx.notify();
 4099            return;
 4100        }
 4101
 4102        cx.propagate();
 4103    }
 4104
 4105    pub fn dismiss_menus_and_popups(
 4106        &mut self,
 4107        is_user_requested: bool,
 4108        window: &mut Window,
 4109        cx: &mut Context<Self>,
 4110    ) -> bool {
 4111        if self.take_rename(false, window, cx).is_some() {
 4112            return true;
 4113        }
 4114
 4115        if self.hide_blame_popover(true, cx) {
 4116            return true;
 4117        }
 4118
 4119        if hide_hover(self, cx) {
 4120            return true;
 4121        }
 4122
 4123        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4124            return true;
 4125        }
 4126
 4127        if self.hide_context_menu(window, cx).is_some() {
 4128            return true;
 4129        }
 4130
 4131        if self.mouse_context_menu.take().is_some() {
 4132            return true;
 4133        }
 4134
 4135        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4136            return true;
 4137        }
 4138
 4139        if self.snippet_stack.pop().is_some() {
 4140            return true;
 4141        }
 4142
 4143        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4144            self.dismiss_diagnostics(cx);
 4145            return true;
 4146        }
 4147
 4148        false
 4149    }
 4150
 4151    fn linked_editing_ranges_for(
 4152        &self,
 4153        selection: Range<text::Anchor>,
 4154        cx: &App,
 4155    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4156        if self.linked_edit_ranges.is_empty() {
 4157            return None;
 4158        }
 4159        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4160            selection.end.buffer_id.and_then(|end_buffer_id| {
 4161                if selection.start.buffer_id != Some(end_buffer_id) {
 4162                    return None;
 4163                }
 4164                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4165                let snapshot = buffer.read(cx).snapshot();
 4166                self.linked_edit_ranges
 4167                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4168                    .map(|ranges| (ranges, snapshot, buffer))
 4169            })?;
 4170        use text::ToOffset as TO;
 4171        // find offset from the start of current range to current cursor position
 4172        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4173
 4174        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4175        let start_difference = start_offset - start_byte_offset;
 4176        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4177        let end_difference = end_offset - start_byte_offset;
 4178        // Current range has associated linked ranges.
 4179        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4180        for range in linked_ranges.iter() {
 4181            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4182            let end_offset = start_offset + end_difference;
 4183            let start_offset = start_offset + start_difference;
 4184            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4185                continue;
 4186            }
 4187            if self.selections.disjoint_anchor_ranges().any(|s| {
 4188                if s.start.buffer_id != selection.start.buffer_id
 4189                    || s.end.buffer_id != selection.end.buffer_id
 4190                {
 4191                    return false;
 4192                }
 4193                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4194                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4195            }) {
 4196                continue;
 4197            }
 4198            let start = buffer_snapshot.anchor_after(start_offset);
 4199            let end = buffer_snapshot.anchor_after(end_offset);
 4200            linked_edits
 4201                .entry(buffer.clone())
 4202                .or_default()
 4203                .push(start..end);
 4204        }
 4205        Some(linked_edits)
 4206    }
 4207
 4208    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4209        let text: Arc<str> = text.into();
 4210
 4211        if self.read_only(cx) {
 4212            return;
 4213        }
 4214
 4215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4216
 4217        self.unfold_buffers_with_selections(cx);
 4218
 4219        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4220        let mut bracket_inserted = false;
 4221        let mut edits = Vec::new();
 4222        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4223        let mut new_selections = Vec::with_capacity(selections.len());
 4224        let mut new_autoclose_regions = Vec::new();
 4225        let snapshot = self.buffer.read(cx).read(cx);
 4226        let mut clear_linked_edit_ranges = false;
 4227
 4228        for (selection, autoclose_region) in
 4229            self.selections_with_autoclose_regions(selections, &snapshot)
 4230        {
 4231            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4232                // Determine if the inserted text matches the opening or closing
 4233                // bracket of any of this language's bracket pairs.
 4234                let mut bracket_pair = None;
 4235                let mut is_bracket_pair_start = false;
 4236                let mut is_bracket_pair_end = false;
 4237                if !text.is_empty() {
 4238                    let mut bracket_pair_matching_end = None;
 4239                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4240                    //  and they are removing the character that triggered IME popup.
 4241                    for (pair, enabled) in scope.brackets() {
 4242                        if !pair.close && !pair.surround {
 4243                            continue;
 4244                        }
 4245
 4246                        if enabled && pair.start.ends_with(text.as_ref()) {
 4247                            let prefix_len = pair.start.len() - text.len();
 4248                            let preceding_text_matches_prefix = prefix_len == 0
 4249                                || (selection.start.column >= (prefix_len as u32)
 4250                                    && snapshot.contains_str_at(
 4251                                        Point::new(
 4252                                            selection.start.row,
 4253                                            selection.start.column - (prefix_len as u32),
 4254                                        ),
 4255                                        &pair.start[..prefix_len],
 4256                                    ));
 4257                            if preceding_text_matches_prefix {
 4258                                bracket_pair = Some(pair.clone());
 4259                                is_bracket_pair_start = true;
 4260                                break;
 4261                            }
 4262                        }
 4263                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4264                        {
 4265                            // take first bracket pair matching end, but don't break in case a later bracket
 4266                            // pair matches start
 4267                            bracket_pair_matching_end = Some(pair.clone());
 4268                        }
 4269                    }
 4270                    if let Some(end) = bracket_pair_matching_end
 4271                        && bracket_pair.is_none()
 4272                    {
 4273                        bracket_pair = Some(end);
 4274                        is_bracket_pair_end = true;
 4275                    }
 4276                }
 4277
 4278                if let Some(bracket_pair) = bracket_pair {
 4279                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4280                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4281                    let auto_surround =
 4282                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4283                    if selection.is_empty() {
 4284                        if is_bracket_pair_start {
 4285                            // If the inserted text is a suffix of an opening bracket and the
 4286                            // selection is preceded by the rest of the opening bracket, then
 4287                            // insert the closing bracket.
 4288                            let following_text_allows_autoclose = snapshot
 4289                                .chars_at(selection.start)
 4290                                .next()
 4291                                .is_none_or(|c| scope.should_autoclose_before(c));
 4292
 4293                            let preceding_text_allows_autoclose = selection.start.column == 0
 4294                                || snapshot
 4295                                    .reversed_chars_at(selection.start)
 4296                                    .next()
 4297                                    .is_none_or(|c| {
 4298                                        bracket_pair.start != bracket_pair.end
 4299                                            || !snapshot
 4300                                                .char_classifier_at(selection.start)
 4301                                                .is_word(c)
 4302                                    });
 4303
 4304                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4305                                && bracket_pair.start.len() == 1
 4306                            {
 4307                                let target = bracket_pair.start.chars().next().unwrap();
 4308                                let current_line_count = snapshot
 4309                                    .reversed_chars_at(selection.start)
 4310                                    .take_while(|&c| c != '\n')
 4311                                    .filter(|&c| c == target)
 4312                                    .count();
 4313                                current_line_count % 2 == 1
 4314                            } else {
 4315                                false
 4316                            };
 4317
 4318                            if autoclose
 4319                                && bracket_pair.close
 4320                                && following_text_allows_autoclose
 4321                                && preceding_text_allows_autoclose
 4322                                && !is_closing_quote
 4323                            {
 4324                                let anchor = snapshot.anchor_before(selection.end);
 4325                                new_selections.push((selection.map(|_| anchor), text.len()));
 4326                                new_autoclose_regions.push((
 4327                                    anchor,
 4328                                    text.len(),
 4329                                    selection.id,
 4330                                    bracket_pair.clone(),
 4331                                ));
 4332                                edits.push((
 4333                                    selection.range(),
 4334                                    format!("{}{}", text, bracket_pair.end).into(),
 4335                                ));
 4336                                bracket_inserted = true;
 4337                                continue;
 4338                            }
 4339                        }
 4340
 4341                        if let Some(region) = autoclose_region {
 4342                            // If the selection is followed by an auto-inserted closing bracket,
 4343                            // then don't insert that closing bracket again; just move the selection
 4344                            // past the closing bracket.
 4345                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4346                                && text.as_ref() == region.pair.end.as_str()
 4347                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4348                            if should_skip {
 4349                                let anchor = snapshot.anchor_after(selection.end);
 4350                                new_selections
 4351                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4352                                continue;
 4353                            }
 4354                        }
 4355
 4356                        let always_treat_brackets_as_autoclosed = snapshot
 4357                            .language_settings_at(selection.start, cx)
 4358                            .always_treat_brackets_as_autoclosed;
 4359                        if always_treat_brackets_as_autoclosed
 4360                            && is_bracket_pair_end
 4361                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4362                        {
 4363                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4364                            // and the inserted text is a closing bracket and the selection is followed
 4365                            // by the closing bracket then move the selection past the closing bracket.
 4366                            let anchor = snapshot.anchor_after(selection.end);
 4367                            new_selections.push((selection.map(|_| anchor), text.len()));
 4368                            continue;
 4369                        }
 4370                    }
 4371                    // If an opening bracket is 1 character long and is typed while
 4372                    // text is selected, then surround that text with the bracket pair.
 4373                    else if auto_surround
 4374                        && bracket_pair.surround
 4375                        && is_bracket_pair_start
 4376                        && bracket_pair.start.chars().count() == 1
 4377                    {
 4378                        edits.push((selection.start..selection.start, text.clone()));
 4379                        edits.push((
 4380                            selection.end..selection.end,
 4381                            bracket_pair.end.as_str().into(),
 4382                        ));
 4383                        bracket_inserted = true;
 4384                        new_selections.push((
 4385                            Selection {
 4386                                id: selection.id,
 4387                                start: snapshot.anchor_after(selection.start),
 4388                                end: snapshot.anchor_before(selection.end),
 4389                                reversed: selection.reversed,
 4390                                goal: selection.goal,
 4391                            },
 4392                            0,
 4393                        ));
 4394                        continue;
 4395                    }
 4396                }
 4397            }
 4398
 4399            if self.auto_replace_emoji_shortcode
 4400                && selection.is_empty()
 4401                && text.as_ref().ends_with(':')
 4402                && let Some(possible_emoji_short_code) =
 4403                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4404                && !possible_emoji_short_code.is_empty()
 4405                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4406            {
 4407                let emoji_shortcode_start = Point::new(
 4408                    selection.start.row,
 4409                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4410                );
 4411
 4412                // Remove shortcode from buffer
 4413                edits.push((
 4414                    emoji_shortcode_start..selection.start,
 4415                    "".to_string().into(),
 4416                ));
 4417                new_selections.push((
 4418                    Selection {
 4419                        id: selection.id,
 4420                        start: snapshot.anchor_after(emoji_shortcode_start),
 4421                        end: snapshot.anchor_before(selection.start),
 4422                        reversed: selection.reversed,
 4423                        goal: selection.goal,
 4424                    },
 4425                    0,
 4426                ));
 4427
 4428                // Insert emoji
 4429                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4430                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4431                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4432
 4433                continue;
 4434            }
 4435
 4436            // If not handling any auto-close operation, then just replace the selected
 4437            // text with the given input and move the selection to the end of the
 4438            // newly inserted text.
 4439            let anchor = snapshot.anchor_after(selection.end);
 4440            if !self.linked_edit_ranges.is_empty() {
 4441                let start_anchor = snapshot.anchor_before(selection.start);
 4442
 4443                let is_word_char = text.chars().next().is_none_or(|char| {
 4444                    let classifier = snapshot
 4445                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4446                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4447                    classifier.is_word(char)
 4448                });
 4449
 4450                if is_word_char {
 4451                    if let Some(ranges) = self
 4452                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4453                    {
 4454                        for (buffer, edits) in ranges {
 4455                            linked_edits
 4456                                .entry(buffer.clone())
 4457                                .or_default()
 4458                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4459                        }
 4460                    }
 4461                } else {
 4462                    clear_linked_edit_ranges = true;
 4463                }
 4464            }
 4465
 4466            new_selections.push((selection.map(|_| anchor), 0));
 4467            edits.push((selection.start..selection.end, text.clone()));
 4468        }
 4469
 4470        drop(snapshot);
 4471
 4472        self.transact(window, cx, |this, window, cx| {
 4473            if clear_linked_edit_ranges {
 4474                this.linked_edit_ranges.clear();
 4475            }
 4476            let initial_buffer_versions =
 4477                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4478
 4479            this.buffer.update(cx, |buffer, cx| {
 4480                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4481            });
 4482            for (buffer, edits) in linked_edits {
 4483                buffer.update(cx, |buffer, cx| {
 4484                    let snapshot = buffer.snapshot();
 4485                    let edits = edits
 4486                        .into_iter()
 4487                        .map(|(range, text)| {
 4488                            use text::ToPoint as TP;
 4489                            let end_point = TP::to_point(&range.end, &snapshot);
 4490                            let start_point = TP::to_point(&range.start, &snapshot);
 4491                            (start_point..end_point, text)
 4492                        })
 4493                        .sorted_by_key(|(range, _)| range.start);
 4494                    buffer.edit(edits, None, cx);
 4495                })
 4496            }
 4497            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4498            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4499            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4500            let new_selections =
 4501                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4502                    .zip(new_selection_deltas)
 4503                    .map(|(selection, delta)| Selection {
 4504                        id: selection.id,
 4505                        start: selection.start + delta,
 4506                        end: selection.end + delta,
 4507                        reversed: selection.reversed,
 4508                        goal: SelectionGoal::None,
 4509                    })
 4510                    .collect::<Vec<_>>();
 4511
 4512            let mut i = 0;
 4513            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4514                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4515                let start = map.buffer_snapshot().anchor_before(position);
 4516                let end = map.buffer_snapshot().anchor_after(position);
 4517                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4518                    match existing_state
 4519                        .range
 4520                        .start
 4521                        .cmp(&start, map.buffer_snapshot())
 4522                    {
 4523                        Ordering::Less => i += 1,
 4524                        Ordering::Greater => break,
 4525                        Ordering::Equal => {
 4526                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4527                                Ordering::Less => i += 1,
 4528                                Ordering::Equal => break,
 4529                                Ordering::Greater => break,
 4530                            }
 4531                        }
 4532                    }
 4533                }
 4534                this.autoclose_regions.insert(
 4535                    i,
 4536                    AutocloseRegion {
 4537                        selection_id,
 4538                        range: start..end,
 4539                        pair,
 4540                    },
 4541                );
 4542            }
 4543
 4544            let had_active_edit_prediction = this.has_active_edit_prediction();
 4545            this.change_selections(
 4546                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4547                window,
 4548                cx,
 4549                |s| s.select(new_selections),
 4550            );
 4551
 4552            if !bracket_inserted
 4553                && let Some(on_type_format_task) =
 4554                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4555            {
 4556                on_type_format_task.detach_and_log_err(cx);
 4557            }
 4558
 4559            let editor_settings = EditorSettings::get_global(cx);
 4560            if bracket_inserted
 4561                && (editor_settings.auto_signature_help
 4562                    || editor_settings.show_signature_help_after_edits)
 4563            {
 4564                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4565            }
 4566
 4567            let trigger_in_words =
 4568                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4569            if this.hard_wrap.is_some() {
 4570                let latest: Range<Point> = this.selections.newest(&map).range();
 4571                if latest.is_empty()
 4572                    && this
 4573                        .buffer()
 4574                        .read(cx)
 4575                        .snapshot(cx)
 4576                        .line_len(MultiBufferRow(latest.start.row))
 4577                        == latest.start.column
 4578                {
 4579                    this.rewrap_impl(
 4580                        RewrapOptions {
 4581                            override_language_settings: true,
 4582                            preserve_existing_whitespace: true,
 4583                        },
 4584                        cx,
 4585                    )
 4586                }
 4587            }
 4588            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4589            refresh_linked_ranges(this, window, cx);
 4590            this.refresh_edit_prediction(true, false, window, cx);
 4591            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4592        });
 4593    }
 4594
 4595    fn find_possible_emoji_shortcode_at_position(
 4596        snapshot: &MultiBufferSnapshot,
 4597        position: Point,
 4598    ) -> Option<String> {
 4599        let mut chars = Vec::new();
 4600        let mut found_colon = false;
 4601        for char in snapshot.reversed_chars_at(position).take(100) {
 4602            // Found a possible emoji shortcode in the middle of the buffer
 4603            if found_colon {
 4604                if char.is_whitespace() {
 4605                    chars.reverse();
 4606                    return Some(chars.iter().collect());
 4607                }
 4608                // If the previous character is not a whitespace, we are in the middle of a word
 4609                // and we only want to complete the shortcode if the word is made up of other emojis
 4610                let mut containing_word = String::new();
 4611                for ch in snapshot
 4612                    .reversed_chars_at(position)
 4613                    .skip(chars.len() + 1)
 4614                    .take(100)
 4615                {
 4616                    if ch.is_whitespace() {
 4617                        break;
 4618                    }
 4619                    containing_word.push(ch);
 4620                }
 4621                let containing_word = containing_word.chars().rev().collect::<String>();
 4622                if util::word_consists_of_emojis(containing_word.as_str()) {
 4623                    chars.reverse();
 4624                    return Some(chars.iter().collect());
 4625                }
 4626            }
 4627
 4628            if char.is_whitespace() || !char.is_ascii() {
 4629                return None;
 4630            }
 4631            if char == ':' {
 4632                found_colon = true;
 4633            } else {
 4634                chars.push(char);
 4635            }
 4636        }
 4637        // Found a possible emoji shortcode at the beginning of the buffer
 4638        chars.reverse();
 4639        Some(chars.iter().collect())
 4640    }
 4641
 4642    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4643        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4644        self.transact(window, cx, |this, window, cx| {
 4645            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4646                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4647                let multi_buffer = this.buffer.read(cx);
 4648                let buffer = multi_buffer.snapshot(cx);
 4649                selections
 4650                    .iter()
 4651                    .map(|selection| {
 4652                        let start_point = selection.start.to_point(&buffer);
 4653                        let mut existing_indent =
 4654                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4655                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4656                        let start = selection.start;
 4657                        let end = selection.end;
 4658                        let selection_is_empty = start == end;
 4659                        let language_scope = buffer.language_scope_at(start);
 4660                        let (
 4661                            comment_delimiter,
 4662                            doc_delimiter,
 4663                            insert_extra_newline,
 4664                            indent_on_newline,
 4665                            indent_on_extra_newline,
 4666                        ) = if let Some(language) = &language_scope {
 4667                            let mut insert_extra_newline =
 4668                                insert_extra_newline_brackets(&buffer, start..end, language)
 4669                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4670
 4671                            // Comment extension on newline is allowed only for cursor selections
 4672                            let comment_delimiter = maybe!({
 4673                                if !selection_is_empty {
 4674                                    return None;
 4675                                }
 4676
 4677                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4678                                    return None;
 4679                                }
 4680
 4681                                let delimiters = language.line_comment_prefixes();
 4682                                let max_len_of_delimiter =
 4683                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4684                                let (snapshot, range) =
 4685                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4686
 4687                                let num_of_whitespaces = snapshot
 4688                                    .chars_for_range(range.clone())
 4689                                    .take_while(|c| c.is_whitespace())
 4690                                    .count();
 4691                                let comment_candidate = snapshot
 4692                                    .chars_for_range(range.clone())
 4693                                    .skip(num_of_whitespaces)
 4694                                    .take(max_len_of_delimiter)
 4695                                    .collect::<String>();
 4696                                let (delimiter, trimmed_len) = delimiters
 4697                                    .iter()
 4698                                    .filter_map(|delimiter| {
 4699                                        let prefix = delimiter.trim_end();
 4700                                        if comment_candidate.starts_with(prefix) {
 4701                                            Some((delimiter, prefix.len()))
 4702                                        } else {
 4703                                            None
 4704                                        }
 4705                                    })
 4706                                    .max_by_key(|(_, len)| *len)?;
 4707
 4708                                if let Some(BlockCommentConfig {
 4709                                    start: block_start, ..
 4710                                }) = language.block_comment()
 4711                                {
 4712                                    let block_start_trimmed = block_start.trim_end();
 4713                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4714                                        let line_content = snapshot
 4715                                            .chars_for_range(range)
 4716                                            .skip(num_of_whitespaces)
 4717                                            .take(block_start_trimmed.len())
 4718                                            .collect::<String>();
 4719
 4720                                        if line_content.starts_with(block_start_trimmed) {
 4721                                            return None;
 4722                                        }
 4723                                    }
 4724                                }
 4725
 4726                                let cursor_is_placed_after_comment_marker =
 4727                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4728                                if cursor_is_placed_after_comment_marker {
 4729                                    Some(delimiter.clone())
 4730                                } else {
 4731                                    None
 4732                                }
 4733                            });
 4734
 4735                            let mut indent_on_newline = IndentSize::spaces(0);
 4736                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4737
 4738                            let doc_delimiter = maybe!({
 4739                                if !selection_is_empty {
 4740                                    return None;
 4741                                }
 4742
 4743                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4744                                    return None;
 4745                                }
 4746
 4747                                let BlockCommentConfig {
 4748                                    start: start_tag,
 4749                                    end: end_tag,
 4750                                    prefix: delimiter,
 4751                                    tab_size: len,
 4752                                } = language.documentation_comment()?;
 4753                                let is_within_block_comment = buffer
 4754                                    .language_scope_at(start_point)
 4755                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4756                                if !is_within_block_comment {
 4757                                    return None;
 4758                                }
 4759
 4760                                let (snapshot, range) =
 4761                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4762
 4763                                let num_of_whitespaces = snapshot
 4764                                    .chars_for_range(range.clone())
 4765                                    .take_while(|c| c.is_whitespace())
 4766                                    .count();
 4767
 4768                                // 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.
 4769                                let column = start_point.column;
 4770                                let cursor_is_after_start_tag = {
 4771                                    let start_tag_len = start_tag.len();
 4772                                    let start_tag_line = snapshot
 4773                                        .chars_for_range(range.clone())
 4774                                        .skip(num_of_whitespaces)
 4775                                        .take(start_tag_len)
 4776                                        .collect::<String>();
 4777                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4778                                        num_of_whitespaces + start_tag_len <= column as usize
 4779                                    } else {
 4780                                        false
 4781                                    }
 4782                                };
 4783
 4784                                let cursor_is_after_delimiter = {
 4785                                    let delimiter_trim = delimiter.trim_end();
 4786                                    let delimiter_line = snapshot
 4787                                        .chars_for_range(range.clone())
 4788                                        .skip(num_of_whitespaces)
 4789                                        .take(delimiter_trim.len())
 4790                                        .collect::<String>();
 4791                                    if delimiter_line.starts_with(delimiter_trim) {
 4792                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4793                                    } else {
 4794                                        false
 4795                                    }
 4796                                };
 4797
 4798                                let cursor_is_before_end_tag_if_exists = {
 4799                                    let mut char_position = 0u32;
 4800                                    let mut end_tag_offset = None;
 4801
 4802                                    'outer: for chunk in snapshot.text_for_range(range) {
 4803                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4804                                            let chars_before_match =
 4805                                                chunk[..byte_pos].chars().count() as u32;
 4806                                            end_tag_offset =
 4807                                                Some(char_position + chars_before_match);
 4808                                            break 'outer;
 4809                                        }
 4810                                        char_position += chunk.chars().count() as u32;
 4811                                    }
 4812
 4813                                    if let Some(end_tag_offset) = end_tag_offset {
 4814                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4815                                        if cursor_is_after_start_tag {
 4816                                            if cursor_is_before_end_tag {
 4817                                                insert_extra_newline = true;
 4818                                            }
 4819                                            let cursor_is_at_start_of_end_tag =
 4820                                                column == end_tag_offset;
 4821                                            if cursor_is_at_start_of_end_tag {
 4822                                                indent_on_extra_newline.len = *len;
 4823                                            }
 4824                                        }
 4825                                        cursor_is_before_end_tag
 4826                                    } else {
 4827                                        true
 4828                                    }
 4829                                };
 4830
 4831                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4832                                    && cursor_is_before_end_tag_if_exists
 4833                                {
 4834                                    if cursor_is_after_start_tag {
 4835                                        indent_on_newline.len = *len;
 4836                                    }
 4837                                    Some(delimiter.clone())
 4838                                } else {
 4839                                    None
 4840                                }
 4841                            });
 4842
 4843                            (
 4844                                comment_delimiter,
 4845                                doc_delimiter,
 4846                                insert_extra_newline,
 4847                                indent_on_newline,
 4848                                indent_on_extra_newline,
 4849                            )
 4850                        } else {
 4851                            (
 4852                                None,
 4853                                None,
 4854                                false,
 4855                                IndentSize::default(),
 4856                                IndentSize::default(),
 4857                            )
 4858                        };
 4859
 4860                        let prevent_auto_indent = doc_delimiter.is_some();
 4861                        let delimiter = comment_delimiter.or(doc_delimiter);
 4862
 4863                        let capacity_for_delimiter =
 4864                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4865                        let mut new_text = String::with_capacity(
 4866                            1 + capacity_for_delimiter
 4867                                + existing_indent.len as usize
 4868                                + indent_on_newline.len as usize
 4869                                + indent_on_extra_newline.len as usize,
 4870                        );
 4871                        new_text.push('\n');
 4872                        new_text.extend(existing_indent.chars());
 4873                        new_text.extend(indent_on_newline.chars());
 4874
 4875                        if let Some(delimiter) = &delimiter {
 4876                            new_text.push_str(delimiter);
 4877                        }
 4878
 4879                        if insert_extra_newline {
 4880                            new_text.push('\n');
 4881                            new_text.extend(existing_indent.chars());
 4882                            new_text.extend(indent_on_extra_newline.chars());
 4883                        }
 4884
 4885                        let anchor = buffer.anchor_after(end);
 4886                        let new_selection = selection.map(|_| anchor);
 4887                        (
 4888                            ((start..end, new_text), prevent_auto_indent),
 4889                            (insert_extra_newline, new_selection),
 4890                        )
 4891                    })
 4892                    .unzip()
 4893            };
 4894
 4895            let mut auto_indent_edits = Vec::new();
 4896            let mut edits = Vec::new();
 4897            for (edit, prevent_auto_indent) in edits_with_flags {
 4898                if prevent_auto_indent {
 4899                    edits.push(edit);
 4900                } else {
 4901                    auto_indent_edits.push(edit);
 4902                }
 4903            }
 4904            if !edits.is_empty() {
 4905                this.edit(edits, cx);
 4906            }
 4907            if !auto_indent_edits.is_empty() {
 4908                this.edit_with_autoindent(auto_indent_edits, cx);
 4909            }
 4910
 4911            let buffer = this.buffer.read(cx).snapshot(cx);
 4912            let new_selections = selection_info
 4913                .into_iter()
 4914                .map(|(extra_newline_inserted, new_selection)| {
 4915                    let mut cursor = new_selection.end.to_point(&buffer);
 4916                    if extra_newline_inserted {
 4917                        cursor.row -= 1;
 4918                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4919                    }
 4920                    new_selection.map(|_| cursor)
 4921                })
 4922                .collect();
 4923
 4924            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4925            this.refresh_edit_prediction(true, false, window, cx);
 4926        });
 4927    }
 4928
 4929    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4931
 4932        let buffer = self.buffer.read(cx);
 4933        let snapshot = buffer.snapshot(cx);
 4934
 4935        let mut edits = Vec::new();
 4936        let mut rows = Vec::new();
 4937
 4938        for (rows_inserted, selection) in self
 4939            .selections
 4940            .all_adjusted(&self.display_snapshot(cx))
 4941            .into_iter()
 4942            .enumerate()
 4943        {
 4944            let cursor = selection.head();
 4945            let row = cursor.row;
 4946
 4947            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4948
 4949            let newline = "\n".to_string();
 4950            edits.push((start_of_line..start_of_line, newline));
 4951
 4952            rows.push(row + rows_inserted as u32);
 4953        }
 4954
 4955        self.transact(window, cx, |editor, window, cx| {
 4956            editor.edit(edits, cx);
 4957
 4958            editor.change_selections(Default::default(), window, cx, |s| {
 4959                let mut index = 0;
 4960                s.move_cursors_with(|map, _, _| {
 4961                    let row = rows[index];
 4962                    index += 1;
 4963
 4964                    let point = Point::new(row, 0);
 4965                    let boundary = map.next_line_boundary(point).1;
 4966                    let clipped = map.clip_point(boundary, Bias::Left);
 4967
 4968                    (clipped, SelectionGoal::None)
 4969                });
 4970            });
 4971
 4972            let mut indent_edits = Vec::new();
 4973            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4974            for row in rows {
 4975                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4976                for (row, indent) in indents {
 4977                    if indent.len == 0 {
 4978                        continue;
 4979                    }
 4980
 4981                    let text = match indent.kind {
 4982                        IndentKind::Space => " ".repeat(indent.len as usize),
 4983                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4984                    };
 4985                    let point = Point::new(row.0, 0);
 4986                    indent_edits.push((point..point, text));
 4987                }
 4988            }
 4989            editor.edit(indent_edits, cx);
 4990        });
 4991    }
 4992
 4993    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4994        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4995
 4996        let buffer = self.buffer.read(cx);
 4997        let snapshot = buffer.snapshot(cx);
 4998
 4999        let mut edits = Vec::new();
 5000        let mut rows = Vec::new();
 5001        let mut rows_inserted = 0;
 5002
 5003        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5004            let cursor = selection.head();
 5005            let row = cursor.row;
 5006
 5007            let point = Point::new(row + 1, 0);
 5008            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5009
 5010            let newline = "\n".to_string();
 5011            edits.push((start_of_line..start_of_line, newline));
 5012
 5013            rows_inserted += 1;
 5014            rows.push(row + rows_inserted);
 5015        }
 5016
 5017        self.transact(window, cx, |editor, window, cx| {
 5018            editor.edit(edits, cx);
 5019
 5020            editor.change_selections(Default::default(), window, cx, |s| {
 5021                let mut index = 0;
 5022                s.move_cursors_with(|map, _, _| {
 5023                    let row = rows[index];
 5024                    index += 1;
 5025
 5026                    let point = Point::new(row, 0);
 5027                    let boundary = map.next_line_boundary(point).1;
 5028                    let clipped = map.clip_point(boundary, Bias::Left);
 5029
 5030                    (clipped, SelectionGoal::None)
 5031                });
 5032            });
 5033
 5034            let mut indent_edits = Vec::new();
 5035            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5036            for row in rows {
 5037                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5038                for (row, indent) in indents {
 5039                    if indent.len == 0 {
 5040                        continue;
 5041                    }
 5042
 5043                    let text = match indent.kind {
 5044                        IndentKind::Space => " ".repeat(indent.len as usize),
 5045                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5046                    };
 5047                    let point = Point::new(row.0, 0);
 5048                    indent_edits.push((point..point, text));
 5049                }
 5050            }
 5051            editor.edit(indent_edits, cx);
 5052        });
 5053    }
 5054
 5055    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5056        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5057            original_indent_columns: Vec::new(),
 5058        });
 5059        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5060    }
 5061
 5062    fn insert_with_autoindent_mode(
 5063        &mut self,
 5064        text: &str,
 5065        autoindent_mode: Option<AutoindentMode>,
 5066        window: &mut Window,
 5067        cx: &mut Context<Self>,
 5068    ) {
 5069        if self.read_only(cx) {
 5070            return;
 5071        }
 5072
 5073        let text: Arc<str> = text.into();
 5074        self.transact(window, cx, |this, window, cx| {
 5075            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5076            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5077                let anchors = {
 5078                    let snapshot = buffer.read(cx);
 5079                    old_selections
 5080                        .iter()
 5081                        .map(|s| {
 5082                            let anchor = snapshot.anchor_after(s.head());
 5083                            s.map(|_| anchor)
 5084                        })
 5085                        .collect::<Vec<_>>()
 5086                };
 5087                buffer.edit(
 5088                    old_selections
 5089                        .iter()
 5090                        .map(|s| (s.start..s.end, text.clone())),
 5091                    autoindent_mode,
 5092                    cx,
 5093                );
 5094                anchors
 5095            });
 5096
 5097            this.change_selections(Default::default(), window, cx, |s| {
 5098                s.select_anchors(selection_anchors);
 5099            });
 5100
 5101            cx.notify();
 5102        });
 5103    }
 5104
 5105    fn trigger_completion_on_input(
 5106        &mut self,
 5107        text: &str,
 5108        trigger_in_words: bool,
 5109        window: &mut Window,
 5110        cx: &mut Context<Self>,
 5111    ) {
 5112        let completions_source = self
 5113            .context_menu
 5114            .borrow()
 5115            .as_ref()
 5116            .and_then(|menu| match menu {
 5117                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5118                CodeContextMenu::CodeActions(_) => None,
 5119            });
 5120
 5121        match completions_source {
 5122            Some(CompletionsMenuSource::Words { .. }) => {
 5123                self.open_or_update_completions_menu(
 5124                    Some(CompletionsMenuSource::Words {
 5125                        ignore_threshold: false,
 5126                    }),
 5127                    None,
 5128                    trigger_in_words,
 5129                    window,
 5130                    cx,
 5131                );
 5132            }
 5133            _ => self.open_or_update_completions_menu(
 5134                None,
 5135                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5136                true,
 5137                window,
 5138                cx,
 5139            ),
 5140        }
 5141    }
 5142
 5143    /// If any empty selections is touching the start of its innermost containing autoclose
 5144    /// region, expand it to select the brackets.
 5145    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5146        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5147        let buffer = self.buffer.read(cx).read(cx);
 5148        let new_selections = self
 5149            .selections_with_autoclose_regions(selections, &buffer)
 5150            .map(|(mut selection, region)| {
 5151                if !selection.is_empty() {
 5152                    return selection;
 5153                }
 5154
 5155                if let Some(region) = region {
 5156                    let mut range = region.range.to_offset(&buffer);
 5157                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5158                        range.start -= region.pair.start.len();
 5159                        if buffer.contains_str_at(range.start, &region.pair.start)
 5160                            && buffer.contains_str_at(range.end, &region.pair.end)
 5161                        {
 5162                            range.end += region.pair.end.len();
 5163                            selection.start = range.start;
 5164                            selection.end = range.end;
 5165
 5166                            return selection;
 5167                        }
 5168                    }
 5169                }
 5170
 5171                let always_treat_brackets_as_autoclosed = buffer
 5172                    .language_settings_at(selection.start, cx)
 5173                    .always_treat_brackets_as_autoclosed;
 5174
 5175                if !always_treat_brackets_as_autoclosed {
 5176                    return selection;
 5177                }
 5178
 5179                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5180                    for (pair, enabled) in scope.brackets() {
 5181                        if !enabled || !pair.close {
 5182                            continue;
 5183                        }
 5184
 5185                        if buffer.contains_str_at(selection.start, &pair.end) {
 5186                            let pair_start_len = pair.start.len();
 5187                            if buffer.contains_str_at(
 5188                                selection.start.saturating_sub(pair_start_len),
 5189                                &pair.start,
 5190                            ) {
 5191                                selection.start -= pair_start_len;
 5192                                selection.end += pair.end.len();
 5193
 5194                                return selection;
 5195                            }
 5196                        }
 5197                    }
 5198                }
 5199
 5200                selection
 5201            })
 5202            .collect();
 5203
 5204        drop(buffer);
 5205        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5206            selections.select(new_selections)
 5207        });
 5208    }
 5209
 5210    /// Iterate the given selections, and for each one, find the smallest surrounding
 5211    /// autoclose region. This uses the ordering of the selections and the autoclose
 5212    /// regions to avoid repeated comparisons.
 5213    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5214        &'a self,
 5215        selections: impl IntoIterator<Item = Selection<D>>,
 5216        buffer: &'a MultiBufferSnapshot,
 5217    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5218        let mut i = 0;
 5219        let mut regions = self.autoclose_regions.as_slice();
 5220        selections.into_iter().map(move |selection| {
 5221            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5222
 5223            let mut enclosing = None;
 5224            while let Some(pair_state) = regions.get(i) {
 5225                if pair_state.range.end.to_offset(buffer) < range.start {
 5226                    regions = &regions[i + 1..];
 5227                    i = 0;
 5228                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5229                    break;
 5230                } else {
 5231                    if pair_state.selection_id == selection.id {
 5232                        enclosing = Some(pair_state);
 5233                    }
 5234                    i += 1;
 5235                }
 5236            }
 5237
 5238            (selection, enclosing)
 5239        })
 5240    }
 5241
 5242    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5243    fn invalidate_autoclose_regions(
 5244        &mut self,
 5245        mut selections: &[Selection<Anchor>],
 5246        buffer: &MultiBufferSnapshot,
 5247    ) {
 5248        self.autoclose_regions.retain(|state| {
 5249            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5250                return false;
 5251            }
 5252
 5253            let mut i = 0;
 5254            while let Some(selection) = selections.get(i) {
 5255                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5256                    selections = &selections[1..];
 5257                    continue;
 5258                }
 5259                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5260                    break;
 5261                }
 5262                if selection.id == state.selection_id {
 5263                    return true;
 5264                } else {
 5265                    i += 1;
 5266                }
 5267            }
 5268            false
 5269        });
 5270    }
 5271
 5272    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5273        let offset = position.to_offset(buffer);
 5274        let (word_range, kind) =
 5275            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5276        if offset > word_range.start && kind == Some(CharKind::Word) {
 5277            Some(
 5278                buffer
 5279                    .text_for_range(word_range.start..offset)
 5280                    .collect::<String>(),
 5281            )
 5282        } else {
 5283            None
 5284        }
 5285    }
 5286
 5287    pub fn visible_excerpts(
 5288        &self,
 5289        cx: &mut Context<Editor>,
 5290    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5291        let Some(project) = self.project() else {
 5292            return HashMap::default();
 5293        };
 5294        let project = project.read(cx);
 5295        let multi_buffer = self.buffer().read(cx);
 5296        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5297        let multi_buffer_visible_start = self
 5298            .scroll_manager
 5299            .anchor()
 5300            .anchor
 5301            .to_point(&multi_buffer_snapshot);
 5302        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5303            multi_buffer_visible_start
 5304                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5305            Bias::Left,
 5306        );
 5307        multi_buffer_snapshot
 5308            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5309            .into_iter()
 5310            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5311            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5312                let buffer_file = project::File::from_dyn(buffer.file())?;
 5313                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5314                let worktree_entry = buffer_worktree
 5315                    .read(cx)
 5316                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5317                if worktree_entry.is_ignored {
 5318                    None
 5319                } else {
 5320                    Some((
 5321                        excerpt_id,
 5322                        (
 5323                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5324                            buffer.version().clone(),
 5325                            excerpt_visible_range,
 5326                        ),
 5327                    ))
 5328                }
 5329            })
 5330            .collect()
 5331    }
 5332
 5333    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5334        TextLayoutDetails {
 5335            text_system: window.text_system().clone(),
 5336            editor_style: self.style.clone().unwrap(),
 5337            rem_size: window.rem_size(),
 5338            scroll_anchor: self.scroll_manager.anchor(),
 5339            visible_rows: self.visible_line_count(),
 5340            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5341        }
 5342    }
 5343
 5344    fn trigger_on_type_formatting(
 5345        &self,
 5346        input: String,
 5347        window: &mut Window,
 5348        cx: &mut Context<Self>,
 5349    ) -> Option<Task<Result<()>>> {
 5350        if input.len() != 1 {
 5351            return None;
 5352        }
 5353
 5354        let project = self.project()?;
 5355        let position = self.selections.newest_anchor().head();
 5356        let (buffer, buffer_position) = self
 5357            .buffer
 5358            .read(cx)
 5359            .text_anchor_for_position(position, cx)?;
 5360
 5361        let settings = language_settings::language_settings(
 5362            buffer
 5363                .read(cx)
 5364                .language_at(buffer_position)
 5365                .map(|l| l.name()),
 5366            buffer.read(cx).file(),
 5367            cx,
 5368        );
 5369        if !settings.use_on_type_format {
 5370            return None;
 5371        }
 5372
 5373        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5374        // hence we do LSP request & edit on host side only — add formats to host's history.
 5375        let push_to_lsp_host_history = true;
 5376        // If this is not the host, append its history with new edits.
 5377        let push_to_client_history = project.read(cx).is_via_collab();
 5378
 5379        let on_type_formatting = project.update(cx, |project, cx| {
 5380            project.on_type_format(
 5381                buffer.clone(),
 5382                buffer_position,
 5383                input,
 5384                push_to_lsp_host_history,
 5385                cx,
 5386            )
 5387        });
 5388        Some(cx.spawn_in(window, async move |editor, cx| {
 5389            if let Some(transaction) = on_type_formatting.await? {
 5390                if push_to_client_history {
 5391                    buffer
 5392                        .update(cx, |buffer, _| {
 5393                            buffer.push_transaction(transaction, Instant::now());
 5394                            buffer.finalize_last_transaction();
 5395                        })
 5396                        .ok();
 5397                }
 5398                editor.update(cx, |editor, cx| {
 5399                    editor.refresh_document_highlights(cx);
 5400                })?;
 5401            }
 5402            Ok(())
 5403        }))
 5404    }
 5405
 5406    pub fn show_word_completions(
 5407        &mut self,
 5408        _: &ShowWordCompletions,
 5409        window: &mut Window,
 5410        cx: &mut Context<Self>,
 5411    ) {
 5412        self.open_or_update_completions_menu(
 5413            Some(CompletionsMenuSource::Words {
 5414                ignore_threshold: true,
 5415            }),
 5416            None,
 5417            false,
 5418            window,
 5419            cx,
 5420        );
 5421    }
 5422
 5423    pub fn show_completions(
 5424        &mut self,
 5425        _: &ShowCompletions,
 5426        window: &mut Window,
 5427        cx: &mut Context<Self>,
 5428    ) {
 5429        self.open_or_update_completions_menu(None, None, false, window, cx);
 5430    }
 5431
 5432    fn open_or_update_completions_menu(
 5433        &mut self,
 5434        requested_source: Option<CompletionsMenuSource>,
 5435        trigger: Option<String>,
 5436        trigger_in_words: bool,
 5437        window: &mut Window,
 5438        cx: &mut Context<Self>,
 5439    ) {
 5440        if self.pending_rename.is_some() {
 5441            return;
 5442        }
 5443
 5444        let completions_source = self
 5445            .context_menu
 5446            .borrow()
 5447            .as_ref()
 5448            .and_then(|menu| match menu {
 5449                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5450                CodeContextMenu::CodeActions(_) => None,
 5451            });
 5452
 5453        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5454
 5455        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5456        // inserted and selected. To handle that case, the start of the selection is used so that
 5457        // the menu starts with all choices.
 5458        let position = self
 5459            .selections
 5460            .newest_anchor()
 5461            .start
 5462            .bias_right(&multibuffer_snapshot);
 5463        if position.diff_base_anchor.is_some() {
 5464            return;
 5465        }
 5466        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5467        let Some(buffer) = buffer_position
 5468            .buffer_id
 5469            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5470        else {
 5471            return;
 5472        };
 5473        let buffer_snapshot = buffer.read(cx).snapshot();
 5474
 5475        let query: Option<Arc<String>> =
 5476            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5477                .map(|query| query.into());
 5478
 5479        drop(multibuffer_snapshot);
 5480
 5481        // Hide the current completions menu when query is empty. Without this, cached
 5482        // completions from before the trigger char may be reused (#32774).
 5483        if query.is_none() {
 5484            let menu_is_open = matches!(
 5485                self.context_menu.borrow().as_ref(),
 5486                Some(CodeContextMenu::Completions(_))
 5487            );
 5488            if menu_is_open {
 5489                self.hide_context_menu(window, cx);
 5490            }
 5491        }
 5492
 5493        let mut ignore_word_threshold = false;
 5494        let provider = match requested_source {
 5495            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5496            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5497                ignore_word_threshold = ignore_threshold;
 5498                None
 5499            }
 5500            Some(CompletionsMenuSource::SnippetChoices)
 5501            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5502                log::error!("bug: SnippetChoices requested_source is not handled");
 5503                None
 5504            }
 5505        };
 5506
 5507        let sort_completions = provider
 5508            .as_ref()
 5509            .is_some_and(|provider| provider.sort_completions());
 5510
 5511        let filter_completions = provider
 5512            .as_ref()
 5513            .is_none_or(|provider| provider.filter_completions());
 5514
 5515        let was_snippets_only = matches!(
 5516            completions_source,
 5517            Some(CompletionsMenuSource::SnippetsOnly)
 5518        );
 5519
 5520        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5521            if filter_completions {
 5522                menu.filter(
 5523                    query.clone().unwrap_or_default(),
 5524                    buffer_position.text_anchor,
 5525                    &buffer,
 5526                    provider.clone(),
 5527                    window,
 5528                    cx,
 5529                );
 5530            }
 5531            // When `is_incomplete` is false, no need to re-query completions when the current query
 5532            // is a suffix of the initial query.
 5533            let was_complete = !menu.is_incomplete;
 5534            if was_complete && !was_snippets_only {
 5535                // If the new query is a suffix of the old query (typing more characters) and
 5536                // the previous result was complete, the existing completions can be filtered.
 5537                //
 5538                // Note that snippet completions are always complete.
 5539                let query_matches = match (&menu.initial_query, &query) {
 5540                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5541                    (None, _) => true,
 5542                    _ => false,
 5543                };
 5544                if query_matches {
 5545                    let position_matches = if menu.initial_position == position {
 5546                        true
 5547                    } else {
 5548                        let snapshot = self.buffer.read(cx).read(cx);
 5549                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5550                    };
 5551                    if position_matches {
 5552                        return;
 5553                    }
 5554                }
 5555            }
 5556        };
 5557
 5558        let Anchor {
 5559            excerpt_id: buffer_excerpt_id,
 5560            text_anchor: buffer_position,
 5561            ..
 5562        } = buffer_position;
 5563
 5564        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5565            buffer_snapshot.surrounding_word(buffer_position, None)
 5566        {
 5567            let word_to_exclude = buffer_snapshot
 5568                .text_for_range(word_range.clone())
 5569                .collect::<String>();
 5570            (
 5571                buffer_snapshot.anchor_before(word_range.start)
 5572                    ..buffer_snapshot.anchor_after(buffer_position),
 5573                Some(word_to_exclude),
 5574            )
 5575        } else {
 5576            (buffer_position..buffer_position, None)
 5577        };
 5578
 5579        let language = buffer_snapshot
 5580            .language_at(buffer_position)
 5581            .map(|language| language.name());
 5582
 5583        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5584            .completions
 5585            .clone();
 5586
 5587        let show_completion_documentation = buffer_snapshot
 5588            .settings_at(buffer_position, cx)
 5589            .show_completion_documentation;
 5590
 5591        // The document can be large, so stay in reasonable bounds when searching for words,
 5592        // otherwise completion pop-up might be slow to appear.
 5593        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5594        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5595        let min_word_search = buffer_snapshot.clip_point(
 5596            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5597            Bias::Left,
 5598        );
 5599        let max_word_search = buffer_snapshot.clip_point(
 5600            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5601            Bias::Right,
 5602        );
 5603        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5604            ..buffer_snapshot.point_to_offset(max_word_search);
 5605
 5606        let skip_digits = query
 5607            .as_ref()
 5608            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5609
 5610        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5611            trigger.as_ref().is_none_or(|trigger| {
 5612                provider.is_completion_trigger(
 5613                    &buffer,
 5614                    position.text_anchor,
 5615                    trigger,
 5616                    trigger_in_words,
 5617                    completions_source.is_some(),
 5618                    cx,
 5619                )
 5620            })
 5621        });
 5622
 5623        let provider_responses = if let Some(provider) = &provider
 5624            && load_provider_completions
 5625        {
 5626            let trigger_character =
 5627                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5628            let completion_context = CompletionContext {
 5629                trigger_kind: match &trigger_character {
 5630                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5631                    None => CompletionTriggerKind::INVOKED,
 5632                },
 5633                trigger_character,
 5634            };
 5635
 5636            provider.completions(
 5637                buffer_excerpt_id,
 5638                &buffer,
 5639                buffer_position,
 5640                completion_context,
 5641                window,
 5642                cx,
 5643            )
 5644        } else {
 5645            Task::ready(Ok(Vec::new()))
 5646        };
 5647
 5648        let load_word_completions = if !self.word_completions_enabled {
 5649            false
 5650        } else if requested_source
 5651            == Some(CompletionsMenuSource::Words {
 5652                ignore_threshold: true,
 5653            })
 5654        {
 5655            true
 5656        } else {
 5657            load_provider_completions
 5658                && completion_settings.words != WordsCompletionMode::Disabled
 5659                && (ignore_word_threshold || {
 5660                    let words_min_length = completion_settings.words_min_length;
 5661                    // check whether word has at least `words_min_length` characters
 5662                    let query_chars = query.iter().flat_map(|q| q.chars());
 5663                    query_chars.take(words_min_length).count() == words_min_length
 5664                })
 5665        };
 5666
 5667        let mut words = if load_word_completions {
 5668            cx.background_spawn({
 5669                let buffer_snapshot = buffer_snapshot.clone();
 5670                async move {
 5671                    buffer_snapshot.words_in_range(WordsQuery {
 5672                        fuzzy_contents: None,
 5673                        range: word_search_range,
 5674                        skip_digits,
 5675                    })
 5676                }
 5677            })
 5678        } else {
 5679            Task::ready(BTreeMap::default())
 5680        };
 5681
 5682        let snippets = if let Some(provider) = &provider
 5683            && provider.show_snippets()
 5684            && let Some(project) = self.project()
 5685        {
 5686            let char_classifier = buffer_snapshot
 5687                .char_classifier_at(buffer_position)
 5688                .scope_context(Some(CharScopeContext::Completion));
 5689            project.update(cx, |project, cx| {
 5690                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5691            })
 5692        } else {
 5693            Task::ready(Ok(CompletionResponse {
 5694                completions: Vec::new(),
 5695                display_options: Default::default(),
 5696                is_incomplete: false,
 5697            }))
 5698        };
 5699
 5700        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5701
 5702        let id = post_inc(&mut self.next_completion_id);
 5703        let task = cx.spawn_in(window, async move |editor, cx| {
 5704            let Ok(()) = editor.update(cx, |this, _| {
 5705                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5706            }) else {
 5707                return;
 5708            };
 5709
 5710            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5711            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5712            let mut completions = Vec::new();
 5713            let mut is_incomplete = false;
 5714            let mut display_options: Option<CompletionDisplayOptions> = None;
 5715            if let Some(provider_responses) = provider_responses.await.log_err()
 5716                && !provider_responses.is_empty()
 5717            {
 5718                for response in provider_responses {
 5719                    completions.extend(response.completions);
 5720                    is_incomplete = is_incomplete || response.is_incomplete;
 5721                    match display_options.as_mut() {
 5722                        None => {
 5723                            display_options = Some(response.display_options);
 5724                        }
 5725                        Some(options) => options.merge(&response.display_options),
 5726                    }
 5727                }
 5728                if completion_settings.words == WordsCompletionMode::Fallback {
 5729                    words = Task::ready(BTreeMap::default());
 5730                }
 5731            }
 5732            let display_options = display_options.unwrap_or_default();
 5733
 5734            let mut words = words.await;
 5735            if let Some(word_to_exclude) = &word_to_exclude {
 5736                words.remove(word_to_exclude);
 5737            }
 5738            for lsp_completion in &completions {
 5739                words.remove(&lsp_completion.new_text);
 5740            }
 5741            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5742                replace_range: word_replace_range.clone(),
 5743                new_text: word.clone(),
 5744                label: CodeLabel::plain(word, None),
 5745                match_start: None,
 5746                snippet_deduplication_key: None,
 5747                icon_path: None,
 5748                documentation: None,
 5749                source: CompletionSource::BufferWord {
 5750                    word_range,
 5751                    resolved: false,
 5752                },
 5753                insert_text_mode: Some(InsertTextMode::AS_IS),
 5754                confirm: None,
 5755            }));
 5756
 5757            completions.extend(
 5758                snippets
 5759                    .await
 5760                    .into_iter()
 5761                    .flat_map(|response| response.completions),
 5762            );
 5763
 5764            let menu = if completions.is_empty() {
 5765                None
 5766            } else {
 5767                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5768                    let languages = editor
 5769                        .workspace
 5770                        .as_ref()
 5771                        .and_then(|(workspace, _)| workspace.upgrade())
 5772                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5773                    let menu = CompletionsMenu::new(
 5774                        id,
 5775                        requested_source.unwrap_or(if load_provider_completions {
 5776                            CompletionsMenuSource::Normal
 5777                        } else {
 5778                            CompletionsMenuSource::SnippetsOnly
 5779                        }),
 5780                        sort_completions,
 5781                        show_completion_documentation,
 5782                        position,
 5783                        query.clone(),
 5784                        is_incomplete,
 5785                        buffer.clone(),
 5786                        completions.into(),
 5787                        display_options,
 5788                        snippet_sort_order,
 5789                        languages,
 5790                        language,
 5791                        cx,
 5792                    );
 5793
 5794                    let query = if filter_completions { query } else { None };
 5795                    let matches_task = menu.do_async_filtering(
 5796                        query.unwrap_or_default(),
 5797                        buffer_position,
 5798                        &buffer,
 5799                        cx,
 5800                    );
 5801                    (menu, matches_task)
 5802                }) else {
 5803                    return;
 5804                };
 5805
 5806                let matches = matches_task.await;
 5807
 5808                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5809                    // Newer menu already set, so exit.
 5810                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5811                        editor.context_menu.borrow().as_ref()
 5812                        && prev_menu.id > id
 5813                    {
 5814                        return;
 5815                    };
 5816
 5817                    // Only valid to take prev_menu because either the new menu is immediately set
 5818                    // below, or the menu is hidden.
 5819                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5820                        editor.context_menu.borrow_mut().take()
 5821                    {
 5822                        let position_matches =
 5823                            if prev_menu.initial_position == menu.initial_position {
 5824                                true
 5825                            } else {
 5826                                let snapshot = editor.buffer.read(cx).read(cx);
 5827                                prev_menu.initial_position.to_offset(&snapshot)
 5828                                    == menu.initial_position.to_offset(&snapshot)
 5829                            };
 5830                        if position_matches {
 5831                            // Preserve markdown cache before `set_filter_results` because it will
 5832                            // try to populate the documentation cache.
 5833                            menu.preserve_markdown_cache(prev_menu);
 5834                        }
 5835                    };
 5836
 5837                    menu.set_filter_results(matches, provider, window, cx);
 5838                }) else {
 5839                    return;
 5840                };
 5841
 5842                menu.visible().then_some(menu)
 5843            };
 5844
 5845            editor
 5846                .update_in(cx, |editor, window, cx| {
 5847                    if editor.focus_handle.is_focused(window)
 5848                        && let Some(menu) = menu
 5849                    {
 5850                        *editor.context_menu.borrow_mut() =
 5851                            Some(CodeContextMenu::Completions(menu));
 5852
 5853                        crate::hover_popover::hide_hover(editor, cx);
 5854                        if editor.show_edit_predictions_in_menu() {
 5855                            editor.update_visible_edit_prediction(window, cx);
 5856                        } else {
 5857                            editor.discard_edit_prediction(false, cx);
 5858                        }
 5859
 5860                        cx.notify();
 5861                        return;
 5862                    }
 5863
 5864                    if editor.completion_tasks.len() <= 1 {
 5865                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5866                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5867                        // If it was already hidden and we don't show edit predictions in the menu,
 5868                        // we should also show the edit prediction when available.
 5869                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5870                            editor.update_visible_edit_prediction(window, cx);
 5871                        }
 5872                    }
 5873                })
 5874                .ok();
 5875        });
 5876
 5877        self.completion_tasks.push((id, task));
 5878    }
 5879
 5880    #[cfg(feature = "test-support")]
 5881    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5882        let menu = self.context_menu.borrow();
 5883        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5884            let completions = menu.completions.borrow();
 5885            Some(completions.to_vec())
 5886        } else {
 5887            None
 5888        }
 5889    }
 5890
 5891    pub fn with_completions_menu_matching_id<R>(
 5892        &self,
 5893        id: CompletionId,
 5894        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5895    ) -> R {
 5896        let mut context_menu = self.context_menu.borrow_mut();
 5897        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5898            return f(None);
 5899        };
 5900        if completions_menu.id != id {
 5901            return f(None);
 5902        }
 5903        f(Some(completions_menu))
 5904    }
 5905
 5906    pub fn confirm_completion(
 5907        &mut self,
 5908        action: &ConfirmCompletion,
 5909        window: &mut Window,
 5910        cx: &mut Context<Self>,
 5911    ) -> Option<Task<Result<()>>> {
 5912        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5913        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5914    }
 5915
 5916    pub fn confirm_completion_insert(
 5917        &mut self,
 5918        _: &ConfirmCompletionInsert,
 5919        window: &mut Window,
 5920        cx: &mut Context<Self>,
 5921    ) -> Option<Task<Result<()>>> {
 5922        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5923        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5924    }
 5925
 5926    pub fn confirm_completion_replace(
 5927        &mut self,
 5928        _: &ConfirmCompletionReplace,
 5929        window: &mut Window,
 5930        cx: &mut Context<Self>,
 5931    ) -> Option<Task<Result<()>>> {
 5932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5933        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5934    }
 5935
 5936    pub fn compose_completion(
 5937        &mut self,
 5938        action: &ComposeCompletion,
 5939        window: &mut Window,
 5940        cx: &mut Context<Self>,
 5941    ) -> Option<Task<Result<()>>> {
 5942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5943        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5944    }
 5945
 5946    fn do_completion(
 5947        &mut self,
 5948        item_ix: Option<usize>,
 5949        intent: CompletionIntent,
 5950        window: &mut Window,
 5951        cx: &mut Context<Editor>,
 5952    ) -> Option<Task<Result<()>>> {
 5953        use language::ToOffset as _;
 5954
 5955        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5956        else {
 5957            return None;
 5958        };
 5959
 5960        let candidate_id = {
 5961            let entries = completions_menu.entries.borrow();
 5962            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5963            if self.show_edit_predictions_in_menu() {
 5964                self.discard_edit_prediction(true, cx);
 5965            }
 5966            mat.candidate_id
 5967        };
 5968
 5969        let completion = completions_menu
 5970            .completions
 5971            .borrow()
 5972            .get(candidate_id)?
 5973            .clone();
 5974        cx.stop_propagation();
 5975
 5976        let buffer_handle = completions_menu.buffer.clone();
 5977
 5978        let CompletionEdit {
 5979            new_text,
 5980            snippet,
 5981            replace_range,
 5982        } = process_completion_for_edit(
 5983            &completion,
 5984            intent,
 5985            &buffer_handle,
 5986            &completions_menu.initial_position.text_anchor,
 5987            cx,
 5988        );
 5989
 5990        let buffer = buffer_handle.read(cx);
 5991        let snapshot = self.buffer.read(cx).snapshot(cx);
 5992        let newest_anchor = self.selections.newest_anchor();
 5993        let replace_range_multibuffer = {
 5994            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5995            excerpt.map_range_from_buffer(replace_range.clone())
 5996        };
 5997        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5998            return None;
 5999        }
 6000
 6001        let old_text = buffer
 6002            .text_for_range(replace_range.clone())
 6003            .collect::<String>();
 6004        let lookbehind = newest_anchor
 6005            .start
 6006            .text_anchor
 6007            .to_offset(buffer)
 6008            .saturating_sub(replace_range.start);
 6009        let lookahead = replace_range
 6010            .end
 6011            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6012        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6013        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6014
 6015        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6016        let mut ranges = Vec::new();
 6017        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6018
 6019        for selection in &selections {
 6020            let range = if selection.id == newest_anchor.id {
 6021                replace_range_multibuffer.clone()
 6022            } else {
 6023                let mut range = selection.range();
 6024
 6025                // if prefix is present, don't duplicate it
 6026                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6027                    range.start = range.start.saturating_sub(lookbehind);
 6028
 6029                    // if suffix is also present, mimic the newest cursor and replace it
 6030                    if selection.id != newest_anchor.id
 6031                        && snapshot.contains_str_at(range.end, suffix)
 6032                    {
 6033                        range.end += lookahead;
 6034                    }
 6035                }
 6036                range
 6037            };
 6038
 6039            ranges.push(range.clone());
 6040
 6041            if !self.linked_edit_ranges.is_empty() {
 6042                let start_anchor = snapshot.anchor_before(range.start);
 6043                let end_anchor = snapshot.anchor_after(range.end);
 6044                if let Some(ranges) = self
 6045                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6046                {
 6047                    for (buffer, edits) in ranges {
 6048                        linked_edits
 6049                            .entry(buffer.clone())
 6050                            .or_default()
 6051                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6052                    }
 6053                }
 6054            }
 6055        }
 6056
 6057        let common_prefix_len = old_text
 6058            .chars()
 6059            .zip(new_text.chars())
 6060            .take_while(|(a, b)| a == b)
 6061            .map(|(a, _)| a.len_utf8())
 6062            .sum::<usize>();
 6063
 6064        cx.emit(EditorEvent::InputHandled {
 6065            utf16_range_to_replace: None,
 6066            text: new_text[common_prefix_len..].into(),
 6067        });
 6068
 6069        self.transact(window, cx, |editor, window, cx| {
 6070            if let Some(mut snippet) = snippet {
 6071                snippet.text = new_text.to_string();
 6072                editor
 6073                    .insert_snippet(&ranges, snippet, window, cx)
 6074                    .log_err();
 6075            } else {
 6076                editor.buffer.update(cx, |multi_buffer, cx| {
 6077                    let auto_indent = match completion.insert_text_mode {
 6078                        Some(InsertTextMode::AS_IS) => None,
 6079                        _ => editor.autoindent_mode.clone(),
 6080                    };
 6081                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6082                    multi_buffer.edit(edits, auto_indent, cx);
 6083                });
 6084            }
 6085            for (buffer, edits) in linked_edits {
 6086                buffer.update(cx, |buffer, cx| {
 6087                    let snapshot = buffer.snapshot();
 6088                    let edits = edits
 6089                        .into_iter()
 6090                        .map(|(range, text)| {
 6091                            use text::ToPoint as TP;
 6092                            let end_point = TP::to_point(&range.end, &snapshot);
 6093                            let start_point = TP::to_point(&range.start, &snapshot);
 6094                            (start_point..end_point, text)
 6095                        })
 6096                        .sorted_by_key(|(range, _)| range.start);
 6097                    buffer.edit(edits, None, cx);
 6098                })
 6099            }
 6100
 6101            editor.refresh_edit_prediction(true, false, window, cx);
 6102        });
 6103        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6104
 6105        let show_new_completions_on_confirm = completion
 6106            .confirm
 6107            .as_ref()
 6108            .is_some_and(|confirm| confirm(intent, window, cx));
 6109        if show_new_completions_on_confirm {
 6110            self.open_or_update_completions_menu(None, None, false, window, cx);
 6111        }
 6112
 6113        let provider = self.completion_provider.as_ref()?;
 6114        drop(completion);
 6115        let apply_edits = provider.apply_additional_edits_for_completion(
 6116            buffer_handle,
 6117            completions_menu.completions.clone(),
 6118            candidate_id,
 6119            true,
 6120            cx,
 6121        );
 6122
 6123        let editor_settings = EditorSettings::get_global(cx);
 6124        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6125            // After the code completion is finished, users often want to know what signatures are needed.
 6126            // so we should automatically call signature_help
 6127            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6128        }
 6129
 6130        Some(cx.foreground_executor().spawn(async move {
 6131            apply_edits.await?;
 6132            Ok(())
 6133        }))
 6134    }
 6135
 6136    pub fn toggle_code_actions(
 6137        &mut self,
 6138        action: &ToggleCodeActions,
 6139        window: &mut Window,
 6140        cx: &mut Context<Self>,
 6141    ) {
 6142        let quick_launch = action.quick_launch;
 6143        let mut context_menu = self.context_menu.borrow_mut();
 6144        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6145            if code_actions.deployed_from == action.deployed_from {
 6146                // Toggle if we're selecting the same one
 6147                *context_menu = None;
 6148                cx.notify();
 6149                return;
 6150            } else {
 6151                // Otherwise, clear it and start a new one
 6152                *context_menu = None;
 6153                cx.notify();
 6154            }
 6155        }
 6156        drop(context_menu);
 6157        let snapshot = self.snapshot(window, cx);
 6158        let deployed_from = action.deployed_from.clone();
 6159        let action = action.clone();
 6160        self.completion_tasks.clear();
 6161        self.discard_edit_prediction(false, cx);
 6162
 6163        let multibuffer_point = match &action.deployed_from {
 6164            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6165                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6166            }
 6167            _ => self
 6168                .selections
 6169                .newest::<Point>(&snapshot.display_snapshot)
 6170                .head(),
 6171        };
 6172        let Some((buffer, buffer_row)) = snapshot
 6173            .buffer_snapshot()
 6174            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6175            .and_then(|(buffer_snapshot, range)| {
 6176                self.buffer()
 6177                    .read(cx)
 6178                    .buffer(buffer_snapshot.remote_id())
 6179                    .map(|buffer| (buffer, range.start.row))
 6180            })
 6181        else {
 6182            return;
 6183        };
 6184        let buffer_id = buffer.read(cx).remote_id();
 6185        let tasks = self
 6186            .tasks
 6187            .get(&(buffer_id, buffer_row))
 6188            .map(|t| Arc::new(t.to_owned()));
 6189
 6190        if !self.focus_handle.is_focused(window) {
 6191            return;
 6192        }
 6193        let project = self.project.clone();
 6194
 6195        let code_actions_task = match deployed_from {
 6196            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6197            _ => self.code_actions(buffer_row, window, cx),
 6198        };
 6199
 6200        let runnable_task = match deployed_from {
 6201            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6202            _ => {
 6203                let mut task_context_task = Task::ready(None);
 6204                if let Some(tasks) = &tasks
 6205                    && let Some(project) = project
 6206                {
 6207                    task_context_task =
 6208                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6209                }
 6210
 6211                cx.spawn_in(window, {
 6212                    let buffer = buffer.clone();
 6213                    async move |editor, cx| {
 6214                        let task_context = task_context_task.await;
 6215
 6216                        let resolved_tasks =
 6217                            tasks
 6218                                .zip(task_context.clone())
 6219                                .map(|(tasks, task_context)| ResolvedTasks {
 6220                                    templates: tasks.resolve(&task_context).collect(),
 6221                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6222                                        multibuffer_point.row,
 6223                                        tasks.column,
 6224                                    )),
 6225                                });
 6226                        let debug_scenarios = editor
 6227                            .update(cx, |editor, cx| {
 6228                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6229                            })?
 6230                            .await;
 6231                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6232                    }
 6233                })
 6234            }
 6235        };
 6236
 6237        cx.spawn_in(window, async move |editor, cx| {
 6238            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6239            let code_actions = code_actions_task.await;
 6240            let spawn_straight_away = quick_launch
 6241                && resolved_tasks
 6242                    .as_ref()
 6243                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6244                && code_actions
 6245                    .as_ref()
 6246                    .is_none_or(|actions| actions.is_empty())
 6247                && debug_scenarios.is_empty();
 6248
 6249            editor.update_in(cx, |editor, window, cx| {
 6250                crate::hover_popover::hide_hover(editor, cx);
 6251                let actions = CodeActionContents::new(
 6252                    resolved_tasks,
 6253                    code_actions,
 6254                    debug_scenarios,
 6255                    task_context.unwrap_or_default(),
 6256                );
 6257
 6258                // Don't show the menu if there are no actions available
 6259                if actions.is_empty() {
 6260                    cx.notify();
 6261                    return Task::ready(Ok(()));
 6262                }
 6263
 6264                *editor.context_menu.borrow_mut() =
 6265                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6266                        buffer,
 6267                        actions,
 6268                        selected_item: Default::default(),
 6269                        scroll_handle: UniformListScrollHandle::default(),
 6270                        deployed_from,
 6271                    }));
 6272                cx.notify();
 6273                if spawn_straight_away
 6274                    && let Some(task) = editor.confirm_code_action(
 6275                        &ConfirmCodeAction { item_ix: Some(0) },
 6276                        window,
 6277                        cx,
 6278                    )
 6279                {
 6280                    return task;
 6281                }
 6282
 6283                Task::ready(Ok(()))
 6284            })
 6285        })
 6286        .detach_and_log_err(cx);
 6287    }
 6288
 6289    fn debug_scenarios(
 6290        &mut self,
 6291        resolved_tasks: &Option<ResolvedTasks>,
 6292        buffer: &Entity<Buffer>,
 6293        cx: &mut App,
 6294    ) -> Task<Vec<task::DebugScenario>> {
 6295        maybe!({
 6296            let project = self.project()?;
 6297            let dap_store = project.read(cx).dap_store();
 6298            let mut scenarios = vec![];
 6299            let resolved_tasks = resolved_tasks.as_ref()?;
 6300            let buffer = buffer.read(cx);
 6301            let language = buffer.language()?;
 6302            let file = buffer.file();
 6303            let debug_adapter = language_settings(language.name().into(), file, cx)
 6304                .debuggers
 6305                .first()
 6306                .map(SharedString::from)
 6307                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6308
 6309            dap_store.update(cx, |dap_store, cx| {
 6310                for (_, task) in &resolved_tasks.templates {
 6311                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6312                        task.original_task().clone(),
 6313                        debug_adapter.clone().into(),
 6314                        task.display_label().to_owned().into(),
 6315                        cx,
 6316                    );
 6317                    scenarios.push(maybe_scenario);
 6318                }
 6319            });
 6320            Some(cx.background_spawn(async move {
 6321                futures::future::join_all(scenarios)
 6322                    .await
 6323                    .into_iter()
 6324                    .flatten()
 6325                    .collect::<Vec<_>>()
 6326            }))
 6327        })
 6328        .unwrap_or_else(|| Task::ready(vec![]))
 6329    }
 6330
 6331    fn code_actions(
 6332        &mut self,
 6333        buffer_row: u32,
 6334        window: &mut Window,
 6335        cx: &mut Context<Self>,
 6336    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6337        let mut task = self.code_actions_task.take();
 6338        cx.spawn_in(window, async move |editor, cx| {
 6339            while let Some(prev_task) = task {
 6340                prev_task.await.log_err();
 6341                task = editor
 6342                    .update(cx, |this, _| this.code_actions_task.take())
 6343                    .ok()?;
 6344            }
 6345
 6346            editor
 6347                .update(cx, |editor, cx| {
 6348                    editor
 6349                        .available_code_actions
 6350                        .clone()
 6351                        .and_then(|(location, code_actions)| {
 6352                            let snapshot = location.buffer.read(cx).snapshot();
 6353                            let point_range = location.range.to_point(&snapshot);
 6354                            let point_range = point_range.start.row..=point_range.end.row;
 6355                            if point_range.contains(&buffer_row) {
 6356                                Some(code_actions)
 6357                            } else {
 6358                                None
 6359                            }
 6360                        })
 6361                })
 6362                .ok()
 6363                .flatten()
 6364        })
 6365    }
 6366
 6367    pub fn confirm_code_action(
 6368        &mut self,
 6369        action: &ConfirmCodeAction,
 6370        window: &mut Window,
 6371        cx: &mut Context<Self>,
 6372    ) -> Option<Task<Result<()>>> {
 6373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6374
 6375        let actions_menu =
 6376            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6377                menu
 6378            } else {
 6379                return None;
 6380            };
 6381
 6382        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6383        let action = actions_menu.actions.get(action_ix)?;
 6384        let title = action.label();
 6385        let buffer = actions_menu.buffer;
 6386        let workspace = self.workspace()?;
 6387
 6388        match action {
 6389            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6390                workspace.update(cx, |workspace, cx| {
 6391                    workspace.schedule_resolved_task(
 6392                        task_source_kind,
 6393                        resolved_task,
 6394                        false,
 6395                        window,
 6396                        cx,
 6397                    );
 6398
 6399                    Some(Task::ready(Ok(())))
 6400                })
 6401            }
 6402            CodeActionsItem::CodeAction {
 6403                excerpt_id,
 6404                action,
 6405                provider,
 6406            } => {
 6407                let apply_code_action =
 6408                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6409                let workspace = workspace.downgrade();
 6410                Some(cx.spawn_in(window, async move |editor, cx| {
 6411                    let project_transaction = apply_code_action.await?;
 6412                    Self::open_project_transaction(
 6413                        &editor,
 6414                        workspace,
 6415                        project_transaction,
 6416                        title,
 6417                        cx,
 6418                    )
 6419                    .await
 6420                }))
 6421            }
 6422            CodeActionsItem::DebugScenario(scenario) => {
 6423                let context = actions_menu.actions.context;
 6424
 6425                workspace.update(cx, |workspace, cx| {
 6426                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6427                    workspace.start_debug_session(
 6428                        scenario,
 6429                        context,
 6430                        Some(buffer),
 6431                        None,
 6432                        window,
 6433                        cx,
 6434                    );
 6435                });
 6436                Some(Task::ready(Ok(())))
 6437            }
 6438        }
 6439    }
 6440
 6441    pub async fn open_project_transaction(
 6442        editor: &WeakEntity<Editor>,
 6443        workspace: WeakEntity<Workspace>,
 6444        transaction: ProjectTransaction,
 6445        title: String,
 6446        cx: &mut AsyncWindowContext,
 6447    ) -> Result<()> {
 6448        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6449        cx.update(|_, cx| {
 6450            entries.sort_unstable_by_key(|(buffer, _)| {
 6451                buffer.read(cx).file().map(|f| f.path().clone())
 6452            });
 6453        })?;
 6454        if entries.is_empty() {
 6455            return Ok(());
 6456        }
 6457
 6458        // If the project transaction's edits are all contained within this editor, then
 6459        // avoid opening a new editor to display them.
 6460
 6461        if let [(buffer, transaction)] = &*entries {
 6462            let excerpt = editor.update(cx, |editor, cx| {
 6463                editor
 6464                    .buffer()
 6465                    .read(cx)
 6466                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6467            })?;
 6468            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6469                && excerpted_buffer == *buffer
 6470            {
 6471                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6472                    let excerpt_range = excerpt_range.to_offset(buffer);
 6473                    buffer
 6474                        .edited_ranges_for_transaction::<usize>(transaction)
 6475                        .all(|range| {
 6476                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6477                        })
 6478                })?;
 6479
 6480                if all_edits_within_excerpt {
 6481                    return Ok(());
 6482                }
 6483            }
 6484        }
 6485
 6486        let mut ranges_to_highlight = Vec::new();
 6487        let excerpt_buffer = cx.new(|cx| {
 6488            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6489            for (buffer_handle, transaction) in &entries {
 6490                let edited_ranges = buffer_handle
 6491                    .read(cx)
 6492                    .edited_ranges_for_transaction::<Point>(transaction)
 6493                    .collect::<Vec<_>>();
 6494                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6495                    PathKey::for_buffer(buffer_handle, cx),
 6496                    buffer_handle.clone(),
 6497                    edited_ranges,
 6498                    multibuffer_context_lines(cx),
 6499                    cx,
 6500                );
 6501
 6502                ranges_to_highlight.extend(ranges);
 6503            }
 6504            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6505            multibuffer
 6506        })?;
 6507
 6508        workspace.update_in(cx, |workspace, window, cx| {
 6509            let project = workspace.project().clone();
 6510            let editor =
 6511                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6512            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6513            editor.update(cx, |editor, cx| {
 6514                editor.highlight_background::<Self>(
 6515                    &ranges_to_highlight,
 6516                    |theme| theme.colors().editor_highlighted_line_background,
 6517                    cx,
 6518                );
 6519            });
 6520        })?;
 6521
 6522        Ok(())
 6523    }
 6524
 6525    pub fn clear_code_action_providers(&mut self) {
 6526        self.code_action_providers.clear();
 6527        self.available_code_actions.take();
 6528    }
 6529
 6530    pub fn add_code_action_provider(
 6531        &mut self,
 6532        provider: Rc<dyn CodeActionProvider>,
 6533        window: &mut Window,
 6534        cx: &mut Context<Self>,
 6535    ) {
 6536        if self
 6537            .code_action_providers
 6538            .iter()
 6539            .any(|existing_provider| existing_provider.id() == provider.id())
 6540        {
 6541            return;
 6542        }
 6543
 6544        self.code_action_providers.push(provider);
 6545        self.refresh_code_actions(window, cx);
 6546    }
 6547
 6548    pub fn remove_code_action_provider(
 6549        &mut self,
 6550        id: Arc<str>,
 6551        window: &mut Window,
 6552        cx: &mut Context<Self>,
 6553    ) {
 6554        self.code_action_providers
 6555            .retain(|provider| provider.id() != id);
 6556        self.refresh_code_actions(window, cx);
 6557    }
 6558
 6559    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6560        !self.code_action_providers.is_empty()
 6561            && EditorSettings::get_global(cx).toolbar.code_actions
 6562    }
 6563
 6564    pub fn has_available_code_actions(&self) -> bool {
 6565        self.available_code_actions
 6566            .as_ref()
 6567            .is_some_and(|(_, actions)| !actions.is_empty())
 6568    }
 6569
 6570    fn render_inline_code_actions(
 6571        &self,
 6572        icon_size: ui::IconSize,
 6573        display_row: DisplayRow,
 6574        is_active: bool,
 6575        cx: &mut Context<Self>,
 6576    ) -> AnyElement {
 6577        let show_tooltip = !self.context_menu_visible();
 6578        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6579            .icon_size(icon_size)
 6580            .shape(ui::IconButtonShape::Square)
 6581            .icon_color(ui::Color::Hidden)
 6582            .toggle_state(is_active)
 6583            .when(show_tooltip, |this| {
 6584                this.tooltip({
 6585                    let focus_handle = self.focus_handle.clone();
 6586                    move |_window, cx| {
 6587                        Tooltip::for_action_in(
 6588                            "Toggle Code Actions",
 6589                            &ToggleCodeActions {
 6590                                deployed_from: None,
 6591                                quick_launch: false,
 6592                            },
 6593                            &focus_handle,
 6594                            cx,
 6595                        )
 6596                    }
 6597                })
 6598            })
 6599            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6600                window.focus(&editor.focus_handle(cx));
 6601                editor.toggle_code_actions(
 6602                    &crate::actions::ToggleCodeActions {
 6603                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6604                            display_row,
 6605                        )),
 6606                        quick_launch: false,
 6607                    },
 6608                    window,
 6609                    cx,
 6610                );
 6611            }))
 6612            .into_any_element()
 6613    }
 6614
 6615    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6616        &self.context_menu
 6617    }
 6618
 6619    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6620        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6621            cx.background_executor()
 6622                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6623                .await;
 6624
 6625            let (start_buffer, start, _, end, newest_selection) = this
 6626                .update(cx, |this, cx| {
 6627                    let newest_selection = this.selections.newest_anchor().clone();
 6628                    if newest_selection.head().diff_base_anchor.is_some() {
 6629                        return None;
 6630                    }
 6631                    let display_snapshot = this.display_snapshot(cx);
 6632                    let newest_selection_adjusted =
 6633                        this.selections.newest_adjusted(&display_snapshot);
 6634                    let buffer = this.buffer.read(cx);
 6635
 6636                    let (start_buffer, start) =
 6637                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6638                    let (end_buffer, end) =
 6639                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6640
 6641                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6642                })?
 6643                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6644                .context(
 6645                    "Expected selection to lie in a single buffer when refreshing code actions",
 6646                )?;
 6647            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6648                let providers = this.code_action_providers.clone();
 6649                let tasks = this
 6650                    .code_action_providers
 6651                    .iter()
 6652                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6653                    .collect::<Vec<_>>();
 6654                (providers, tasks)
 6655            })?;
 6656
 6657            let mut actions = Vec::new();
 6658            for (provider, provider_actions) in
 6659                providers.into_iter().zip(future::join_all(tasks).await)
 6660            {
 6661                if let Some(provider_actions) = provider_actions.log_err() {
 6662                    actions.extend(provider_actions.into_iter().map(|action| {
 6663                        AvailableCodeAction {
 6664                            excerpt_id: newest_selection.start.excerpt_id,
 6665                            action,
 6666                            provider: provider.clone(),
 6667                        }
 6668                    }));
 6669                }
 6670            }
 6671
 6672            this.update(cx, |this, cx| {
 6673                this.available_code_actions = if actions.is_empty() {
 6674                    None
 6675                } else {
 6676                    Some((
 6677                        Location {
 6678                            buffer: start_buffer,
 6679                            range: start..end,
 6680                        },
 6681                        actions.into(),
 6682                    ))
 6683                };
 6684                cx.notify();
 6685            })
 6686        }));
 6687    }
 6688
 6689    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6690        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6691            self.show_git_blame_inline = false;
 6692
 6693            self.show_git_blame_inline_delay_task =
 6694                Some(cx.spawn_in(window, async move |this, cx| {
 6695                    cx.background_executor().timer(delay).await;
 6696
 6697                    this.update(cx, |this, cx| {
 6698                        this.show_git_blame_inline = true;
 6699                        cx.notify();
 6700                    })
 6701                    .log_err();
 6702                }));
 6703        }
 6704    }
 6705
 6706    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6707        let snapshot = self.snapshot(window, cx);
 6708        let cursor = self
 6709            .selections
 6710            .newest::<Point>(&snapshot.display_snapshot)
 6711            .head();
 6712        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6713        else {
 6714            return;
 6715        };
 6716
 6717        let Some(blame) = self.blame.as_ref() else {
 6718            return;
 6719        };
 6720
 6721        let row_info = RowInfo {
 6722            buffer_id: Some(buffer.remote_id()),
 6723            buffer_row: Some(point.row),
 6724            ..Default::default()
 6725        };
 6726        let Some((buffer, blame_entry)) = blame
 6727            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6728            .flatten()
 6729        else {
 6730            return;
 6731        };
 6732
 6733        let anchor = self.selections.newest_anchor().head();
 6734        let position = self.to_pixel_point(anchor, &snapshot, window);
 6735        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6736            self.show_blame_popover(
 6737                buffer,
 6738                &blame_entry,
 6739                position + last_bounds.origin,
 6740                true,
 6741                cx,
 6742            );
 6743        };
 6744    }
 6745
 6746    fn show_blame_popover(
 6747        &mut self,
 6748        buffer: BufferId,
 6749        blame_entry: &BlameEntry,
 6750        position: gpui::Point<Pixels>,
 6751        ignore_timeout: bool,
 6752        cx: &mut Context<Self>,
 6753    ) {
 6754        if let Some(state) = &mut self.inline_blame_popover {
 6755            state.hide_task.take();
 6756        } else {
 6757            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6758            let blame_entry = blame_entry.clone();
 6759            let show_task = cx.spawn(async move |editor, cx| {
 6760                if !ignore_timeout {
 6761                    cx.background_executor()
 6762                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6763                        .await;
 6764                }
 6765                editor
 6766                    .update(cx, |editor, cx| {
 6767                        editor.inline_blame_popover_show_task.take();
 6768                        let Some(blame) = editor.blame.as_ref() else {
 6769                            return;
 6770                        };
 6771                        let blame = blame.read(cx);
 6772                        let details = blame.details_for_entry(buffer, &blame_entry);
 6773                        let markdown = cx.new(|cx| {
 6774                            Markdown::new(
 6775                                details
 6776                                    .as_ref()
 6777                                    .map(|message| message.message.clone())
 6778                                    .unwrap_or_default(),
 6779                                None,
 6780                                None,
 6781                                cx,
 6782                            )
 6783                        });
 6784                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6785                            position,
 6786                            hide_task: None,
 6787                            popover_bounds: None,
 6788                            popover_state: InlineBlamePopoverState {
 6789                                scroll_handle: ScrollHandle::new(),
 6790                                commit_message: details,
 6791                                markdown,
 6792                            },
 6793                            keyboard_grace: ignore_timeout,
 6794                        });
 6795                        cx.notify();
 6796                    })
 6797                    .ok();
 6798            });
 6799            self.inline_blame_popover_show_task = Some(show_task);
 6800        }
 6801    }
 6802
 6803    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6804        self.inline_blame_popover_show_task.take();
 6805        if let Some(state) = &mut self.inline_blame_popover {
 6806            let hide_task = cx.spawn(async move |editor, cx| {
 6807                if !ignore_timeout {
 6808                    cx.background_executor()
 6809                        .timer(std::time::Duration::from_millis(100))
 6810                        .await;
 6811                }
 6812                editor
 6813                    .update(cx, |editor, cx| {
 6814                        editor.inline_blame_popover.take();
 6815                        cx.notify();
 6816                    })
 6817                    .ok();
 6818            });
 6819            state.hide_task = Some(hide_task);
 6820            true
 6821        } else {
 6822            false
 6823        }
 6824    }
 6825
 6826    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6827        if self.pending_rename.is_some() {
 6828            return None;
 6829        }
 6830
 6831        let provider = self.semantics_provider.clone()?;
 6832        let buffer = self.buffer.read(cx);
 6833        let newest_selection = self.selections.newest_anchor().clone();
 6834        let cursor_position = newest_selection.head();
 6835        let (cursor_buffer, cursor_buffer_position) =
 6836            buffer.text_anchor_for_position(cursor_position, cx)?;
 6837        let (tail_buffer, tail_buffer_position) =
 6838            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6839        if cursor_buffer != tail_buffer {
 6840            return None;
 6841        }
 6842
 6843        let snapshot = cursor_buffer.read(cx).snapshot();
 6844        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6845        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6846        if start_word_range != end_word_range {
 6847            self.document_highlights_task.take();
 6848            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6849            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6850            return None;
 6851        }
 6852
 6853        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6854        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6855            cx.background_executor()
 6856                .timer(Duration::from_millis(debounce))
 6857                .await;
 6858
 6859            let highlights = if let Some(highlights) = cx
 6860                .update(|cx| {
 6861                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6862                })
 6863                .ok()
 6864                .flatten()
 6865            {
 6866                highlights.await.log_err()
 6867            } else {
 6868                None
 6869            };
 6870
 6871            if let Some(highlights) = highlights {
 6872                this.update(cx, |this, cx| {
 6873                    if this.pending_rename.is_some() {
 6874                        return;
 6875                    }
 6876
 6877                    let buffer = this.buffer.read(cx);
 6878                    if buffer
 6879                        .text_anchor_for_position(cursor_position, cx)
 6880                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6881                    {
 6882                        return;
 6883                    }
 6884
 6885                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6886                    let mut write_ranges = Vec::new();
 6887                    let mut read_ranges = Vec::new();
 6888                    for highlight in highlights {
 6889                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6890                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6891                        {
 6892                            let start = highlight
 6893                                .range
 6894                                .start
 6895                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6896                            let end = highlight
 6897                                .range
 6898                                .end
 6899                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6900                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6901                                continue;
 6902                            }
 6903
 6904                            let range =
 6905                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6906                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6907                                write_ranges.push(range);
 6908                            } else {
 6909                                read_ranges.push(range);
 6910                            }
 6911                        }
 6912                    }
 6913
 6914                    this.highlight_background::<DocumentHighlightRead>(
 6915                        &read_ranges,
 6916                        |theme| theme.colors().editor_document_highlight_read_background,
 6917                        cx,
 6918                    );
 6919                    this.highlight_background::<DocumentHighlightWrite>(
 6920                        &write_ranges,
 6921                        |theme| theme.colors().editor_document_highlight_write_background,
 6922                        cx,
 6923                    );
 6924                    cx.notify();
 6925                })
 6926                .log_err();
 6927            }
 6928        }));
 6929        None
 6930    }
 6931
 6932    fn prepare_highlight_query_from_selection(
 6933        &mut self,
 6934        window: &Window,
 6935        cx: &mut Context<Editor>,
 6936    ) -> Option<(String, Range<Anchor>)> {
 6937        if matches!(self.mode, EditorMode::SingleLine) {
 6938            return None;
 6939        }
 6940        if !EditorSettings::get_global(cx).selection_highlight {
 6941            return None;
 6942        }
 6943        if self.selections.count() != 1 || self.selections.line_mode() {
 6944            return None;
 6945        }
 6946        let snapshot = self.snapshot(window, cx);
 6947        let selection = self.selections.newest::<Point>(&snapshot);
 6948        // If the selection spans multiple rows OR it is empty
 6949        if selection.start.row != selection.end.row
 6950            || selection.start.column == selection.end.column
 6951        {
 6952            return None;
 6953        }
 6954        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6955        let query = snapshot
 6956            .buffer_snapshot()
 6957            .text_for_range(selection_anchor_range.clone())
 6958            .collect::<String>();
 6959        if query.trim().is_empty() {
 6960            return None;
 6961        }
 6962        Some((query, selection_anchor_range))
 6963    }
 6964
 6965    fn update_selection_occurrence_highlights(
 6966        &mut self,
 6967        query_text: String,
 6968        query_range: Range<Anchor>,
 6969        multi_buffer_range_to_query: Range<Point>,
 6970        use_debounce: bool,
 6971        window: &mut Window,
 6972        cx: &mut Context<Editor>,
 6973    ) -> Task<()> {
 6974        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6975        cx.spawn_in(window, async move |editor, cx| {
 6976            if use_debounce {
 6977                cx.background_executor()
 6978                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6979                    .await;
 6980            }
 6981            let match_task = cx.background_spawn(async move {
 6982                let buffer_ranges = multi_buffer_snapshot
 6983                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6984                    .into_iter()
 6985                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6986                let mut match_ranges = Vec::new();
 6987                let Ok(regex) = project::search::SearchQuery::text(
 6988                    query_text.clone(),
 6989                    false,
 6990                    false,
 6991                    false,
 6992                    Default::default(),
 6993                    Default::default(),
 6994                    false,
 6995                    None,
 6996                ) else {
 6997                    return Vec::default();
 6998                };
 6999                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7000                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7001                    match_ranges.extend(
 7002                        regex
 7003                            .search(buffer_snapshot, Some(search_range.clone()))
 7004                            .await
 7005                            .into_iter()
 7006                            .filter_map(|match_range| {
 7007                                let match_start = buffer_snapshot
 7008                                    .anchor_after(search_range.start + match_range.start);
 7009                                let match_end = buffer_snapshot
 7010                                    .anchor_before(search_range.start + match_range.end);
 7011                                let match_anchor_range = Anchor::range_in_buffer(
 7012                                    excerpt_id,
 7013                                    buffer_snapshot.remote_id(),
 7014                                    match_start..match_end,
 7015                                );
 7016                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7017                            }),
 7018                    );
 7019                }
 7020                match_ranges
 7021            });
 7022            let match_ranges = match_task.await;
 7023            editor
 7024                .update_in(cx, |editor, _, cx| {
 7025                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7026                    if !match_ranges.is_empty() {
 7027                        editor.highlight_background::<SelectedTextHighlight>(
 7028                            &match_ranges,
 7029                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7030                            cx,
 7031                        )
 7032                    }
 7033                })
 7034                .log_err();
 7035        })
 7036    }
 7037
 7038    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7039        struct NewlineFold;
 7040        let type_id = std::any::TypeId::of::<NewlineFold>();
 7041        if !self.mode.is_single_line() {
 7042            return;
 7043        }
 7044        let snapshot = self.snapshot(window, cx);
 7045        if snapshot.buffer_snapshot().max_point().row == 0 {
 7046            return;
 7047        }
 7048        let task = cx.background_spawn(async move {
 7049            let new_newlines = snapshot
 7050                .buffer_chars_at(0)
 7051                .filter_map(|(c, i)| {
 7052                    if c == '\n' {
 7053                        Some(
 7054                            snapshot.buffer_snapshot().anchor_after(i)
 7055                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7056                        )
 7057                    } else {
 7058                        None
 7059                    }
 7060                })
 7061                .collect::<Vec<_>>();
 7062            let existing_newlines = snapshot
 7063                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7064                .filter_map(|fold| {
 7065                    if fold.placeholder.type_tag == Some(type_id) {
 7066                        Some(fold.range.start..fold.range.end)
 7067                    } else {
 7068                        None
 7069                    }
 7070                })
 7071                .collect::<Vec<_>>();
 7072
 7073            (new_newlines, existing_newlines)
 7074        });
 7075        self.folding_newlines = cx.spawn(async move |this, cx| {
 7076            let (new_newlines, existing_newlines) = task.await;
 7077            if new_newlines == existing_newlines {
 7078                return;
 7079            }
 7080            let placeholder = FoldPlaceholder {
 7081                render: Arc::new(move |_, _, cx| {
 7082                    div()
 7083                        .bg(cx.theme().status().hint_background)
 7084                        .border_b_1()
 7085                        .size_full()
 7086                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7087                        .border_color(cx.theme().status().hint)
 7088                        .child("\\n")
 7089                        .into_any()
 7090                }),
 7091                constrain_width: false,
 7092                merge_adjacent: false,
 7093                type_tag: Some(type_id),
 7094            };
 7095            let creases = new_newlines
 7096                .into_iter()
 7097                .map(|range| Crease::simple(range, placeholder.clone()))
 7098                .collect();
 7099            this.update(cx, |this, cx| {
 7100                this.display_map.update(cx, |display_map, cx| {
 7101                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7102                    display_map.fold(creases, cx);
 7103                });
 7104            })
 7105            .ok();
 7106        });
 7107    }
 7108
 7109    fn refresh_selected_text_highlights(
 7110        &mut self,
 7111        on_buffer_edit: bool,
 7112        window: &mut Window,
 7113        cx: &mut Context<Editor>,
 7114    ) {
 7115        let Some((query_text, query_range)) =
 7116            self.prepare_highlight_query_from_selection(window, cx)
 7117        else {
 7118            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7119            self.quick_selection_highlight_task.take();
 7120            self.debounced_selection_highlight_task.take();
 7121            return;
 7122        };
 7123        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7124        if on_buffer_edit
 7125            || self
 7126                .quick_selection_highlight_task
 7127                .as_ref()
 7128                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7129        {
 7130            let multi_buffer_visible_start = self
 7131                .scroll_manager
 7132                .anchor()
 7133                .anchor
 7134                .to_point(&multi_buffer_snapshot);
 7135            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7136                multi_buffer_visible_start
 7137                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7138                Bias::Left,
 7139            );
 7140            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7141            self.quick_selection_highlight_task = Some((
 7142                query_range.clone(),
 7143                self.update_selection_occurrence_highlights(
 7144                    query_text.clone(),
 7145                    query_range.clone(),
 7146                    multi_buffer_visible_range,
 7147                    false,
 7148                    window,
 7149                    cx,
 7150                ),
 7151            ));
 7152        }
 7153        if on_buffer_edit
 7154            || self
 7155                .debounced_selection_highlight_task
 7156                .as_ref()
 7157                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7158        {
 7159            let multi_buffer_start = multi_buffer_snapshot
 7160                .anchor_before(0)
 7161                .to_point(&multi_buffer_snapshot);
 7162            let multi_buffer_end = multi_buffer_snapshot
 7163                .anchor_after(multi_buffer_snapshot.len())
 7164                .to_point(&multi_buffer_snapshot);
 7165            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7166            self.debounced_selection_highlight_task = Some((
 7167                query_range.clone(),
 7168                self.update_selection_occurrence_highlights(
 7169                    query_text,
 7170                    query_range,
 7171                    multi_buffer_full_range,
 7172                    true,
 7173                    window,
 7174                    cx,
 7175                ),
 7176            ));
 7177        }
 7178    }
 7179
 7180    pub fn refresh_edit_prediction(
 7181        &mut self,
 7182        debounce: bool,
 7183        user_requested: bool,
 7184        window: &mut Window,
 7185        cx: &mut Context<Self>,
 7186    ) -> Option<()> {
 7187        if DisableAiSettings::get_global(cx).disable_ai {
 7188            return None;
 7189        }
 7190
 7191        let provider = self.edit_prediction_provider()?;
 7192        let cursor = self.selections.newest_anchor().head();
 7193        let (buffer, cursor_buffer_position) =
 7194            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7195
 7196        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7197            self.discard_edit_prediction(false, cx);
 7198            return None;
 7199        }
 7200
 7201        self.update_visible_edit_prediction(window, cx);
 7202
 7203        if !user_requested
 7204            && (!self.should_show_edit_predictions()
 7205                || !self.is_focused(window)
 7206                || buffer.read(cx).is_empty())
 7207        {
 7208            self.discard_edit_prediction(false, cx);
 7209            return None;
 7210        }
 7211
 7212        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7213        Some(())
 7214    }
 7215
 7216    fn show_edit_predictions_in_menu(&self) -> bool {
 7217        match self.edit_prediction_settings {
 7218            EditPredictionSettings::Disabled => false,
 7219            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7220        }
 7221    }
 7222
 7223    pub fn edit_predictions_enabled(&self) -> bool {
 7224        match self.edit_prediction_settings {
 7225            EditPredictionSettings::Disabled => false,
 7226            EditPredictionSettings::Enabled { .. } => true,
 7227        }
 7228    }
 7229
 7230    fn edit_prediction_requires_modifier(&self) -> bool {
 7231        match self.edit_prediction_settings {
 7232            EditPredictionSettings::Disabled => false,
 7233            EditPredictionSettings::Enabled {
 7234                preview_requires_modifier,
 7235                ..
 7236            } => preview_requires_modifier,
 7237        }
 7238    }
 7239
 7240    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7241        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7242            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7243            self.discard_edit_prediction(false, cx);
 7244        } else {
 7245            let selection = self.selections.newest_anchor();
 7246            let cursor = selection.head();
 7247
 7248            if let Some((buffer, cursor_buffer_position)) =
 7249                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7250            {
 7251                self.edit_prediction_settings =
 7252                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7253            }
 7254        }
 7255    }
 7256
 7257    fn edit_prediction_settings_at_position(
 7258        &self,
 7259        buffer: &Entity<Buffer>,
 7260        buffer_position: language::Anchor,
 7261        cx: &App,
 7262    ) -> EditPredictionSettings {
 7263        if !self.mode.is_full()
 7264            || !self.show_edit_predictions_override.unwrap_or(true)
 7265            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7266        {
 7267            return EditPredictionSettings::Disabled;
 7268        }
 7269
 7270        let buffer = buffer.read(cx);
 7271
 7272        let file = buffer.file();
 7273
 7274        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7275            return EditPredictionSettings::Disabled;
 7276        };
 7277
 7278        let by_provider = matches!(
 7279            self.menu_edit_predictions_policy,
 7280            MenuEditPredictionsPolicy::ByProvider
 7281        );
 7282
 7283        let show_in_menu = by_provider
 7284            && self
 7285                .edit_prediction_provider
 7286                .as_ref()
 7287                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7288
 7289        let preview_requires_modifier =
 7290            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7291
 7292        EditPredictionSettings::Enabled {
 7293            show_in_menu,
 7294            preview_requires_modifier,
 7295        }
 7296    }
 7297
 7298    fn should_show_edit_predictions(&self) -> bool {
 7299        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7300    }
 7301
 7302    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7303        matches!(
 7304            self.edit_prediction_preview,
 7305            EditPredictionPreview::Active { .. }
 7306        )
 7307    }
 7308
 7309    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7310        let cursor = self.selections.newest_anchor().head();
 7311        if let Some((buffer, cursor_position)) =
 7312            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7313        {
 7314            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7315        } else {
 7316            false
 7317        }
 7318    }
 7319
 7320    pub fn supports_minimap(&self, cx: &App) -> bool {
 7321        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7322    }
 7323
 7324    fn edit_predictions_enabled_in_buffer(
 7325        &self,
 7326        buffer: &Entity<Buffer>,
 7327        buffer_position: language::Anchor,
 7328        cx: &App,
 7329    ) -> bool {
 7330        maybe!({
 7331            if self.read_only(cx) {
 7332                return Some(false);
 7333            }
 7334            let provider = self.edit_prediction_provider()?;
 7335            if !provider.is_enabled(buffer, buffer_position, cx) {
 7336                return Some(false);
 7337            }
 7338            let buffer = buffer.read(cx);
 7339            let Some(file) = buffer.file() else {
 7340                return Some(true);
 7341            };
 7342            let settings = all_language_settings(Some(file), cx);
 7343            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7344        })
 7345        .unwrap_or(false)
 7346    }
 7347
 7348    fn cycle_edit_prediction(
 7349        &mut self,
 7350        direction: Direction,
 7351        window: &mut Window,
 7352        cx: &mut Context<Self>,
 7353    ) -> Option<()> {
 7354        let provider = self.edit_prediction_provider()?;
 7355        let cursor = self.selections.newest_anchor().head();
 7356        let (buffer, cursor_buffer_position) =
 7357            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7358        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7359            return None;
 7360        }
 7361
 7362        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7363        self.update_visible_edit_prediction(window, cx);
 7364
 7365        Some(())
 7366    }
 7367
 7368    pub fn show_edit_prediction(
 7369        &mut self,
 7370        _: &ShowEditPrediction,
 7371        window: &mut Window,
 7372        cx: &mut Context<Self>,
 7373    ) {
 7374        if !self.has_active_edit_prediction() {
 7375            self.refresh_edit_prediction(false, true, window, cx);
 7376            return;
 7377        }
 7378
 7379        self.update_visible_edit_prediction(window, cx);
 7380    }
 7381
 7382    pub fn display_cursor_names(
 7383        &mut self,
 7384        _: &DisplayCursorNames,
 7385        window: &mut Window,
 7386        cx: &mut Context<Self>,
 7387    ) {
 7388        self.show_cursor_names(window, cx);
 7389    }
 7390
 7391    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7392        self.show_cursor_names = true;
 7393        cx.notify();
 7394        cx.spawn_in(window, async move |this, cx| {
 7395            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7396            this.update(cx, |this, cx| {
 7397                this.show_cursor_names = false;
 7398                cx.notify()
 7399            })
 7400            .ok()
 7401        })
 7402        .detach();
 7403    }
 7404
 7405    pub fn next_edit_prediction(
 7406        &mut self,
 7407        _: &NextEditPrediction,
 7408        window: &mut Window,
 7409        cx: &mut Context<Self>,
 7410    ) {
 7411        if self.has_active_edit_prediction() {
 7412            self.cycle_edit_prediction(Direction::Next, window, cx);
 7413        } else {
 7414            let is_copilot_disabled = self
 7415                .refresh_edit_prediction(false, true, window, cx)
 7416                .is_none();
 7417            if is_copilot_disabled {
 7418                cx.propagate();
 7419            }
 7420        }
 7421    }
 7422
 7423    pub fn previous_edit_prediction(
 7424        &mut self,
 7425        _: &PreviousEditPrediction,
 7426        window: &mut Window,
 7427        cx: &mut Context<Self>,
 7428    ) {
 7429        if self.has_active_edit_prediction() {
 7430            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7431        } else {
 7432            let is_copilot_disabled = self
 7433                .refresh_edit_prediction(false, true, window, cx)
 7434                .is_none();
 7435            if is_copilot_disabled {
 7436                cx.propagate();
 7437            }
 7438        }
 7439    }
 7440
 7441    pub fn accept_edit_prediction(
 7442        &mut self,
 7443        _: &AcceptEditPrediction,
 7444        window: &mut Window,
 7445        cx: &mut Context<Self>,
 7446    ) {
 7447        if self.show_edit_predictions_in_menu() {
 7448            self.hide_context_menu(window, cx);
 7449        }
 7450
 7451        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7452            return;
 7453        };
 7454
 7455        match &active_edit_prediction.completion {
 7456            EditPrediction::MoveWithin { target, .. } => {
 7457                let target = *target;
 7458
 7459                if let Some(position_map) = &self.last_position_map {
 7460                    if position_map
 7461                        .visible_row_range
 7462                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7463                        || !self.edit_prediction_requires_modifier()
 7464                    {
 7465                        self.unfold_ranges(&[target..target], true, false, cx);
 7466                        // Note that this is also done in vim's handler of the Tab action.
 7467                        self.change_selections(
 7468                            SelectionEffects::scroll(Autoscroll::newest()),
 7469                            window,
 7470                            cx,
 7471                            |selections| {
 7472                                selections.select_anchor_ranges([target..target]);
 7473                            },
 7474                        );
 7475                        self.clear_row_highlights::<EditPredictionPreview>();
 7476
 7477                        self.edit_prediction_preview
 7478                            .set_previous_scroll_position(None);
 7479                    } else {
 7480                        self.edit_prediction_preview
 7481                            .set_previous_scroll_position(Some(
 7482                                position_map.snapshot.scroll_anchor,
 7483                            ));
 7484
 7485                        self.highlight_rows::<EditPredictionPreview>(
 7486                            target..target,
 7487                            cx.theme().colors().editor_highlighted_line_background,
 7488                            RowHighlightOptions {
 7489                                autoscroll: true,
 7490                                ..Default::default()
 7491                            },
 7492                            cx,
 7493                        );
 7494                        self.request_autoscroll(Autoscroll::fit(), cx);
 7495                    }
 7496                }
 7497            }
 7498            EditPrediction::MoveOutside { snapshot, target } => {
 7499                if let Some(workspace) = self.workspace() {
 7500                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7501                        .detach_and_log_err(cx);
 7502                }
 7503            }
 7504            EditPrediction::Edit { edits, .. } => {
 7505                self.report_edit_prediction_event(
 7506                    active_edit_prediction.completion_id.clone(),
 7507                    true,
 7508                    cx,
 7509                );
 7510
 7511                if let Some(provider) = self.edit_prediction_provider() {
 7512                    provider.accept(cx);
 7513                }
 7514
 7515                // Store the transaction ID and selections before applying the edit
 7516                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7517
 7518                let snapshot = self.buffer.read(cx).snapshot(cx);
 7519                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7520
 7521                self.buffer.update(cx, |buffer, cx| {
 7522                    buffer.edit(edits.iter().cloned(), None, cx)
 7523                });
 7524
 7525                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7526                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7527                });
 7528
 7529                let selections = self.selections.disjoint_anchors_arc();
 7530                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7531                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7532                    if has_new_transaction {
 7533                        self.selection_history
 7534                            .insert_transaction(transaction_id_now, selections);
 7535                    }
 7536                }
 7537
 7538                self.update_visible_edit_prediction(window, cx);
 7539                if self.active_edit_prediction.is_none() {
 7540                    self.refresh_edit_prediction(true, true, window, cx);
 7541                }
 7542
 7543                cx.notify();
 7544            }
 7545        }
 7546
 7547        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7548    }
 7549
 7550    pub fn accept_partial_edit_prediction(
 7551        &mut self,
 7552        _: &AcceptPartialEditPrediction,
 7553        window: &mut Window,
 7554        cx: &mut Context<Self>,
 7555    ) {
 7556        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7557            return;
 7558        };
 7559        if self.selections.count() != 1 {
 7560            return;
 7561        }
 7562
 7563        match &active_edit_prediction.completion {
 7564            EditPrediction::MoveWithin { target, .. } => {
 7565                let target = *target;
 7566                self.change_selections(
 7567                    SelectionEffects::scroll(Autoscroll::newest()),
 7568                    window,
 7569                    cx,
 7570                    |selections| {
 7571                        selections.select_anchor_ranges([target..target]);
 7572                    },
 7573                );
 7574            }
 7575            EditPrediction::MoveOutside { snapshot, target } => {
 7576                if let Some(workspace) = self.workspace() {
 7577                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7578                        .detach_and_log_err(cx);
 7579                }
 7580            }
 7581            EditPrediction::Edit { edits, .. } => {
 7582                self.report_edit_prediction_event(
 7583                    active_edit_prediction.completion_id.clone(),
 7584                    true,
 7585                    cx,
 7586                );
 7587
 7588                // Find an insertion that starts at the cursor position.
 7589                let snapshot = self.buffer.read(cx).snapshot(cx);
 7590                let cursor_offset = self
 7591                    .selections
 7592                    .newest::<usize>(&self.display_snapshot(cx))
 7593                    .head();
 7594                let insertion = edits.iter().find_map(|(range, text)| {
 7595                    let range = range.to_offset(&snapshot);
 7596                    if range.is_empty() && range.start == cursor_offset {
 7597                        Some(text)
 7598                    } else {
 7599                        None
 7600                    }
 7601                });
 7602
 7603                if let Some(text) = insertion {
 7604                    let mut partial_completion = text
 7605                        .chars()
 7606                        .by_ref()
 7607                        .take_while(|c| c.is_alphabetic())
 7608                        .collect::<String>();
 7609                    if partial_completion.is_empty() {
 7610                        partial_completion = text
 7611                            .chars()
 7612                            .by_ref()
 7613                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7614                            .collect::<String>();
 7615                    }
 7616
 7617                    cx.emit(EditorEvent::InputHandled {
 7618                        utf16_range_to_replace: None,
 7619                        text: partial_completion.clone().into(),
 7620                    });
 7621
 7622                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7623
 7624                    self.refresh_edit_prediction(true, true, window, cx);
 7625                    cx.notify();
 7626                } else {
 7627                    self.accept_edit_prediction(&Default::default(), window, cx);
 7628                }
 7629            }
 7630        }
 7631    }
 7632
 7633    fn discard_edit_prediction(
 7634        &mut self,
 7635        should_report_edit_prediction_event: bool,
 7636        cx: &mut Context<Self>,
 7637    ) -> bool {
 7638        if should_report_edit_prediction_event {
 7639            let completion_id = self
 7640                .active_edit_prediction
 7641                .as_ref()
 7642                .and_then(|active_completion| active_completion.completion_id.clone());
 7643
 7644            self.report_edit_prediction_event(completion_id, false, cx);
 7645        }
 7646
 7647        if let Some(provider) = self.edit_prediction_provider() {
 7648            provider.discard(cx);
 7649        }
 7650
 7651        self.take_active_edit_prediction(cx)
 7652    }
 7653
 7654    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7655        let Some(provider) = self.edit_prediction_provider() else {
 7656            return;
 7657        };
 7658
 7659        let Some((_, buffer, _)) = self
 7660            .buffer
 7661            .read(cx)
 7662            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7663        else {
 7664            return;
 7665        };
 7666
 7667        let extension = buffer
 7668            .read(cx)
 7669            .file()
 7670            .and_then(|file| Some(file.path().extension()?.to_string()));
 7671
 7672        let event_type = match accepted {
 7673            true => "Edit Prediction Accepted",
 7674            false => "Edit Prediction Discarded",
 7675        };
 7676        telemetry::event!(
 7677            event_type,
 7678            provider = provider.name(),
 7679            prediction_id = id,
 7680            suggestion_accepted = accepted,
 7681            file_extension = extension,
 7682        );
 7683    }
 7684
 7685    fn open_editor_at_anchor(
 7686        snapshot: &language::BufferSnapshot,
 7687        target: language::Anchor,
 7688        workspace: &Entity<Workspace>,
 7689        window: &mut Window,
 7690        cx: &mut App,
 7691    ) -> Task<Result<()>> {
 7692        workspace.update(cx, |workspace, cx| {
 7693            let path = snapshot.file().map(|file| file.full_path(cx));
 7694            let Some(path) =
 7695                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7696            else {
 7697                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7698            };
 7699            let target = text::ToPoint::to_point(&target, snapshot);
 7700            let item = workspace.open_path(path, None, true, window, cx);
 7701            window.spawn(cx, async move |cx| {
 7702                let Some(editor) = item.await?.downcast::<Editor>() else {
 7703                    return Ok(());
 7704                };
 7705                editor
 7706                    .update_in(cx, |editor, window, cx| {
 7707                        editor.go_to_singleton_buffer_point(target, window, cx);
 7708                    })
 7709                    .ok();
 7710                anyhow::Ok(())
 7711            })
 7712        })
 7713    }
 7714
 7715    pub fn has_active_edit_prediction(&self) -> bool {
 7716        self.active_edit_prediction.is_some()
 7717    }
 7718
 7719    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7720        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7721            return false;
 7722        };
 7723
 7724        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7725        self.clear_highlights::<EditPredictionHighlight>(cx);
 7726        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7727        true
 7728    }
 7729
 7730    /// Returns true when we're displaying the edit prediction popover below the cursor
 7731    /// like we are not previewing and the LSP autocomplete menu is visible
 7732    /// or we are in `when_holding_modifier` mode.
 7733    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7734        if self.edit_prediction_preview_is_active()
 7735            || !self.show_edit_predictions_in_menu()
 7736            || !self.edit_predictions_enabled()
 7737        {
 7738            return false;
 7739        }
 7740
 7741        if self.has_visible_completions_menu() {
 7742            return true;
 7743        }
 7744
 7745        has_completion && self.edit_prediction_requires_modifier()
 7746    }
 7747
 7748    fn handle_modifiers_changed(
 7749        &mut self,
 7750        modifiers: Modifiers,
 7751        position_map: &PositionMap,
 7752        window: &mut Window,
 7753        cx: &mut Context<Self>,
 7754    ) {
 7755        // Ensure that the edit prediction preview is updated, even when not
 7756        // enabled, if there's an active edit prediction preview.
 7757        if self.show_edit_predictions_in_menu()
 7758            || matches!(
 7759                self.edit_prediction_preview,
 7760                EditPredictionPreview::Active { .. }
 7761            )
 7762        {
 7763            self.update_edit_prediction_preview(&modifiers, window, cx);
 7764        }
 7765
 7766        self.update_selection_mode(&modifiers, position_map, window, cx);
 7767
 7768        let mouse_position = window.mouse_position();
 7769        if !position_map.text_hitbox.is_hovered(window) {
 7770            return;
 7771        }
 7772
 7773        self.update_hovered_link(
 7774            position_map.point_for_position(mouse_position),
 7775            &position_map.snapshot,
 7776            modifiers,
 7777            window,
 7778            cx,
 7779        )
 7780    }
 7781
 7782    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7783        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7784            MultiCursorModifier::Alt => modifiers.secondary(),
 7785            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7786        }
 7787    }
 7788
 7789    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7790        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7791            MultiCursorModifier::Alt => modifiers.alt,
 7792            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7793        }
 7794    }
 7795
 7796    fn columnar_selection_mode(
 7797        modifiers: &Modifiers,
 7798        cx: &mut Context<Self>,
 7799    ) -> Option<ColumnarMode> {
 7800        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7801            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7802                Some(ColumnarMode::FromMouse)
 7803            } else if Self::is_alt_pressed(modifiers, cx) {
 7804                Some(ColumnarMode::FromSelection)
 7805            } else {
 7806                None
 7807            }
 7808        } else {
 7809            None
 7810        }
 7811    }
 7812
 7813    fn update_selection_mode(
 7814        &mut self,
 7815        modifiers: &Modifiers,
 7816        position_map: &PositionMap,
 7817        window: &mut Window,
 7818        cx: &mut Context<Self>,
 7819    ) {
 7820        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7821            return;
 7822        };
 7823        if self.selections.pending_anchor().is_none() {
 7824            return;
 7825        }
 7826
 7827        let mouse_position = window.mouse_position();
 7828        let point_for_position = position_map.point_for_position(mouse_position);
 7829        let position = point_for_position.previous_valid;
 7830
 7831        self.select(
 7832            SelectPhase::BeginColumnar {
 7833                position,
 7834                reset: false,
 7835                mode,
 7836                goal_column: point_for_position.exact_unclipped.column(),
 7837            },
 7838            window,
 7839            cx,
 7840        );
 7841    }
 7842
 7843    fn update_edit_prediction_preview(
 7844        &mut self,
 7845        modifiers: &Modifiers,
 7846        window: &mut Window,
 7847        cx: &mut Context<Self>,
 7848    ) {
 7849        let mut modifiers_held = false;
 7850        if let Some(accept_keystroke) = self
 7851            .accept_edit_prediction_keybind(false, window, cx)
 7852            .keystroke()
 7853        {
 7854            modifiers_held = modifiers_held
 7855                || (accept_keystroke.modifiers() == modifiers
 7856                    && accept_keystroke.modifiers().modified());
 7857        };
 7858        if let Some(accept_partial_keystroke) = self
 7859            .accept_edit_prediction_keybind(true, window, cx)
 7860            .keystroke()
 7861        {
 7862            modifiers_held = modifiers_held
 7863                || (accept_partial_keystroke.modifiers() == modifiers
 7864                    && accept_partial_keystroke.modifiers().modified());
 7865        }
 7866
 7867        if modifiers_held {
 7868            if matches!(
 7869                self.edit_prediction_preview,
 7870                EditPredictionPreview::Inactive { .. }
 7871            ) {
 7872                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7873                    provider.provider.did_show(cx)
 7874                }
 7875
 7876                self.edit_prediction_preview = EditPredictionPreview::Active {
 7877                    previous_scroll_position: None,
 7878                    since: Instant::now(),
 7879                };
 7880
 7881                self.update_visible_edit_prediction(window, cx);
 7882                cx.notify();
 7883            }
 7884        } else if let EditPredictionPreview::Active {
 7885            previous_scroll_position,
 7886            since,
 7887        } = self.edit_prediction_preview
 7888        {
 7889            if let (Some(previous_scroll_position), Some(position_map)) =
 7890                (previous_scroll_position, self.last_position_map.as_ref())
 7891            {
 7892                self.set_scroll_position(
 7893                    previous_scroll_position
 7894                        .scroll_position(&position_map.snapshot.display_snapshot),
 7895                    window,
 7896                    cx,
 7897                );
 7898            }
 7899
 7900            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7901                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7902            };
 7903            self.clear_row_highlights::<EditPredictionPreview>();
 7904            self.update_visible_edit_prediction(window, cx);
 7905            cx.notify();
 7906        }
 7907    }
 7908
 7909    fn update_visible_edit_prediction(
 7910        &mut self,
 7911        _window: &mut Window,
 7912        cx: &mut Context<Self>,
 7913    ) -> Option<()> {
 7914        if DisableAiSettings::get_global(cx).disable_ai {
 7915            return None;
 7916        }
 7917
 7918        if self.ime_transaction.is_some() {
 7919            self.discard_edit_prediction(false, cx);
 7920            return None;
 7921        }
 7922
 7923        let selection = self.selections.newest_anchor();
 7924        let cursor = selection.head();
 7925        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7926        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7927        let excerpt_id = cursor.excerpt_id;
 7928
 7929        let show_in_menu = self.show_edit_predictions_in_menu();
 7930        let completions_menu_has_precedence = !show_in_menu
 7931            && (self.context_menu.borrow().is_some()
 7932                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7933
 7934        if completions_menu_has_precedence
 7935            || !offset_selection.is_empty()
 7936            || self
 7937                .active_edit_prediction
 7938                .as_ref()
 7939                .is_some_and(|completion| {
 7940                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7941                        return false;
 7942                    };
 7943                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7944                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7945                    !invalidation_range.contains(&offset_selection.head())
 7946                })
 7947        {
 7948            self.discard_edit_prediction(false, cx);
 7949            return None;
 7950        }
 7951
 7952        self.take_active_edit_prediction(cx);
 7953        let Some(provider) = self.edit_prediction_provider() else {
 7954            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7955            return None;
 7956        };
 7957
 7958        let (buffer, cursor_buffer_position) =
 7959            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7960
 7961        self.edit_prediction_settings =
 7962            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7963
 7964        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7965
 7966        if self.edit_prediction_indent_conflict {
 7967            let cursor_point = cursor.to_point(&multibuffer);
 7968
 7969            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7970
 7971            if let Some((_, indent)) = indents.iter().next()
 7972                && indent.len == cursor_point.column
 7973            {
 7974                self.edit_prediction_indent_conflict = false;
 7975            }
 7976        }
 7977
 7978        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7979
 7980        let (completion_id, edits, edit_preview) = match edit_prediction {
 7981            edit_prediction::EditPrediction::Local {
 7982                id,
 7983                edits,
 7984                edit_preview,
 7985            } => (id, edits, edit_preview),
 7986            edit_prediction::EditPrediction::Jump {
 7987                id,
 7988                snapshot,
 7989                target,
 7990            } => {
 7991                self.stale_edit_prediction_in_menu = None;
 7992                self.active_edit_prediction = Some(EditPredictionState {
 7993                    inlay_ids: vec![],
 7994                    completion: EditPrediction::MoveOutside { snapshot, target },
 7995                    completion_id: id,
 7996                    invalidation_range: None,
 7997                });
 7998                cx.notify();
 7999                return Some(());
 8000            }
 8001        };
 8002
 8003        let edits = edits
 8004            .into_iter()
 8005            .flat_map(|(range, new_text)| {
 8006                Some((
 8007                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8008                    new_text,
 8009                ))
 8010            })
 8011            .collect::<Vec<_>>();
 8012        if edits.is_empty() {
 8013            return None;
 8014        }
 8015
 8016        let first_edit_start = edits.first().unwrap().0.start;
 8017        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8018        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8019
 8020        let last_edit_end = edits.last().unwrap().0.end;
 8021        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8022        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8023
 8024        let cursor_row = cursor.to_point(&multibuffer).row;
 8025
 8026        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8027
 8028        let mut inlay_ids = Vec::new();
 8029        let invalidation_row_range;
 8030        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8031            Some(cursor_row..edit_end_row)
 8032        } else if cursor_row > edit_end_row {
 8033            Some(edit_start_row..cursor_row)
 8034        } else {
 8035            None
 8036        };
 8037        let supports_jump = self
 8038            .edit_prediction_provider
 8039            .as_ref()
 8040            .map(|provider| provider.provider.supports_jump_to_edit())
 8041            .unwrap_or(true);
 8042
 8043        let is_move = supports_jump
 8044            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8045        let completion = if is_move {
 8046            invalidation_row_range =
 8047                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8048            let target = first_edit_start;
 8049            EditPrediction::MoveWithin { target, snapshot }
 8050        } else {
 8051            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8052                && !self.edit_predictions_hidden_for_vim_mode;
 8053
 8054            if show_completions_in_buffer {
 8055                if let Some(provider) = &self.edit_prediction_provider {
 8056                    provider.provider.did_show(cx);
 8057                }
 8058                if edits
 8059                    .iter()
 8060                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8061                {
 8062                    let mut inlays = Vec::new();
 8063                    for (range, new_text) in &edits {
 8064                        let inlay = Inlay::edit_prediction(
 8065                            post_inc(&mut self.next_inlay_id),
 8066                            range.start,
 8067                            new_text.as_ref(),
 8068                        );
 8069                        inlay_ids.push(inlay.id);
 8070                        inlays.push(inlay);
 8071                    }
 8072
 8073                    self.splice_inlays(&[], inlays, cx);
 8074                } else {
 8075                    let background_color = cx.theme().status().deleted_background;
 8076                    self.highlight_text::<EditPredictionHighlight>(
 8077                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8078                        HighlightStyle {
 8079                            background_color: Some(background_color),
 8080                            ..Default::default()
 8081                        },
 8082                        cx,
 8083                    );
 8084                }
 8085            }
 8086
 8087            invalidation_row_range = edit_start_row..edit_end_row;
 8088
 8089            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8090                if provider.show_tab_accept_marker() {
 8091                    EditDisplayMode::TabAccept
 8092                } else {
 8093                    EditDisplayMode::Inline
 8094                }
 8095            } else {
 8096                EditDisplayMode::DiffPopover
 8097            };
 8098
 8099            EditPrediction::Edit {
 8100                edits,
 8101                edit_preview,
 8102                display_mode,
 8103                snapshot,
 8104            }
 8105        };
 8106
 8107        let invalidation_range = multibuffer
 8108            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8109            ..multibuffer.anchor_after(Point::new(
 8110                invalidation_row_range.end,
 8111                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8112            ));
 8113
 8114        self.stale_edit_prediction_in_menu = None;
 8115        self.active_edit_prediction = Some(EditPredictionState {
 8116            inlay_ids,
 8117            completion,
 8118            completion_id,
 8119            invalidation_range: Some(invalidation_range),
 8120        });
 8121
 8122        cx.notify();
 8123
 8124        Some(())
 8125    }
 8126
 8127    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8128        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8129    }
 8130
 8131    fn clear_tasks(&mut self) {
 8132        self.tasks.clear()
 8133    }
 8134
 8135    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8136        if self.tasks.insert(key, value).is_some() {
 8137            // This case should hopefully be rare, but just in case...
 8138            log::error!(
 8139                "multiple different run targets found on a single line, only the last target will be rendered"
 8140            )
 8141        }
 8142    }
 8143
 8144    /// Get all display points of breakpoints that will be rendered within editor
 8145    ///
 8146    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8147    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8148    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8149    fn active_breakpoints(
 8150        &self,
 8151        range: Range<DisplayRow>,
 8152        window: &mut Window,
 8153        cx: &mut Context<Self>,
 8154    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8155        let mut breakpoint_display_points = HashMap::default();
 8156
 8157        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8158            return breakpoint_display_points;
 8159        };
 8160
 8161        let snapshot = self.snapshot(window, cx);
 8162
 8163        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8164        let Some(project) = self.project() else {
 8165            return breakpoint_display_points;
 8166        };
 8167
 8168        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8169            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8170
 8171        for (buffer_snapshot, range, excerpt_id) in
 8172            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8173        {
 8174            let Some(buffer) = project
 8175                .read(cx)
 8176                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8177            else {
 8178                continue;
 8179            };
 8180            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8181                &buffer,
 8182                Some(
 8183                    buffer_snapshot.anchor_before(range.start)
 8184                        ..buffer_snapshot.anchor_after(range.end),
 8185                ),
 8186                buffer_snapshot,
 8187                cx,
 8188            );
 8189            for (breakpoint, state) in breakpoints {
 8190                let multi_buffer_anchor =
 8191                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8192                let position = multi_buffer_anchor
 8193                    .to_point(&multi_buffer_snapshot)
 8194                    .to_display_point(&snapshot);
 8195
 8196                breakpoint_display_points.insert(
 8197                    position.row(),
 8198                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8199                );
 8200            }
 8201        }
 8202
 8203        breakpoint_display_points
 8204    }
 8205
 8206    fn breakpoint_context_menu(
 8207        &self,
 8208        anchor: Anchor,
 8209        window: &mut Window,
 8210        cx: &mut Context<Self>,
 8211    ) -> Entity<ui::ContextMenu> {
 8212        let weak_editor = cx.weak_entity();
 8213        let focus_handle = self.focus_handle(cx);
 8214
 8215        let row = self
 8216            .buffer
 8217            .read(cx)
 8218            .snapshot(cx)
 8219            .summary_for_anchor::<Point>(&anchor)
 8220            .row;
 8221
 8222        let breakpoint = self
 8223            .breakpoint_at_row(row, window, cx)
 8224            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8225
 8226        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8227            "Edit Log Breakpoint"
 8228        } else {
 8229            "Set Log Breakpoint"
 8230        };
 8231
 8232        let condition_breakpoint_msg = if breakpoint
 8233            .as_ref()
 8234            .is_some_and(|bp| bp.1.condition.is_some())
 8235        {
 8236            "Edit Condition Breakpoint"
 8237        } else {
 8238            "Set Condition Breakpoint"
 8239        };
 8240
 8241        let hit_condition_breakpoint_msg = if breakpoint
 8242            .as_ref()
 8243            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8244        {
 8245            "Edit Hit Condition Breakpoint"
 8246        } else {
 8247            "Set Hit Condition Breakpoint"
 8248        };
 8249
 8250        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8251            "Unset Breakpoint"
 8252        } else {
 8253            "Set Breakpoint"
 8254        };
 8255
 8256        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8257
 8258        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8259            BreakpointState::Enabled => Some("Disable"),
 8260            BreakpointState::Disabled => Some("Enable"),
 8261        });
 8262
 8263        let (anchor, breakpoint) =
 8264            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8265
 8266        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8267            menu.on_blur_subscription(Subscription::new(|| {}))
 8268                .context(focus_handle)
 8269                .when(run_to_cursor, |this| {
 8270                    let weak_editor = weak_editor.clone();
 8271                    this.entry("Run to cursor", None, move |window, cx| {
 8272                        weak_editor
 8273                            .update(cx, |editor, cx| {
 8274                                editor.change_selections(
 8275                                    SelectionEffects::no_scroll(),
 8276                                    window,
 8277                                    cx,
 8278                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8279                                );
 8280                            })
 8281                            .ok();
 8282
 8283                        window.dispatch_action(Box::new(RunToCursor), cx);
 8284                    })
 8285                    .separator()
 8286                })
 8287                .when_some(toggle_state_msg, |this, msg| {
 8288                    this.entry(msg, None, {
 8289                        let weak_editor = weak_editor.clone();
 8290                        let breakpoint = breakpoint.clone();
 8291                        move |_window, cx| {
 8292                            weak_editor
 8293                                .update(cx, |this, cx| {
 8294                                    this.edit_breakpoint_at_anchor(
 8295                                        anchor,
 8296                                        breakpoint.as_ref().clone(),
 8297                                        BreakpointEditAction::InvertState,
 8298                                        cx,
 8299                                    );
 8300                                })
 8301                                .log_err();
 8302                        }
 8303                    })
 8304                })
 8305                .entry(set_breakpoint_msg, None, {
 8306                    let weak_editor = weak_editor.clone();
 8307                    let breakpoint = breakpoint.clone();
 8308                    move |_window, cx| {
 8309                        weak_editor
 8310                            .update(cx, |this, cx| {
 8311                                this.edit_breakpoint_at_anchor(
 8312                                    anchor,
 8313                                    breakpoint.as_ref().clone(),
 8314                                    BreakpointEditAction::Toggle,
 8315                                    cx,
 8316                                );
 8317                            })
 8318                            .log_err();
 8319                    }
 8320                })
 8321                .entry(log_breakpoint_msg, None, {
 8322                    let breakpoint = breakpoint.clone();
 8323                    let weak_editor = weak_editor.clone();
 8324                    move |window, cx| {
 8325                        weak_editor
 8326                            .update(cx, |this, cx| {
 8327                                this.add_edit_breakpoint_block(
 8328                                    anchor,
 8329                                    breakpoint.as_ref(),
 8330                                    BreakpointPromptEditAction::Log,
 8331                                    window,
 8332                                    cx,
 8333                                );
 8334                            })
 8335                            .log_err();
 8336                    }
 8337                })
 8338                .entry(condition_breakpoint_msg, None, {
 8339                    let breakpoint = breakpoint.clone();
 8340                    let weak_editor = weak_editor.clone();
 8341                    move |window, cx| {
 8342                        weak_editor
 8343                            .update(cx, |this, cx| {
 8344                                this.add_edit_breakpoint_block(
 8345                                    anchor,
 8346                                    breakpoint.as_ref(),
 8347                                    BreakpointPromptEditAction::Condition,
 8348                                    window,
 8349                                    cx,
 8350                                );
 8351                            })
 8352                            .log_err();
 8353                    }
 8354                })
 8355                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8356                    weak_editor
 8357                        .update(cx, |this, cx| {
 8358                            this.add_edit_breakpoint_block(
 8359                                anchor,
 8360                                breakpoint.as_ref(),
 8361                                BreakpointPromptEditAction::HitCondition,
 8362                                window,
 8363                                cx,
 8364                            );
 8365                        })
 8366                        .log_err();
 8367                })
 8368        })
 8369    }
 8370
 8371    fn render_breakpoint(
 8372        &self,
 8373        position: Anchor,
 8374        row: DisplayRow,
 8375        breakpoint: &Breakpoint,
 8376        state: Option<BreakpointSessionState>,
 8377        cx: &mut Context<Self>,
 8378    ) -> IconButton {
 8379        let is_rejected = state.is_some_and(|s| !s.verified);
 8380        // Is it a breakpoint that shows up when hovering over gutter?
 8381        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8382            (false, false),
 8383            |PhantomBreakpointIndicator {
 8384                 is_active,
 8385                 display_row,
 8386                 collides_with_existing_breakpoint,
 8387             }| {
 8388                (
 8389                    is_active && display_row == row,
 8390                    collides_with_existing_breakpoint,
 8391                )
 8392            },
 8393        );
 8394
 8395        let (color, icon) = {
 8396            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8397                (false, false) => ui::IconName::DebugBreakpoint,
 8398                (true, false) => ui::IconName::DebugLogBreakpoint,
 8399                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8400                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8401            };
 8402
 8403            let color = if is_phantom {
 8404                Color::Hint
 8405            } else if is_rejected {
 8406                Color::Disabled
 8407            } else {
 8408                Color::Debugger
 8409            };
 8410
 8411            (color, icon)
 8412        };
 8413
 8414        let breakpoint = Arc::from(breakpoint.clone());
 8415
 8416        let alt_as_text = gpui::Keystroke {
 8417            modifiers: Modifiers::secondary_key(),
 8418            ..Default::default()
 8419        };
 8420        let primary_action_text = if breakpoint.is_disabled() {
 8421            "Enable breakpoint"
 8422        } else if is_phantom && !collides_with_existing {
 8423            "Set breakpoint"
 8424        } else {
 8425            "Unset breakpoint"
 8426        };
 8427        let focus_handle = self.focus_handle.clone();
 8428
 8429        let meta = if is_rejected {
 8430            SharedString::from("No executable code is associated with this line.")
 8431        } else if collides_with_existing && !breakpoint.is_disabled() {
 8432            SharedString::from(format!(
 8433                "{alt_as_text}-click to disable,\nright-click for more options."
 8434            ))
 8435        } else {
 8436            SharedString::from("Right-click for more options.")
 8437        };
 8438        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8439            .icon_size(IconSize::XSmall)
 8440            .size(ui::ButtonSize::None)
 8441            .when(is_rejected, |this| {
 8442                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8443            })
 8444            .icon_color(color)
 8445            .style(ButtonStyle::Transparent)
 8446            .on_click(cx.listener({
 8447                move |editor, event: &ClickEvent, window, cx| {
 8448                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8449                        BreakpointEditAction::InvertState
 8450                    } else {
 8451                        BreakpointEditAction::Toggle
 8452                    };
 8453
 8454                    window.focus(&editor.focus_handle(cx));
 8455                    editor.edit_breakpoint_at_anchor(
 8456                        position,
 8457                        breakpoint.as_ref().clone(),
 8458                        edit_action,
 8459                        cx,
 8460                    );
 8461                }
 8462            }))
 8463            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8464                editor.set_breakpoint_context_menu(
 8465                    row,
 8466                    Some(position),
 8467                    event.position(),
 8468                    window,
 8469                    cx,
 8470                );
 8471            }))
 8472            .tooltip(move |_window, cx| {
 8473                Tooltip::with_meta_in(
 8474                    primary_action_text,
 8475                    Some(&ToggleBreakpoint),
 8476                    meta.clone(),
 8477                    &focus_handle,
 8478                    cx,
 8479                )
 8480            })
 8481    }
 8482
 8483    fn build_tasks_context(
 8484        project: &Entity<Project>,
 8485        buffer: &Entity<Buffer>,
 8486        buffer_row: u32,
 8487        tasks: &Arc<RunnableTasks>,
 8488        cx: &mut Context<Self>,
 8489    ) -> Task<Option<task::TaskContext>> {
 8490        let position = Point::new(buffer_row, tasks.column);
 8491        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8492        let location = Location {
 8493            buffer: buffer.clone(),
 8494            range: range_start..range_start,
 8495        };
 8496        // Fill in the environmental variables from the tree-sitter captures
 8497        let mut captured_task_variables = TaskVariables::default();
 8498        for (capture_name, value) in tasks.extra_variables.clone() {
 8499            captured_task_variables.insert(
 8500                task::VariableName::Custom(capture_name.into()),
 8501                value.clone(),
 8502            );
 8503        }
 8504        project.update(cx, |project, cx| {
 8505            project.task_store().update(cx, |task_store, cx| {
 8506                task_store.task_context_for_location(captured_task_variables, location, cx)
 8507            })
 8508        })
 8509    }
 8510
 8511    pub fn spawn_nearest_task(
 8512        &mut self,
 8513        action: &SpawnNearestTask,
 8514        window: &mut Window,
 8515        cx: &mut Context<Self>,
 8516    ) {
 8517        let Some((workspace, _)) = self.workspace.clone() else {
 8518            return;
 8519        };
 8520        let Some(project) = self.project.clone() else {
 8521            return;
 8522        };
 8523
 8524        // Try to find a closest, enclosing node using tree-sitter that has a task
 8525        let Some((buffer, buffer_row, tasks)) = self
 8526            .find_enclosing_node_task(cx)
 8527            // Or find the task that's closest in row-distance.
 8528            .or_else(|| self.find_closest_task(cx))
 8529        else {
 8530            return;
 8531        };
 8532
 8533        let reveal_strategy = action.reveal;
 8534        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8535        cx.spawn_in(window, async move |_, cx| {
 8536            let context = task_context.await?;
 8537            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8538
 8539            let resolved = &mut resolved_task.resolved;
 8540            resolved.reveal = reveal_strategy;
 8541
 8542            workspace
 8543                .update_in(cx, |workspace, window, cx| {
 8544                    workspace.schedule_resolved_task(
 8545                        task_source_kind,
 8546                        resolved_task,
 8547                        false,
 8548                        window,
 8549                        cx,
 8550                    );
 8551                })
 8552                .ok()
 8553        })
 8554        .detach();
 8555    }
 8556
 8557    fn find_closest_task(
 8558        &mut self,
 8559        cx: &mut Context<Self>,
 8560    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8561        let cursor_row = self
 8562            .selections
 8563            .newest_adjusted(&self.display_snapshot(cx))
 8564            .head()
 8565            .row;
 8566
 8567        let ((buffer_id, row), tasks) = self
 8568            .tasks
 8569            .iter()
 8570            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8571
 8572        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8573        let tasks = Arc::new(tasks.to_owned());
 8574        Some((buffer, *row, tasks))
 8575    }
 8576
 8577    fn find_enclosing_node_task(
 8578        &mut self,
 8579        cx: &mut Context<Self>,
 8580    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8581        let snapshot = self.buffer.read(cx).snapshot(cx);
 8582        let offset = self
 8583            .selections
 8584            .newest::<usize>(&self.display_snapshot(cx))
 8585            .head();
 8586        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8587        let buffer_id = excerpt.buffer().remote_id();
 8588
 8589        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8590        let mut cursor = layer.node().walk();
 8591
 8592        while cursor.goto_first_child_for_byte(offset).is_some() {
 8593            if cursor.node().end_byte() == offset {
 8594                cursor.goto_next_sibling();
 8595            }
 8596        }
 8597
 8598        // Ascend to the smallest ancestor that contains the range and has a task.
 8599        loop {
 8600            let node = cursor.node();
 8601            let node_range = node.byte_range();
 8602            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8603
 8604            // Check if this node contains our offset
 8605            if node_range.start <= offset && node_range.end >= offset {
 8606                // If it contains offset, check for task
 8607                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8608                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8609                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8610                }
 8611            }
 8612
 8613            if !cursor.goto_parent() {
 8614                break;
 8615            }
 8616        }
 8617        None
 8618    }
 8619
 8620    fn render_run_indicator(
 8621        &self,
 8622        _style: &EditorStyle,
 8623        is_active: bool,
 8624        row: DisplayRow,
 8625        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8626        cx: &mut Context<Self>,
 8627    ) -> IconButton {
 8628        let color = Color::Muted;
 8629        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8630
 8631        IconButton::new(
 8632            ("run_indicator", row.0 as usize),
 8633            ui::IconName::PlayOutlined,
 8634        )
 8635        .shape(ui::IconButtonShape::Square)
 8636        .icon_size(IconSize::XSmall)
 8637        .icon_color(color)
 8638        .toggle_state(is_active)
 8639        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8640            let quick_launch = match e {
 8641                ClickEvent::Keyboard(_) => true,
 8642                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8643            };
 8644
 8645            window.focus(&editor.focus_handle(cx));
 8646            editor.toggle_code_actions(
 8647                &ToggleCodeActions {
 8648                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8649                    quick_launch,
 8650                },
 8651                window,
 8652                cx,
 8653            );
 8654        }))
 8655        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8656            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8657        }))
 8658    }
 8659
 8660    pub fn context_menu_visible(&self) -> bool {
 8661        !self.edit_prediction_preview_is_active()
 8662            && self
 8663                .context_menu
 8664                .borrow()
 8665                .as_ref()
 8666                .is_some_and(|menu| menu.visible())
 8667    }
 8668
 8669    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8670        self.context_menu
 8671            .borrow()
 8672            .as_ref()
 8673            .map(|menu| menu.origin())
 8674    }
 8675
 8676    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8677        self.context_menu_options = Some(options);
 8678    }
 8679
 8680    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8681    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8682
 8683    fn render_edit_prediction_popover(
 8684        &mut self,
 8685        text_bounds: &Bounds<Pixels>,
 8686        content_origin: gpui::Point<Pixels>,
 8687        right_margin: Pixels,
 8688        editor_snapshot: &EditorSnapshot,
 8689        visible_row_range: Range<DisplayRow>,
 8690        scroll_top: ScrollOffset,
 8691        scroll_bottom: ScrollOffset,
 8692        line_layouts: &[LineWithInvisibles],
 8693        line_height: Pixels,
 8694        scroll_position: gpui::Point<ScrollOffset>,
 8695        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8696        newest_selection_head: Option<DisplayPoint>,
 8697        editor_width: Pixels,
 8698        style: &EditorStyle,
 8699        window: &mut Window,
 8700        cx: &mut App,
 8701    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8702        if self.mode().is_minimap() {
 8703            return None;
 8704        }
 8705        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8706
 8707        if self.edit_prediction_visible_in_cursor_popover(true) {
 8708            return None;
 8709        }
 8710
 8711        match &active_edit_prediction.completion {
 8712            EditPrediction::MoveWithin { target, .. } => {
 8713                let target_display_point = target.to_display_point(editor_snapshot);
 8714
 8715                if self.edit_prediction_requires_modifier() {
 8716                    if !self.edit_prediction_preview_is_active() {
 8717                        return None;
 8718                    }
 8719
 8720                    self.render_edit_prediction_modifier_jump_popover(
 8721                        text_bounds,
 8722                        content_origin,
 8723                        visible_row_range,
 8724                        line_layouts,
 8725                        line_height,
 8726                        scroll_pixel_position,
 8727                        newest_selection_head,
 8728                        target_display_point,
 8729                        window,
 8730                        cx,
 8731                    )
 8732                } else {
 8733                    self.render_edit_prediction_eager_jump_popover(
 8734                        text_bounds,
 8735                        content_origin,
 8736                        editor_snapshot,
 8737                        visible_row_range,
 8738                        scroll_top,
 8739                        scroll_bottom,
 8740                        line_height,
 8741                        scroll_pixel_position,
 8742                        target_display_point,
 8743                        editor_width,
 8744                        window,
 8745                        cx,
 8746                    )
 8747                }
 8748            }
 8749            EditPrediction::Edit {
 8750                display_mode: EditDisplayMode::Inline,
 8751                ..
 8752            } => None,
 8753            EditPrediction::Edit {
 8754                display_mode: EditDisplayMode::TabAccept,
 8755                edits,
 8756                ..
 8757            } => {
 8758                let range = &edits.first()?.0;
 8759                let target_display_point = range.end.to_display_point(editor_snapshot);
 8760
 8761                self.render_edit_prediction_end_of_line_popover(
 8762                    "Accept",
 8763                    editor_snapshot,
 8764                    visible_row_range,
 8765                    target_display_point,
 8766                    line_height,
 8767                    scroll_pixel_position,
 8768                    content_origin,
 8769                    editor_width,
 8770                    window,
 8771                    cx,
 8772                )
 8773            }
 8774            EditPrediction::Edit {
 8775                edits,
 8776                edit_preview,
 8777                display_mode: EditDisplayMode::DiffPopover,
 8778                snapshot,
 8779            } => self.render_edit_prediction_diff_popover(
 8780                text_bounds,
 8781                content_origin,
 8782                right_margin,
 8783                editor_snapshot,
 8784                visible_row_range,
 8785                line_layouts,
 8786                line_height,
 8787                scroll_position,
 8788                scroll_pixel_position,
 8789                newest_selection_head,
 8790                editor_width,
 8791                style,
 8792                edits,
 8793                edit_preview,
 8794                snapshot,
 8795                window,
 8796                cx,
 8797            ),
 8798            EditPrediction::MoveOutside { snapshot, .. } => {
 8799                let file_name = snapshot
 8800                    .file()
 8801                    .map(|file| file.file_name(cx))
 8802                    .unwrap_or("untitled");
 8803                let mut element = self
 8804                    .render_edit_prediction_line_popover(
 8805                        format!("Jump to {file_name}"),
 8806                        Some(IconName::ZedPredict),
 8807                        window,
 8808                        cx,
 8809                    )
 8810                    .into_any();
 8811
 8812                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8813                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8814                let origin_y = text_bounds.size.height - size.height - px(30.);
 8815                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8816                element.prepaint_at(origin, window, cx);
 8817
 8818                Some((element, origin))
 8819            }
 8820        }
 8821    }
 8822
 8823    fn render_edit_prediction_modifier_jump_popover(
 8824        &mut self,
 8825        text_bounds: &Bounds<Pixels>,
 8826        content_origin: gpui::Point<Pixels>,
 8827        visible_row_range: Range<DisplayRow>,
 8828        line_layouts: &[LineWithInvisibles],
 8829        line_height: Pixels,
 8830        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8831        newest_selection_head: Option<DisplayPoint>,
 8832        target_display_point: DisplayPoint,
 8833        window: &mut Window,
 8834        cx: &mut App,
 8835    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8836        let scrolled_content_origin =
 8837            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8838
 8839        const SCROLL_PADDING_Y: Pixels = px(12.);
 8840
 8841        if target_display_point.row() < visible_row_range.start {
 8842            return self.render_edit_prediction_scroll_popover(
 8843                |_| SCROLL_PADDING_Y,
 8844                IconName::ArrowUp,
 8845                visible_row_range,
 8846                line_layouts,
 8847                newest_selection_head,
 8848                scrolled_content_origin,
 8849                window,
 8850                cx,
 8851            );
 8852        } else if target_display_point.row() >= visible_row_range.end {
 8853            return self.render_edit_prediction_scroll_popover(
 8854                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8855                IconName::ArrowDown,
 8856                visible_row_range,
 8857                line_layouts,
 8858                newest_selection_head,
 8859                scrolled_content_origin,
 8860                window,
 8861                cx,
 8862            );
 8863        }
 8864
 8865        const POLE_WIDTH: Pixels = px(2.);
 8866
 8867        let line_layout =
 8868            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8869        let target_column = target_display_point.column() as usize;
 8870
 8871        let target_x = line_layout.x_for_index(target_column);
 8872        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8873            - scroll_pixel_position.y;
 8874
 8875        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8876
 8877        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8878        border_color.l += 0.001;
 8879
 8880        let mut element = v_flex()
 8881            .items_end()
 8882            .when(flag_on_right, |el| el.items_start())
 8883            .child(if flag_on_right {
 8884                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8885                    .rounded_bl(px(0.))
 8886                    .rounded_tl(px(0.))
 8887                    .border_l_2()
 8888                    .border_color(border_color)
 8889            } else {
 8890                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8891                    .rounded_br(px(0.))
 8892                    .rounded_tr(px(0.))
 8893                    .border_r_2()
 8894                    .border_color(border_color)
 8895            })
 8896            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8897            .into_any();
 8898
 8899        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8900
 8901        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8902            - point(
 8903                if flag_on_right {
 8904                    POLE_WIDTH
 8905                } else {
 8906                    size.width - POLE_WIDTH
 8907                },
 8908                size.height - line_height,
 8909            );
 8910
 8911        origin.x = origin.x.max(content_origin.x);
 8912
 8913        element.prepaint_at(origin, window, cx);
 8914
 8915        Some((element, origin))
 8916    }
 8917
 8918    fn render_edit_prediction_scroll_popover(
 8919        &mut self,
 8920        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8921        scroll_icon: IconName,
 8922        visible_row_range: Range<DisplayRow>,
 8923        line_layouts: &[LineWithInvisibles],
 8924        newest_selection_head: Option<DisplayPoint>,
 8925        scrolled_content_origin: gpui::Point<Pixels>,
 8926        window: &mut Window,
 8927        cx: &mut App,
 8928    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8929        let mut element = self
 8930            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8931            .into_any();
 8932
 8933        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8934
 8935        let cursor = newest_selection_head?;
 8936        let cursor_row_layout =
 8937            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8938        let cursor_column = cursor.column() as usize;
 8939
 8940        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8941
 8942        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8943
 8944        element.prepaint_at(origin, window, cx);
 8945        Some((element, origin))
 8946    }
 8947
 8948    fn render_edit_prediction_eager_jump_popover(
 8949        &mut self,
 8950        text_bounds: &Bounds<Pixels>,
 8951        content_origin: gpui::Point<Pixels>,
 8952        editor_snapshot: &EditorSnapshot,
 8953        visible_row_range: Range<DisplayRow>,
 8954        scroll_top: ScrollOffset,
 8955        scroll_bottom: ScrollOffset,
 8956        line_height: Pixels,
 8957        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8958        target_display_point: DisplayPoint,
 8959        editor_width: Pixels,
 8960        window: &mut Window,
 8961        cx: &mut App,
 8962    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8963        if target_display_point.row().as_f64() < scroll_top {
 8964            let mut element = self
 8965                .render_edit_prediction_line_popover(
 8966                    "Jump to Edit",
 8967                    Some(IconName::ArrowUp),
 8968                    window,
 8969                    cx,
 8970                )
 8971                .into_any();
 8972
 8973            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8974            let offset = point(
 8975                (text_bounds.size.width - size.width) / 2.,
 8976                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8977            );
 8978
 8979            let origin = text_bounds.origin + offset;
 8980            element.prepaint_at(origin, window, cx);
 8981            Some((element, origin))
 8982        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8983            let mut element = self
 8984                .render_edit_prediction_line_popover(
 8985                    "Jump to Edit",
 8986                    Some(IconName::ArrowDown),
 8987                    window,
 8988                    cx,
 8989                )
 8990                .into_any();
 8991
 8992            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8993            let offset = point(
 8994                (text_bounds.size.width - size.width) / 2.,
 8995                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8996            );
 8997
 8998            let origin = text_bounds.origin + offset;
 8999            element.prepaint_at(origin, window, cx);
 9000            Some((element, origin))
 9001        } else {
 9002            self.render_edit_prediction_end_of_line_popover(
 9003                "Jump to Edit",
 9004                editor_snapshot,
 9005                visible_row_range,
 9006                target_display_point,
 9007                line_height,
 9008                scroll_pixel_position,
 9009                content_origin,
 9010                editor_width,
 9011                window,
 9012                cx,
 9013            )
 9014        }
 9015    }
 9016
 9017    fn render_edit_prediction_end_of_line_popover(
 9018        self: &mut Editor,
 9019        label: &'static str,
 9020        editor_snapshot: &EditorSnapshot,
 9021        visible_row_range: Range<DisplayRow>,
 9022        target_display_point: DisplayPoint,
 9023        line_height: Pixels,
 9024        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9025        content_origin: gpui::Point<Pixels>,
 9026        editor_width: Pixels,
 9027        window: &mut Window,
 9028        cx: &mut App,
 9029    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9030        let target_line_end = DisplayPoint::new(
 9031            target_display_point.row(),
 9032            editor_snapshot.line_len(target_display_point.row()),
 9033        );
 9034
 9035        let mut element = self
 9036            .render_edit_prediction_line_popover(label, None, window, cx)
 9037            .into_any();
 9038
 9039        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9040
 9041        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9042
 9043        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9044        let mut origin = start_point
 9045            + line_origin
 9046            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9047        origin.x = origin.x.max(content_origin.x);
 9048
 9049        let max_x = content_origin.x + editor_width - size.width;
 9050
 9051        if origin.x > max_x {
 9052            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9053
 9054            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9055                origin.y += offset;
 9056                IconName::ArrowUp
 9057            } else {
 9058                origin.y -= offset;
 9059                IconName::ArrowDown
 9060            };
 9061
 9062            element = self
 9063                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9064                .into_any();
 9065
 9066            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9067
 9068            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9069        }
 9070
 9071        element.prepaint_at(origin, window, cx);
 9072        Some((element, origin))
 9073    }
 9074
 9075    fn render_edit_prediction_diff_popover(
 9076        self: &Editor,
 9077        text_bounds: &Bounds<Pixels>,
 9078        content_origin: gpui::Point<Pixels>,
 9079        right_margin: Pixels,
 9080        editor_snapshot: &EditorSnapshot,
 9081        visible_row_range: Range<DisplayRow>,
 9082        line_layouts: &[LineWithInvisibles],
 9083        line_height: Pixels,
 9084        scroll_position: gpui::Point<ScrollOffset>,
 9085        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9086        newest_selection_head: Option<DisplayPoint>,
 9087        editor_width: Pixels,
 9088        style: &EditorStyle,
 9089        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9090        edit_preview: &Option<language::EditPreview>,
 9091        snapshot: &language::BufferSnapshot,
 9092        window: &mut Window,
 9093        cx: &mut App,
 9094    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9095        let edit_start = edits
 9096            .first()
 9097            .unwrap()
 9098            .0
 9099            .start
 9100            .to_display_point(editor_snapshot);
 9101        let edit_end = edits
 9102            .last()
 9103            .unwrap()
 9104            .0
 9105            .end
 9106            .to_display_point(editor_snapshot);
 9107
 9108        let is_visible = visible_row_range.contains(&edit_start.row())
 9109            || visible_row_range.contains(&edit_end.row());
 9110        if !is_visible {
 9111            return None;
 9112        }
 9113
 9114        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9115            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9116        } else {
 9117            // Fallback for providers without edit_preview
 9118            crate::edit_prediction_fallback_text(edits, cx)
 9119        };
 9120
 9121        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9122        let line_count = highlighted_edits.text.lines().count();
 9123
 9124        const BORDER_WIDTH: Pixels = px(1.);
 9125
 9126        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9127        let has_keybind = keybind.is_some();
 9128
 9129        let mut element = h_flex()
 9130            .items_start()
 9131            .child(
 9132                h_flex()
 9133                    .bg(cx.theme().colors().editor_background)
 9134                    .border(BORDER_WIDTH)
 9135                    .shadow_xs()
 9136                    .border_color(cx.theme().colors().border)
 9137                    .rounded_l_lg()
 9138                    .when(line_count > 1, |el| el.rounded_br_lg())
 9139                    .pr_1()
 9140                    .child(styled_text),
 9141            )
 9142            .child(
 9143                h_flex()
 9144                    .h(line_height + BORDER_WIDTH * 2.)
 9145                    .px_1p5()
 9146                    .gap_1()
 9147                    // Workaround: For some reason, there's a gap if we don't do this
 9148                    .ml(-BORDER_WIDTH)
 9149                    .shadow(vec![gpui::BoxShadow {
 9150                        color: gpui::black().opacity(0.05),
 9151                        offset: point(px(1.), px(1.)),
 9152                        blur_radius: px(2.),
 9153                        spread_radius: px(0.),
 9154                    }])
 9155                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9156                    .border(BORDER_WIDTH)
 9157                    .border_color(cx.theme().colors().border)
 9158                    .rounded_r_lg()
 9159                    .id("edit_prediction_diff_popover_keybind")
 9160                    .when(!has_keybind, |el| {
 9161                        let status_colors = cx.theme().status();
 9162
 9163                        el.bg(status_colors.error_background)
 9164                            .border_color(status_colors.error.opacity(0.6))
 9165                            .child(Icon::new(IconName::Info).color(Color::Error))
 9166                            .cursor_default()
 9167                            .hoverable_tooltip(move |_window, cx| {
 9168                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9169                            })
 9170                    })
 9171                    .children(keybind),
 9172            )
 9173            .into_any();
 9174
 9175        let longest_row =
 9176            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9177        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9178            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9179        } else {
 9180            layout_line(
 9181                longest_row,
 9182                editor_snapshot,
 9183                style,
 9184                editor_width,
 9185                |_| false,
 9186                window,
 9187                cx,
 9188            )
 9189            .width
 9190        };
 9191
 9192        let viewport_bounds =
 9193            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9194                right: -right_margin,
 9195                ..Default::default()
 9196            });
 9197
 9198        let x_after_longest = Pixels::from(
 9199            ScrollPixelOffset::from(
 9200                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9201            ) - scroll_pixel_position.x,
 9202        );
 9203
 9204        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9205
 9206        // Fully visible if it can be displayed within the window (allow overlapping other
 9207        // panes). However, this is only allowed if the popover starts within text_bounds.
 9208        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9209            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9210
 9211        let mut origin = if can_position_to_the_right {
 9212            point(
 9213                x_after_longest,
 9214                text_bounds.origin.y
 9215                    + Pixels::from(
 9216                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9217                            - scroll_pixel_position.y,
 9218                    ),
 9219            )
 9220        } else {
 9221            let cursor_row = newest_selection_head.map(|head| head.row());
 9222            let above_edit = edit_start
 9223                .row()
 9224                .0
 9225                .checked_sub(line_count as u32)
 9226                .map(DisplayRow);
 9227            let below_edit = Some(edit_end.row() + 1);
 9228            let above_cursor =
 9229                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9230            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9231
 9232            // Place the edit popover adjacent to the edit if there is a location
 9233            // available that is onscreen and does not obscure the cursor. Otherwise,
 9234            // place it adjacent to the cursor.
 9235            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9236                .into_iter()
 9237                .flatten()
 9238                .find(|&start_row| {
 9239                    let end_row = start_row + line_count as u32;
 9240                    visible_row_range.contains(&start_row)
 9241                        && visible_row_range.contains(&end_row)
 9242                        && cursor_row
 9243                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9244                })?;
 9245
 9246            content_origin
 9247                + point(
 9248                    Pixels::from(-scroll_pixel_position.x),
 9249                    Pixels::from(
 9250                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9251                    ),
 9252                )
 9253        };
 9254
 9255        origin.x -= BORDER_WIDTH;
 9256
 9257        window.defer_draw(element, origin, 1);
 9258
 9259        // Do not return an element, since it will already be drawn due to defer_draw.
 9260        None
 9261    }
 9262
 9263    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9264        px(30.)
 9265    }
 9266
 9267    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9268        if self.read_only(cx) {
 9269            cx.theme().players().read_only()
 9270        } else {
 9271            self.style.as_ref().unwrap().local_player
 9272        }
 9273    }
 9274
 9275    fn render_edit_prediction_accept_keybind(
 9276        &self,
 9277        window: &mut Window,
 9278        cx: &mut App,
 9279    ) -> Option<AnyElement> {
 9280        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9281        let accept_keystroke = accept_binding.keystroke()?;
 9282
 9283        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9284
 9285        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9286            Color::Accent
 9287        } else {
 9288            Color::Muted
 9289        };
 9290
 9291        h_flex()
 9292            .px_0p5()
 9293            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9294            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9295            .text_size(TextSize::XSmall.rems(cx))
 9296            .child(h_flex().children(ui::render_modifiers(
 9297                accept_keystroke.modifiers(),
 9298                PlatformStyle::platform(),
 9299                Some(modifiers_color),
 9300                Some(IconSize::XSmall.rems().into()),
 9301                true,
 9302            )))
 9303            .when(is_platform_style_mac, |parent| {
 9304                parent.child(accept_keystroke.key().to_string())
 9305            })
 9306            .when(!is_platform_style_mac, |parent| {
 9307                parent.child(
 9308                    Key::new(
 9309                        util::capitalize(accept_keystroke.key()),
 9310                        Some(Color::Default),
 9311                    )
 9312                    .size(Some(IconSize::XSmall.rems().into())),
 9313                )
 9314            })
 9315            .into_any()
 9316            .into()
 9317    }
 9318
 9319    fn render_edit_prediction_line_popover(
 9320        &self,
 9321        label: impl Into<SharedString>,
 9322        icon: Option<IconName>,
 9323        window: &mut Window,
 9324        cx: &mut App,
 9325    ) -> Stateful<Div> {
 9326        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9327
 9328        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9329        let has_keybind = keybind.is_some();
 9330
 9331        h_flex()
 9332            .id("ep-line-popover")
 9333            .py_0p5()
 9334            .pl_1()
 9335            .pr(padding_right)
 9336            .gap_1()
 9337            .rounded_md()
 9338            .border_1()
 9339            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9340            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9341            .shadow_xs()
 9342            .when(!has_keybind, |el| {
 9343                let status_colors = cx.theme().status();
 9344
 9345                el.bg(status_colors.error_background)
 9346                    .border_color(status_colors.error.opacity(0.6))
 9347                    .pl_2()
 9348                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9349                    .cursor_default()
 9350                    .hoverable_tooltip(move |_window, cx| {
 9351                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9352                    })
 9353            })
 9354            .children(keybind)
 9355            .child(
 9356                Label::new(label)
 9357                    .size(LabelSize::Small)
 9358                    .when(!has_keybind, |el| {
 9359                        el.color(cx.theme().status().error.into()).strikethrough()
 9360                    }),
 9361            )
 9362            .when(!has_keybind, |el| {
 9363                el.child(
 9364                    h_flex().ml_1().child(
 9365                        Icon::new(IconName::Info)
 9366                            .size(IconSize::Small)
 9367                            .color(cx.theme().status().error.into()),
 9368                    ),
 9369                )
 9370            })
 9371            .when_some(icon, |element, icon| {
 9372                element.child(
 9373                    div()
 9374                        .mt(px(1.5))
 9375                        .child(Icon::new(icon).size(IconSize::Small)),
 9376                )
 9377            })
 9378    }
 9379
 9380    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9381        let accent_color = cx.theme().colors().text_accent;
 9382        let editor_bg_color = cx.theme().colors().editor_background;
 9383        editor_bg_color.blend(accent_color.opacity(0.1))
 9384    }
 9385
 9386    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9387        let accent_color = cx.theme().colors().text_accent;
 9388        let editor_bg_color = cx.theme().colors().editor_background;
 9389        editor_bg_color.blend(accent_color.opacity(0.6))
 9390    }
 9391    fn get_prediction_provider_icon_name(
 9392        provider: &Option<RegisteredEditPredictionProvider>,
 9393    ) -> IconName {
 9394        match provider {
 9395            Some(provider) => match provider.provider.name() {
 9396                "copilot" => IconName::Copilot,
 9397                "supermaven" => IconName::Supermaven,
 9398                _ => IconName::ZedPredict,
 9399            },
 9400            None => IconName::ZedPredict,
 9401        }
 9402    }
 9403
 9404    fn render_edit_prediction_cursor_popover(
 9405        &self,
 9406        min_width: Pixels,
 9407        max_width: Pixels,
 9408        cursor_point: Point,
 9409        style: &EditorStyle,
 9410        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9411        _window: &Window,
 9412        cx: &mut Context<Editor>,
 9413    ) -> Option<AnyElement> {
 9414        let provider = self.edit_prediction_provider.as_ref()?;
 9415        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9416
 9417        let is_refreshing = provider.provider.is_refreshing(cx);
 9418
 9419        fn pending_completion_container(icon: IconName) -> Div {
 9420            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9421        }
 9422
 9423        let completion = match &self.active_edit_prediction {
 9424            Some(prediction) => {
 9425                if !self.has_visible_completions_menu() {
 9426                    const RADIUS: Pixels = px(6.);
 9427                    const BORDER_WIDTH: Pixels = px(1.);
 9428
 9429                    return Some(
 9430                        h_flex()
 9431                            .elevation_2(cx)
 9432                            .border(BORDER_WIDTH)
 9433                            .border_color(cx.theme().colors().border)
 9434                            .when(accept_keystroke.is_none(), |el| {
 9435                                el.border_color(cx.theme().status().error)
 9436                            })
 9437                            .rounded(RADIUS)
 9438                            .rounded_tl(px(0.))
 9439                            .overflow_hidden()
 9440                            .child(div().px_1p5().child(match &prediction.completion {
 9441                                EditPrediction::MoveWithin { target, snapshot } => {
 9442                                    use text::ToPoint as _;
 9443                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9444                                    {
 9445                                        Icon::new(IconName::ZedPredictDown)
 9446                                    } else {
 9447                                        Icon::new(IconName::ZedPredictUp)
 9448                                    }
 9449                                }
 9450                                EditPrediction::MoveOutside { .. } => {
 9451                                    // TODO [zeta2] custom icon for external jump?
 9452                                    Icon::new(provider_icon)
 9453                                }
 9454                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9455                            }))
 9456                            .child(
 9457                                h_flex()
 9458                                    .gap_1()
 9459                                    .py_1()
 9460                                    .px_2()
 9461                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9462                                    .border_l_1()
 9463                                    .border_color(cx.theme().colors().border)
 9464                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9465                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9466                                        el.child(
 9467                                            Label::new("Hold")
 9468                                                .size(LabelSize::Small)
 9469                                                .when(accept_keystroke.is_none(), |el| {
 9470                                                    el.strikethrough()
 9471                                                })
 9472                                                .line_height_style(LineHeightStyle::UiLabel),
 9473                                        )
 9474                                    })
 9475                                    .id("edit_prediction_cursor_popover_keybind")
 9476                                    .when(accept_keystroke.is_none(), |el| {
 9477                                        let status_colors = cx.theme().status();
 9478
 9479                                        el.bg(status_colors.error_background)
 9480                                            .border_color(status_colors.error.opacity(0.6))
 9481                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9482                                            .cursor_default()
 9483                                            .hoverable_tooltip(move |_window, cx| {
 9484                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9485                                                    .into()
 9486                                            })
 9487                                    })
 9488                                    .when_some(
 9489                                        accept_keystroke.as_ref(),
 9490                                        |el, accept_keystroke| {
 9491                                            el.child(h_flex().children(ui::render_modifiers(
 9492                                                accept_keystroke.modifiers(),
 9493                                                PlatformStyle::platform(),
 9494                                                Some(Color::Default),
 9495                                                Some(IconSize::XSmall.rems().into()),
 9496                                                false,
 9497                                            )))
 9498                                        },
 9499                                    ),
 9500                            )
 9501                            .into_any(),
 9502                    );
 9503                }
 9504
 9505                self.render_edit_prediction_cursor_popover_preview(
 9506                    prediction,
 9507                    cursor_point,
 9508                    style,
 9509                    cx,
 9510                )?
 9511            }
 9512
 9513            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9514                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9515                    stale_completion,
 9516                    cursor_point,
 9517                    style,
 9518                    cx,
 9519                )?,
 9520
 9521                None => pending_completion_container(provider_icon)
 9522                    .child(Label::new("...").size(LabelSize::Small)),
 9523            },
 9524
 9525            None => pending_completion_container(provider_icon)
 9526                .child(Label::new("...").size(LabelSize::Small)),
 9527        };
 9528
 9529        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9530            completion
 9531                .with_animation(
 9532                    "loading-completion",
 9533                    Animation::new(Duration::from_secs(2))
 9534                        .repeat()
 9535                        .with_easing(pulsating_between(0.4, 0.8)),
 9536                    |label, delta| label.opacity(delta),
 9537                )
 9538                .into_any_element()
 9539        } else {
 9540            completion.into_any_element()
 9541        };
 9542
 9543        let has_completion = self.active_edit_prediction.is_some();
 9544
 9545        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9546        Some(
 9547            h_flex()
 9548                .min_w(min_width)
 9549                .max_w(max_width)
 9550                .flex_1()
 9551                .elevation_2(cx)
 9552                .border_color(cx.theme().colors().border)
 9553                .child(
 9554                    div()
 9555                        .flex_1()
 9556                        .py_1()
 9557                        .px_2()
 9558                        .overflow_hidden()
 9559                        .child(completion),
 9560                )
 9561                .when_some(accept_keystroke, |el, accept_keystroke| {
 9562                    if !accept_keystroke.modifiers().modified() {
 9563                        return el;
 9564                    }
 9565
 9566                    el.child(
 9567                        h_flex()
 9568                            .h_full()
 9569                            .border_l_1()
 9570                            .rounded_r_lg()
 9571                            .border_color(cx.theme().colors().border)
 9572                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9573                            .gap_1()
 9574                            .py_1()
 9575                            .px_2()
 9576                            .child(
 9577                                h_flex()
 9578                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9579                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9580                                    .child(h_flex().children(ui::render_modifiers(
 9581                                        accept_keystroke.modifiers(),
 9582                                        PlatformStyle::platform(),
 9583                                        Some(if !has_completion {
 9584                                            Color::Muted
 9585                                        } else {
 9586                                            Color::Default
 9587                                        }),
 9588                                        None,
 9589                                        false,
 9590                                    ))),
 9591                            )
 9592                            .child(Label::new("Preview").into_any_element())
 9593                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9594                    )
 9595                })
 9596                .into_any(),
 9597        )
 9598    }
 9599
 9600    fn render_edit_prediction_cursor_popover_preview(
 9601        &self,
 9602        completion: &EditPredictionState,
 9603        cursor_point: Point,
 9604        style: &EditorStyle,
 9605        cx: &mut Context<Editor>,
 9606    ) -> Option<Div> {
 9607        use text::ToPoint as _;
 9608
 9609        fn render_relative_row_jump(
 9610            prefix: impl Into<String>,
 9611            current_row: u32,
 9612            target_row: u32,
 9613        ) -> Div {
 9614            let (row_diff, arrow) = if target_row < current_row {
 9615                (current_row - target_row, IconName::ArrowUp)
 9616            } else {
 9617                (target_row - current_row, IconName::ArrowDown)
 9618            };
 9619
 9620            h_flex()
 9621                .child(
 9622                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9623                        .color(Color::Muted)
 9624                        .size(LabelSize::Small),
 9625                )
 9626                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9627        }
 9628
 9629        let supports_jump = self
 9630            .edit_prediction_provider
 9631            .as_ref()
 9632            .map(|provider| provider.provider.supports_jump_to_edit())
 9633            .unwrap_or(true);
 9634
 9635        match &completion.completion {
 9636            EditPrediction::MoveWithin {
 9637                target, snapshot, ..
 9638            } => {
 9639                if !supports_jump {
 9640                    return None;
 9641                }
 9642
 9643                Some(
 9644                    h_flex()
 9645                        .px_2()
 9646                        .gap_2()
 9647                        .flex_1()
 9648                        .child(
 9649                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9650                                Icon::new(IconName::ZedPredictDown)
 9651                            } else {
 9652                                Icon::new(IconName::ZedPredictUp)
 9653                            },
 9654                        )
 9655                        .child(Label::new("Jump to Edit")),
 9656                )
 9657            }
 9658            EditPrediction::MoveOutside { snapshot, .. } => {
 9659                let file_name = snapshot
 9660                    .file()
 9661                    .map(|file| file.file_name(cx))
 9662                    .unwrap_or("untitled");
 9663                Some(
 9664                    h_flex()
 9665                        .px_2()
 9666                        .gap_2()
 9667                        .flex_1()
 9668                        .child(Icon::new(IconName::ZedPredict))
 9669                        .child(Label::new(format!("Jump to {file_name}"))),
 9670                )
 9671            }
 9672            EditPrediction::Edit {
 9673                edits,
 9674                edit_preview,
 9675                snapshot,
 9676                display_mode: _,
 9677            } => {
 9678                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9679
 9680                let (highlighted_edits, has_more_lines) =
 9681                    if let Some(edit_preview) = edit_preview.as_ref() {
 9682                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9683                            .first_line_preview()
 9684                    } else {
 9685                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9686                    };
 9687
 9688                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9689                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9690
 9691                let preview = h_flex()
 9692                    .gap_1()
 9693                    .min_w_16()
 9694                    .child(styled_text)
 9695                    .when(has_more_lines, |parent| parent.child(""));
 9696
 9697                let left = if supports_jump && first_edit_row != cursor_point.row {
 9698                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9699                        .into_any_element()
 9700                } else {
 9701                    let icon_name =
 9702                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9703                    Icon::new(icon_name).into_any_element()
 9704                };
 9705
 9706                Some(
 9707                    h_flex()
 9708                        .h_full()
 9709                        .flex_1()
 9710                        .gap_2()
 9711                        .pr_1()
 9712                        .overflow_x_hidden()
 9713                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9714                        .child(left)
 9715                        .child(preview),
 9716                )
 9717            }
 9718        }
 9719    }
 9720
 9721    pub fn render_context_menu(
 9722        &self,
 9723        style: &EditorStyle,
 9724        max_height_in_lines: u32,
 9725        window: &mut Window,
 9726        cx: &mut Context<Editor>,
 9727    ) -> Option<AnyElement> {
 9728        let menu = self.context_menu.borrow();
 9729        let menu = menu.as_ref()?;
 9730        if !menu.visible() {
 9731            return None;
 9732        };
 9733        Some(menu.render(style, max_height_in_lines, window, cx))
 9734    }
 9735
 9736    fn render_context_menu_aside(
 9737        &mut self,
 9738        max_size: Size<Pixels>,
 9739        window: &mut Window,
 9740        cx: &mut Context<Editor>,
 9741    ) -> Option<AnyElement> {
 9742        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9743            if menu.visible() {
 9744                menu.render_aside(max_size, window, cx)
 9745            } else {
 9746                None
 9747            }
 9748        })
 9749    }
 9750
 9751    fn hide_context_menu(
 9752        &mut self,
 9753        window: &mut Window,
 9754        cx: &mut Context<Self>,
 9755    ) -> Option<CodeContextMenu> {
 9756        cx.notify();
 9757        self.completion_tasks.clear();
 9758        let context_menu = self.context_menu.borrow_mut().take();
 9759        self.stale_edit_prediction_in_menu.take();
 9760        self.update_visible_edit_prediction(window, cx);
 9761        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9762            && let Some(completion_provider) = &self.completion_provider
 9763        {
 9764            completion_provider.selection_changed(None, window, cx);
 9765        }
 9766        context_menu
 9767    }
 9768
 9769    fn show_snippet_choices(
 9770        &mut self,
 9771        choices: &Vec<String>,
 9772        selection: Range<Anchor>,
 9773        cx: &mut Context<Self>,
 9774    ) {
 9775        let Some((_, buffer, _)) = self
 9776            .buffer()
 9777            .read(cx)
 9778            .excerpt_containing(selection.start, cx)
 9779        else {
 9780            return;
 9781        };
 9782        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9783        else {
 9784            return;
 9785        };
 9786        if buffer != end_buffer {
 9787            log::error!("expected anchor range to have matching buffer IDs");
 9788            return;
 9789        }
 9790
 9791        let id = post_inc(&mut self.next_completion_id);
 9792        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9793        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9794            CompletionsMenu::new_snippet_choices(
 9795                id,
 9796                true,
 9797                choices,
 9798                selection,
 9799                buffer,
 9800                snippet_sort_order,
 9801            ),
 9802        ));
 9803    }
 9804
 9805    pub fn insert_snippet(
 9806        &mut self,
 9807        insertion_ranges: &[Range<usize>],
 9808        snippet: Snippet,
 9809        window: &mut Window,
 9810        cx: &mut Context<Self>,
 9811    ) -> Result<()> {
 9812        struct Tabstop<T> {
 9813            is_end_tabstop: bool,
 9814            ranges: Vec<Range<T>>,
 9815            choices: Option<Vec<String>>,
 9816        }
 9817
 9818        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9819            let snippet_text: Arc<str> = snippet.text.clone().into();
 9820            let edits = insertion_ranges
 9821                .iter()
 9822                .cloned()
 9823                .map(|range| (range, snippet_text.clone()));
 9824            let autoindent_mode = AutoindentMode::Block {
 9825                original_indent_columns: Vec::new(),
 9826            };
 9827            buffer.edit(edits, Some(autoindent_mode), cx);
 9828
 9829            let snapshot = &*buffer.read(cx);
 9830            let snippet = &snippet;
 9831            snippet
 9832                .tabstops
 9833                .iter()
 9834                .map(|tabstop| {
 9835                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9836                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9837                    });
 9838                    let mut tabstop_ranges = tabstop
 9839                        .ranges
 9840                        .iter()
 9841                        .flat_map(|tabstop_range| {
 9842                            let mut delta = 0_isize;
 9843                            insertion_ranges.iter().map(move |insertion_range| {
 9844                                let insertion_start = insertion_range.start as isize + delta;
 9845                                delta +=
 9846                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9847
 9848                                let start = ((insertion_start + tabstop_range.start) as usize)
 9849                                    .min(snapshot.len());
 9850                                let end = ((insertion_start + tabstop_range.end) as usize)
 9851                                    .min(snapshot.len());
 9852                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9853                            })
 9854                        })
 9855                        .collect::<Vec<_>>();
 9856                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9857
 9858                    Tabstop {
 9859                        is_end_tabstop,
 9860                        ranges: tabstop_ranges,
 9861                        choices: tabstop.choices.clone(),
 9862                    }
 9863                })
 9864                .collect::<Vec<_>>()
 9865        });
 9866        if let Some(tabstop) = tabstops.first() {
 9867            self.change_selections(Default::default(), window, cx, |s| {
 9868                // Reverse order so that the first range is the newest created selection.
 9869                // Completions will use it and autoscroll will prioritize it.
 9870                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9871            });
 9872
 9873            if let Some(choices) = &tabstop.choices
 9874                && let Some(selection) = tabstop.ranges.first()
 9875            {
 9876                self.show_snippet_choices(choices, selection.clone(), cx)
 9877            }
 9878
 9879            // If we're already at the last tabstop and it's at the end of the snippet,
 9880            // we're done, we don't need to keep the state around.
 9881            if !tabstop.is_end_tabstop {
 9882                let choices = tabstops
 9883                    .iter()
 9884                    .map(|tabstop| tabstop.choices.clone())
 9885                    .collect();
 9886
 9887                let ranges = tabstops
 9888                    .into_iter()
 9889                    .map(|tabstop| tabstop.ranges)
 9890                    .collect::<Vec<_>>();
 9891
 9892                self.snippet_stack.push(SnippetState {
 9893                    active_index: 0,
 9894                    ranges,
 9895                    choices,
 9896                });
 9897            }
 9898
 9899            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9900            if self.autoclose_regions.is_empty() {
 9901                let snapshot = self.buffer.read(cx).snapshot(cx);
 9902                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9903                    let selection_head = selection.head();
 9904                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9905                        continue;
 9906                    };
 9907
 9908                    let mut bracket_pair = None;
 9909                    let max_lookup_length = scope
 9910                        .brackets()
 9911                        .map(|(pair, _)| {
 9912                            pair.start
 9913                                .as_str()
 9914                                .chars()
 9915                                .count()
 9916                                .max(pair.end.as_str().chars().count())
 9917                        })
 9918                        .max();
 9919                    if let Some(max_lookup_length) = max_lookup_length {
 9920                        let next_text = snapshot
 9921                            .chars_at(selection_head)
 9922                            .take(max_lookup_length)
 9923                            .collect::<String>();
 9924                        let prev_text = snapshot
 9925                            .reversed_chars_at(selection_head)
 9926                            .take(max_lookup_length)
 9927                            .collect::<String>();
 9928
 9929                        for (pair, enabled) in scope.brackets() {
 9930                            if enabled
 9931                                && pair.close
 9932                                && prev_text.starts_with(pair.start.as_str())
 9933                                && next_text.starts_with(pair.end.as_str())
 9934                            {
 9935                                bracket_pair = Some(pair.clone());
 9936                                break;
 9937                            }
 9938                        }
 9939                    }
 9940
 9941                    if let Some(pair) = bracket_pair {
 9942                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9943                        let autoclose_enabled =
 9944                            self.use_autoclose && snapshot_settings.use_autoclose;
 9945                        if autoclose_enabled {
 9946                            let start = snapshot.anchor_after(selection_head);
 9947                            let end = snapshot.anchor_after(selection_head);
 9948                            self.autoclose_regions.push(AutocloseRegion {
 9949                                selection_id: selection.id,
 9950                                range: start..end,
 9951                                pair,
 9952                            });
 9953                        }
 9954                    }
 9955                }
 9956            }
 9957        }
 9958        Ok(())
 9959    }
 9960
 9961    pub fn move_to_next_snippet_tabstop(
 9962        &mut self,
 9963        window: &mut Window,
 9964        cx: &mut Context<Self>,
 9965    ) -> bool {
 9966        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9967    }
 9968
 9969    pub fn move_to_prev_snippet_tabstop(
 9970        &mut self,
 9971        window: &mut Window,
 9972        cx: &mut Context<Self>,
 9973    ) -> bool {
 9974        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9975    }
 9976
 9977    pub fn move_to_snippet_tabstop(
 9978        &mut self,
 9979        bias: Bias,
 9980        window: &mut Window,
 9981        cx: &mut Context<Self>,
 9982    ) -> bool {
 9983        if let Some(mut snippet) = self.snippet_stack.pop() {
 9984            match bias {
 9985                Bias::Left => {
 9986                    if snippet.active_index > 0 {
 9987                        snippet.active_index -= 1;
 9988                    } else {
 9989                        self.snippet_stack.push(snippet);
 9990                        return false;
 9991                    }
 9992                }
 9993                Bias::Right => {
 9994                    if snippet.active_index + 1 < snippet.ranges.len() {
 9995                        snippet.active_index += 1;
 9996                    } else {
 9997                        self.snippet_stack.push(snippet);
 9998                        return false;
 9999                    }
10000                }
10001            }
10002            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10003                self.change_selections(Default::default(), window, cx, |s| {
10004                    // Reverse order so that the first range is the newest created selection.
10005                    // Completions will use it and autoscroll will prioritize it.
10006                    s.select_ranges(current_ranges.iter().rev().cloned())
10007                });
10008
10009                if let Some(choices) = &snippet.choices[snippet.active_index]
10010                    && let Some(selection) = current_ranges.first()
10011                {
10012                    self.show_snippet_choices(choices, selection.clone(), cx);
10013                }
10014
10015                // If snippet state is not at the last tabstop, push it back on the stack
10016                if snippet.active_index + 1 < snippet.ranges.len() {
10017                    self.snippet_stack.push(snippet);
10018                }
10019                return true;
10020            }
10021        }
10022
10023        false
10024    }
10025
10026    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10027        self.transact(window, cx, |this, window, cx| {
10028            this.select_all(&SelectAll, window, cx);
10029            this.insert("", window, cx);
10030        });
10031    }
10032
10033    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10034        if self.read_only(cx) {
10035            return;
10036        }
10037        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10038        self.transact(window, cx, |this, window, cx| {
10039            this.select_autoclose_pair(window, cx);
10040
10041            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10042
10043            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10044            if !this.linked_edit_ranges.is_empty() {
10045                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10046                let snapshot = this.buffer.read(cx).snapshot(cx);
10047
10048                for selection in selections.iter() {
10049                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10050                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10051                    if selection_start.buffer_id != selection_end.buffer_id {
10052                        continue;
10053                    }
10054                    if let Some(ranges) =
10055                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10056                    {
10057                        for (buffer, entries) in ranges {
10058                            linked_ranges.entry(buffer).or_default().extend(entries);
10059                        }
10060                    }
10061                }
10062            }
10063
10064            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10065            for selection in &mut selections {
10066                if selection.is_empty() {
10067                    let old_head = selection.head();
10068                    let mut new_head =
10069                        movement::left(&display_map, old_head.to_display_point(&display_map))
10070                            .to_point(&display_map);
10071                    if let Some((buffer, line_buffer_range)) = display_map
10072                        .buffer_snapshot()
10073                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10074                    {
10075                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10076                        let indent_len = match indent_size.kind {
10077                            IndentKind::Space => {
10078                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10079                            }
10080                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10081                        };
10082                        if old_head.column <= indent_size.len && old_head.column > 0 {
10083                            let indent_len = indent_len.get();
10084                            new_head = cmp::min(
10085                                new_head,
10086                                MultiBufferPoint::new(
10087                                    old_head.row,
10088                                    ((old_head.column - 1) / indent_len) * indent_len,
10089                                ),
10090                            );
10091                        }
10092                    }
10093
10094                    selection.set_head(new_head, SelectionGoal::None);
10095                }
10096            }
10097
10098            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10099            this.insert("", window, cx);
10100            let empty_str: Arc<str> = Arc::from("");
10101            for (buffer, edits) in linked_ranges {
10102                let snapshot = buffer.read(cx).snapshot();
10103                use text::ToPoint as TP;
10104
10105                let edits = edits
10106                    .into_iter()
10107                    .map(|range| {
10108                        let end_point = TP::to_point(&range.end, &snapshot);
10109                        let mut start_point = TP::to_point(&range.start, &snapshot);
10110
10111                        if end_point == start_point {
10112                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10113                                .saturating_sub(1);
10114                            start_point =
10115                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10116                        };
10117
10118                        (start_point..end_point, empty_str.clone())
10119                    })
10120                    .sorted_by_key(|(range, _)| range.start)
10121                    .collect::<Vec<_>>();
10122                buffer.update(cx, |this, cx| {
10123                    this.edit(edits, None, cx);
10124                })
10125            }
10126            this.refresh_edit_prediction(true, false, window, cx);
10127            refresh_linked_ranges(this, window, cx);
10128        });
10129    }
10130
10131    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10132        if self.read_only(cx) {
10133            return;
10134        }
10135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10136        self.transact(window, cx, |this, window, cx| {
10137            this.change_selections(Default::default(), window, cx, |s| {
10138                s.move_with(|map, selection| {
10139                    if selection.is_empty() {
10140                        let cursor = movement::right(map, selection.head());
10141                        selection.end = cursor;
10142                        selection.reversed = true;
10143                        selection.goal = SelectionGoal::None;
10144                    }
10145                })
10146            });
10147            this.insert("", window, cx);
10148            this.refresh_edit_prediction(true, false, window, cx);
10149        });
10150    }
10151
10152    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10153        if self.mode.is_single_line() {
10154            cx.propagate();
10155            return;
10156        }
10157
10158        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10159        if self.move_to_prev_snippet_tabstop(window, cx) {
10160            return;
10161        }
10162        self.outdent(&Outdent, window, cx);
10163    }
10164
10165    pub fn next_snippet_tabstop(
10166        &mut self,
10167        _: &NextSnippetTabstop,
10168        window: &mut Window,
10169        cx: &mut Context<Self>,
10170    ) {
10171        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10172            cx.propagate();
10173            return;
10174        }
10175
10176        if self.move_to_next_snippet_tabstop(window, cx) {
10177            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10178            return;
10179        }
10180        cx.propagate();
10181    }
10182
10183    pub fn previous_snippet_tabstop(
10184        &mut self,
10185        _: &PreviousSnippetTabstop,
10186        window: &mut Window,
10187        cx: &mut Context<Self>,
10188    ) {
10189        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10190            cx.propagate();
10191            return;
10192        }
10193
10194        if self.move_to_prev_snippet_tabstop(window, cx) {
10195            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10196            return;
10197        }
10198        cx.propagate();
10199    }
10200
10201    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10202        if self.mode.is_single_line() {
10203            cx.propagate();
10204            return;
10205        }
10206
10207        if self.move_to_next_snippet_tabstop(window, cx) {
10208            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10209            return;
10210        }
10211        if self.read_only(cx) {
10212            return;
10213        }
10214        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10215        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10216        let buffer = self.buffer.read(cx);
10217        let snapshot = buffer.snapshot(cx);
10218        let rows_iter = selections.iter().map(|s| s.head().row);
10219        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10220
10221        let has_some_cursor_in_whitespace = selections
10222            .iter()
10223            .filter(|selection| selection.is_empty())
10224            .any(|selection| {
10225                let cursor = selection.head();
10226                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10227                cursor.column < current_indent.len
10228            });
10229
10230        let mut edits = Vec::new();
10231        let mut prev_edited_row = 0;
10232        let mut row_delta = 0;
10233        for selection in &mut selections {
10234            if selection.start.row != prev_edited_row {
10235                row_delta = 0;
10236            }
10237            prev_edited_row = selection.end.row;
10238
10239            // If the selection is non-empty, then increase the indentation of the selected lines.
10240            if !selection.is_empty() {
10241                row_delta =
10242                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10243                continue;
10244            }
10245
10246            let cursor = selection.head();
10247            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10248            if let Some(suggested_indent) =
10249                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10250            {
10251                // Don't do anything if already at suggested indent
10252                // and there is any other cursor which is not
10253                if has_some_cursor_in_whitespace
10254                    && cursor.column == current_indent.len
10255                    && current_indent.len == suggested_indent.len
10256                {
10257                    continue;
10258                }
10259
10260                // Adjust line and move cursor to suggested indent
10261                // if cursor is not at suggested indent
10262                if cursor.column < suggested_indent.len
10263                    && cursor.column <= current_indent.len
10264                    && current_indent.len <= suggested_indent.len
10265                {
10266                    selection.start = Point::new(cursor.row, suggested_indent.len);
10267                    selection.end = selection.start;
10268                    if row_delta == 0 {
10269                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10270                            cursor.row,
10271                            current_indent,
10272                            suggested_indent,
10273                        ));
10274                        row_delta = suggested_indent.len - current_indent.len;
10275                    }
10276                    continue;
10277                }
10278
10279                // If current indent is more than suggested indent
10280                // only move cursor to current indent and skip indent
10281                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10282                    selection.start = Point::new(cursor.row, current_indent.len);
10283                    selection.end = selection.start;
10284                    continue;
10285                }
10286            }
10287
10288            // Otherwise, insert a hard or soft tab.
10289            let settings = buffer.language_settings_at(cursor, cx);
10290            let tab_size = if settings.hard_tabs {
10291                IndentSize::tab()
10292            } else {
10293                let tab_size = settings.tab_size.get();
10294                let indent_remainder = snapshot
10295                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10296                    .flat_map(str::chars)
10297                    .fold(row_delta % tab_size, |counter: u32, c| {
10298                        if c == '\t' {
10299                            0
10300                        } else {
10301                            (counter + 1) % tab_size
10302                        }
10303                    });
10304
10305                let chars_to_next_tab_stop = tab_size - indent_remainder;
10306                IndentSize::spaces(chars_to_next_tab_stop)
10307            };
10308            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10309            selection.end = selection.start;
10310            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10311            row_delta += tab_size.len;
10312        }
10313
10314        self.transact(window, cx, |this, window, cx| {
10315            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10316            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10317            this.refresh_edit_prediction(true, false, window, cx);
10318        });
10319    }
10320
10321    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10322        if self.read_only(cx) {
10323            return;
10324        }
10325        if self.mode.is_single_line() {
10326            cx.propagate();
10327            return;
10328        }
10329
10330        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10331        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10332        let mut prev_edited_row = 0;
10333        let mut row_delta = 0;
10334        let mut edits = Vec::new();
10335        let buffer = self.buffer.read(cx);
10336        let snapshot = buffer.snapshot(cx);
10337        for selection in &mut selections {
10338            if selection.start.row != prev_edited_row {
10339                row_delta = 0;
10340            }
10341            prev_edited_row = selection.end.row;
10342
10343            row_delta =
10344                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10345        }
10346
10347        self.transact(window, cx, |this, window, cx| {
10348            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10349            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10350        });
10351    }
10352
10353    fn indent_selection(
10354        buffer: &MultiBuffer,
10355        snapshot: &MultiBufferSnapshot,
10356        selection: &mut Selection<Point>,
10357        edits: &mut Vec<(Range<Point>, String)>,
10358        delta_for_start_row: u32,
10359        cx: &App,
10360    ) -> u32 {
10361        let settings = buffer.language_settings_at(selection.start, cx);
10362        let tab_size = settings.tab_size.get();
10363        let indent_kind = if settings.hard_tabs {
10364            IndentKind::Tab
10365        } else {
10366            IndentKind::Space
10367        };
10368        let mut start_row = selection.start.row;
10369        let mut end_row = selection.end.row + 1;
10370
10371        // If a selection ends at the beginning of a line, don't indent
10372        // that last line.
10373        if selection.end.column == 0 && selection.end.row > selection.start.row {
10374            end_row -= 1;
10375        }
10376
10377        // Avoid re-indenting a row that has already been indented by a
10378        // previous selection, but still update this selection's column
10379        // to reflect that indentation.
10380        if delta_for_start_row > 0 {
10381            start_row += 1;
10382            selection.start.column += delta_for_start_row;
10383            if selection.end.row == selection.start.row {
10384                selection.end.column += delta_for_start_row;
10385            }
10386        }
10387
10388        let mut delta_for_end_row = 0;
10389        let has_multiple_rows = start_row + 1 != end_row;
10390        for row in start_row..end_row {
10391            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10392            let indent_delta = match (current_indent.kind, indent_kind) {
10393                (IndentKind::Space, IndentKind::Space) => {
10394                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10395                    IndentSize::spaces(columns_to_next_tab_stop)
10396                }
10397                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10398                (_, IndentKind::Tab) => IndentSize::tab(),
10399            };
10400
10401            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10402                0
10403            } else {
10404                selection.start.column
10405            };
10406            let row_start = Point::new(row, start);
10407            edits.push((
10408                row_start..row_start,
10409                indent_delta.chars().collect::<String>(),
10410            ));
10411
10412            // Update this selection's endpoints to reflect the indentation.
10413            if row == selection.start.row {
10414                selection.start.column += indent_delta.len;
10415            }
10416            if row == selection.end.row {
10417                selection.end.column += indent_delta.len;
10418                delta_for_end_row = indent_delta.len;
10419            }
10420        }
10421
10422        if selection.start.row == selection.end.row {
10423            delta_for_start_row + delta_for_end_row
10424        } else {
10425            delta_for_end_row
10426        }
10427    }
10428
10429    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10430        if self.read_only(cx) {
10431            return;
10432        }
10433        if self.mode.is_single_line() {
10434            cx.propagate();
10435            return;
10436        }
10437
10438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10439        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10440        let selections = self.selections.all::<Point>(&display_map);
10441        let mut deletion_ranges = Vec::new();
10442        let mut last_outdent = None;
10443        {
10444            let buffer = self.buffer.read(cx);
10445            let snapshot = buffer.snapshot(cx);
10446            for selection in &selections {
10447                let settings = buffer.language_settings_at(selection.start, cx);
10448                let tab_size = settings.tab_size.get();
10449                let mut rows = selection.spanned_rows(false, &display_map);
10450
10451                // Avoid re-outdenting a row that has already been outdented by a
10452                // previous selection.
10453                if let Some(last_row) = last_outdent
10454                    && last_row == rows.start
10455                {
10456                    rows.start = rows.start.next_row();
10457                }
10458                let has_multiple_rows = rows.len() > 1;
10459                for row in rows.iter_rows() {
10460                    let indent_size = snapshot.indent_size_for_line(row);
10461                    if indent_size.len > 0 {
10462                        let deletion_len = match indent_size.kind {
10463                            IndentKind::Space => {
10464                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10465                                if columns_to_prev_tab_stop == 0 {
10466                                    tab_size
10467                                } else {
10468                                    columns_to_prev_tab_stop
10469                                }
10470                            }
10471                            IndentKind::Tab => 1,
10472                        };
10473                        let start = if has_multiple_rows
10474                            || deletion_len > selection.start.column
10475                            || indent_size.len < selection.start.column
10476                        {
10477                            0
10478                        } else {
10479                            selection.start.column - deletion_len
10480                        };
10481                        deletion_ranges.push(
10482                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10483                        );
10484                        last_outdent = Some(row);
10485                    }
10486                }
10487            }
10488        }
10489
10490        self.transact(window, cx, |this, window, cx| {
10491            this.buffer.update(cx, |buffer, cx| {
10492                let empty_str: Arc<str> = Arc::default();
10493                buffer.edit(
10494                    deletion_ranges
10495                        .into_iter()
10496                        .map(|range| (range, empty_str.clone())),
10497                    None,
10498                    cx,
10499                );
10500            });
10501            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10502            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10503        });
10504    }
10505
10506    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10507        if self.read_only(cx) {
10508            return;
10509        }
10510        if self.mode.is_single_line() {
10511            cx.propagate();
10512            return;
10513        }
10514
10515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10516        let selections = self
10517            .selections
10518            .all::<usize>(&self.display_snapshot(cx))
10519            .into_iter()
10520            .map(|s| s.range());
10521
10522        self.transact(window, cx, |this, window, cx| {
10523            this.buffer.update(cx, |buffer, cx| {
10524                buffer.autoindent_ranges(selections, cx);
10525            });
10526            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10527            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10528        });
10529    }
10530
10531    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10534        let selections = self.selections.all::<Point>(&display_map);
10535
10536        let mut new_cursors = Vec::new();
10537        let mut edit_ranges = Vec::new();
10538        let mut selections = selections.iter().peekable();
10539        while let Some(selection) = selections.next() {
10540            let mut rows = selection.spanned_rows(false, &display_map);
10541
10542            // Accumulate contiguous regions of rows that we want to delete.
10543            while let Some(next_selection) = selections.peek() {
10544                let next_rows = next_selection.spanned_rows(false, &display_map);
10545                if next_rows.start <= rows.end {
10546                    rows.end = next_rows.end;
10547                    selections.next().unwrap();
10548                } else {
10549                    break;
10550                }
10551            }
10552
10553            let buffer = display_map.buffer_snapshot();
10554            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10555            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10556                // If there's a line after the range, delete the \n from the end of the row range
10557                (
10558                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10559                    rows.end,
10560                )
10561            } else {
10562                // If there isn't a line after the range, delete the \n from the line before the
10563                // start of the row range
10564                edit_start = edit_start.saturating_sub(1);
10565                (buffer.len(), rows.start.previous_row())
10566            };
10567
10568            let text_layout_details = self.text_layout_details(window);
10569            let x = display_map.x_for_display_point(
10570                selection.head().to_display_point(&display_map),
10571                &text_layout_details,
10572            );
10573            let row = Point::new(target_row.0, 0)
10574                .to_display_point(&display_map)
10575                .row();
10576            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10577
10578            new_cursors.push((
10579                selection.id,
10580                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10581                SelectionGoal::None,
10582            ));
10583            edit_ranges.push(edit_start..edit_end);
10584        }
10585
10586        self.transact(window, cx, |this, window, cx| {
10587            let buffer = this.buffer.update(cx, |buffer, cx| {
10588                let empty_str: Arc<str> = Arc::default();
10589                buffer.edit(
10590                    edit_ranges
10591                        .into_iter()
10592                        .map(|range| (range, empty_str.clone())),
10593                    None,
10594                    cx,
10595                );
10596                buffer.snapshot(cx)
10597            });
10598            let new_selections = new_cursors
10599                .into_iter()
10600                .map(|(id, cursor, goal)| {
10601                    let cursor = cursor.to_point(&buffer);
10602                    Selection {
10603                        id,
10604                        start: cursor,
10605                        end: cursor,
10606                        reversed: false,
10607                        goal,
10608                    }
10609                })
10610                .collect();
10611
10612            this.change_selections(Default::default(), window, cx, |s| {
10613                s.select(new_selections);
10614            });
10615        });
10616    }
10617
10618    pub fn join_lines_impl(
10619        &mut self,
10620        insert_whitespace: bool,
10621        window: &mut Window,
10622        cx: &mut Context<Self>,
10623    ) {
10624        if self.read_only(cx) {
10625            return;
10626        }
10627        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10628        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10629            let start = MultiBufferRow(selection.start.row);
10630            // Treat single line selections as if they include the next line. Otherwise this action
10631            // would do nothing for single line selections individual cursors.
10632            let end = if selection.start.row == selection.end.row {
10633                MultiBufferRow(selection.start.row + 1)
10634            } else {
10635                MultiBufferRow(selection.end.row)
10636            };
10637
10638            if let Some(last_row_range) = row_ranges.last_mut()
10639                && start <= last_row_range.end
10640            {
10641                last_row_range.end = end;
10642                continue;
10643            }
10644            row_ranges.push(start..end);
10645        }
10646
10647        let snapshot = self.buffer.read(cx).snapshot(cx);
10648        let mut cursor_positions = Vec::new();
10649        for row_range in &row_ranges {
10650            let anchor = snapshot.anchor_before(Point::new(
10651                row_range.end.previous_row().0,
10652                snapshot.line_len(row_range.end.previous_row()),
10653            ));
10654            cursor_positions.push(anchor..anchor);
10655        }
10656
10657        self.transact(window, cx, |this, window, cx| {
10658            for row_range in row_ranges.into_iter().rev() {
10659                for row in row_range.iter_rows().rev() {
10660                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10661                    let next_line_row = row.next_row();
10662                    let indent = snapshot.indent_size_for_line(next_line_row);
10663                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10664
10665                    let replace =
10666                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10667                            " "
10668                        } else {
10669                            ""
10670                        };
10671
10672                    this.buffer.update(cx, |buffer, cx| {
10673                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10674                    });
10675                }
10676            }
10677
10678            this.change_selections(Default::default(), window, cx, |s| {
10679                s.select_anchor_ranges(cursor_positions)
10680            });
10681        });
10682    }
10683
10684    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10685        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10686        self.join_lines_impl(true, window, cx);
10687    }
10688
10689    pub fn sort_lines_case_sensitive(
10690        &mut self,
10691        _: &SortLinesCaseSensitive,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10696    }
10697
10698    pub fn sort_lines_by_length(
10699        &mut self,
10700        _: &SortLinesByLength,
10701        window: &mut Window,
10702        cx: &mut Context<Self>,
10703    ) {
10704        self.manipulate_immutable_lines(window, cx, |lines| {
10705            lines.sort_by_key(|&line| line.chars().count())
10706        })
10707    }
10708
10709    pub fn sort_lines_case_insensitive(
10710        &mut self,
10711        _: &SortLinesCaseInsensitive,
10712        window: &mut Window,
10713        cx: &mut Context<Self>,
10714    ) {
10715        self.manipulate_immutable_lines(window, cx, |lines| {
10716            lines.sort_by_key(|line| line.to_lowercase())
10717        })
10718    }
10719
10720    pub fn unique_lines_case_insensitive(
10721        &mut self,
10722        _: &UniqueLinesCaseInsensitive,
10723        window: &mut Window,
10724        cx: &mut Context<Self>,
10725    ) {
10726        self.manipulate_immutable_lines(window, cx, |lines| {
10727            let mut seen = HashSet::default();
10728            lines.retain(|line| seen.insert(line.to_lowercase()));
10729        })
10730    }
10731
10732    pub fn unique_lines_case_sensitive(
10733        &mut self,
10734        _: &UniqueLinesCaseSensitive,
10735        window: &mut Window,
10736        cx: &mut Context<Self>,
10737    ) {
10738        self.manipulate_immutable_lines(window, cx, |lines| {
10739            let mut seen = HashSet::default();
10740            lines.retain(|line| seen.insert(*line));
10741        })
10742    }
10743
10744    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10745        let snapshot = self.buffer.read(cx).snapshot(cx);
10746        for selection in self.selections.disjoint_anchors_arc().iter() {
10747            if snapshot
10748                .language_at(selection.start)
10749                .and_then(|lang| lang.config().wrap_characters.as_ref())
10750                .is_some()
10751            {
10752                return true;
10753            }
10754        }
10755        false
10756    }
10757
10758    fn wrap_selections_in_tag(
10759        &mut self,
10760        _: &WrapSelectionsInTag,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) {
10764        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10765
10766        let snapshot = self.buffer.read(cx).snapshot(cx);
10767
10768        let mut edits = Vec::new();
10769        let mut boundaries = Vec::new();
10770
10771        for selection in self
10772            .selections
10773            .all_adjusted(&self.display_snapshot(cx))
10774            .iter()
10775        {
10776            let Some(wrap_config) = snapshot
10777                .language_at(selection.start)
10778                .and_then(|lang| lang.config().wrap_characters.clone())
10779            else {
10780                continue;
10781            };
10782
10783            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10784            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10785
10786            let start_before = snapshot.anchor_before(selection.start);
10787            let end_after = snapshot.anchor_after(selection.end);
10788
10789            edits.push((start_before..start_before, open_tag));
10790            edits.push((end_after..end_after, close_tag));
10791
10792            boundaries.push((
10793                start_before,
10794                end_after,
10795                wrap_config.start_prefix.len(),
10796                wrap_config.end_suffix.len(),
10797            ));
10798        }
10799
10800        if edits.is_empty() {
10801            return;
10802        }
10803
10804        self.transact(window, cx, |this, window, cx| {
10805            let buffer = this.buffer.update(cx, |buffer, cx| {
10806                buffer.edit(edits, None, cx);
10807                buffer.snapshot(cx)
10808            });
10809
10810            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10811            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10812                boundaries.into_iter()
10813            {
10814                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10815                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10816                new_selections.push(open_offset..open_offset);
10817                new_selections.push(close_offset..close_offset);
10818            }
10819
10820            this.change_selections(Default::default(), window, cx, |s| {
10821                s.select_ranges(new_selections);
10822            });
10823
10824            this.request_autoscroll(Autoscroll::fit(), cx);
10825        });
10826    }
10827
10828    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10829        let Some(project) = self.project.clone() else {
10830            return;
10831        };
10832        self.reload(project, window, cx)
10833            .detach_and_notify_err(window, cx);
10834    }
10835
10836    pub fn restore_file(
10837        &mut self,
10838        _: &::git::RestoreFile,
10839        window: &mut Window,
10840        cx: &mut Context<Self>,
10841    ) {
10842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10843        let mut buffer_ids = HashSet::default();
10844        let snapshot = self.buffer().read(cx).snapshot(cx);
10845        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10846            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10847        }
10848
10849        let buffer = self.buffer().read(cx);
10850        let ranges = buffer_ids
10851            .into_iter()
10852            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10853            .collect::<Vec<_>>();
10854
10855        self.restore_hunks_in_ranges(ranges, window, cx);
10856    }
10857
10858    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10860        let selections = self
10861            .selections
10862            .all(&self.display_snapshot(cx))
10863            .into_iter()
10864            .map(|s| s.range())
10865            .collect();
10866        self.restore_hunks_in_ranges(selections, window, cx);
10867    }
10868
10869    pub fn restore_hunks_in_ranges(
10870        &mut self,
10871        ranges: Vec<Range<Point>>,
10872        window: &mut Window,
10873        cx: &mut Context<Editor>,
10874    ) {
10875        let mut revert_changes = HashMap::default();
10876        let chunk_by = self
10877            .snapshot(window, cx)
10878            .hunks_for_ranges(ranges)
10879            .into_iter()
10880            .chunk_by(|hunk| hunk.buffer_id);
10881        for (buffer_id, hunks) in &chunk_by {
10882            let hunks = hunks.collect::<Vec<_>>();
10883            for hunk in &hunks {
10884                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10885            }
10886            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10887        }
10888        drop(chunk_by);
10889        if !revert_changes.is_empty() {
10890            self.transact(window, cx, |editor, window, cx| {
10891                editor.restore(revert_changes, window, cx);
10892            });
10893        }
10894    }
10895
10896    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10897        if let Some(status) = self
10898            .addons
10899            .iter()
10900            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10901        {
10902            return Some(status);
10903        }
10904        self.project
10905            .as_ref()?
10906            .read(cx)
10907            .status_for_buffer_id(buffer_id, cx)
10908    }
10909
10910    pub fn open_active_item_in_terminal(
10911        &mut self,
10912        _: &OpenInTerminal,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10917            let project_path = buffer.read(cx).project_path(cx)?;
10918            let project = self.project()?.read(cx);
10919            let entry = project.entry_for_path(&project_path, cx)?;
10920            let parent = match &entry.canonical_path {
10921                Some(canonical_path) => canonical_path.to_path_buf(),
10922                None => project.absolute_path(&project_path, cx)?,
10923            }
10924            .parent()?
10925            .to_path_buf();
10926            Some(parent)
10927        }) {
10928            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10929        }
10930    }
10931
10932    fn set_breakpoint_context_menu(
10933        &mut self,
10934        display_row: DisplayRow,
10935        position: Option<Anchor>,
10936        clicked_point: gpui::Point<Pixels>,
10937        window: &mut Window,
10938        cx: &mut Context<Self>,
10939    ) {
10940        let source = self
10941            .buffer
10942            .read(cx)
10943            .snapshot(cx)
10944            .anchor_before(Point::new(display_row.0, 0u32));
10945
10946        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10947
10948        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10949            self,
10950            source,
10951            clicked_point,
10952            context_menu,
10953            window,
10954            cx,
10955        );
10956    }
10957
10958    fn add_edit_breakpoint_block(
10959        &mut self,
10960        anchor: Anchor,
10961        breakpoint: &Breakpoint,
10962        edit_action: BreakpointPromptEditAction,
10963        window: &mut Window,
10964        cx: &mut Context<Self>,
10965    ) {
10966        let weak_editor = cx.weak_entity();
10967        let bp_prompt = cx.new(|cx| {
10968            BreakpointPromptEditor::new(
10969                weak_editor,
10970                anchor,
10971                breakpoint.clone(),
10972                edit_action,
10973                window,
10974                cx,
10975            )
10976        });
10977
10978        let height = bp_prompt.update(cx, |this, cx| {
10979            this.prompt
10980                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10981        });
10982        let cloned_prompt = bp_prompt.clone();
10983        let blocks = vec![BlockProperties {
10984            style: BlockStyle::Sticky,
10985            placement: BlockPlacement::Above(anchor),
10986            height: Some(height),
10987            render: Arc::new(move |cx| {
10988                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10989                cloned_prompt.clone().into_any_element()
10990            }),
10991            priority: 0,
10992        }];
10993
10994        let focus_handle = bp_prompt.focus_handle(cx);
10995        window.focus(&focus_handle);
10996
10997        let block_ids = self.insert_blocks(blocks, None, cx);
10998        bp_prompt.update(cx, |prompt, _| {
10999            prompt.add_block_ids(block_ids);
11000        });
11001    }
11002
11003    pub(crate) fn breakpoint_at_row(
11004        &self,
11005        row: u32,
11006        window: &mut Window,
11007        cx: &mut Context<Self>,
11008    ) -> Option<(Anchor, Breakpoint)> {
11009        let snapshot = self.snapshot(window, cx);
11010        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11011
11012        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11013    }
11014
11015    pub(crate) fn breakpoint_at_anchor(
11016        &self,
11017        breakpoint_position: Anchor,
11018        snapshot: &EditorSnapshot,
11019        cx: &mut Context<Self>,
11020    ) -> Option<(Anchor, Breakpoint)> {
11021        let buffer = self
11022            .buffer
11023            .read(cx)
11024            .buffer_for_anchor(breakpoint_position, cx)?;
11025
11026        let enclosing_excerpt = breakpoint_position.excerpt_id;
11027        let buffer_snapshot = buffer.read(cx).snapshot();
11028
11029        let row = buffer_snapshot
11030            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11031            .row;
11032
11033        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11034        let anchor_end = snapshot
11035            .buffer_snapshot()
11036            .anchor_after(Point::new(row, line_len));
11037
11038        self.breakpoint_store
11039            .as_ref()?
11040            .read_with(cx, |breakpoint_store, cx| {
11041                breakpoint_store
11042                    .breakpoints(
11043                        &buffer,
11044                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11045                        &buffer_snapshot,
11046                        cx,
11047                    )
11048                    .next()
11049                    .and_then(|(bp, _)| {
11050                        let breakpoint_row = buffer_snapshot
11051                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11052                            .row;
11053
11054                        if breakpoint_row == row {
11055                            snapshot
11056                                .buffer_snapshot()
11057                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11058                                .map(|position| (position, bp.bp.clone()))
11059                        } else {
11060                            None
11061                        }
11062                    })
11063            })
11064    }
11065
11066    pub fn edit_log_breakpoint(
11067        &mut self,
11068        _: &EditLogBreakpoint,
11069        window: &mut Window,
11070        cx: &mut Context<Self>,
11071    ) {
11072        if self.breakpoint_store.is_none() {
11073            return;
11074        }
11075
11076        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11077            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11078                message: None,
11079                state: BreakpointState::Enabled,
11080                condition: None,
11081                hit_condition: None,
11082            });
11083
11084            self.add_edit_breakpoint_block(
11085                anchor,
11086                &breakpoint,
11087                BreakpointPromptEditAction::Log,
11088                window,
11089                cx,
11090            );
11091        }
11092    }
11093
11094    fn breakpoints_at_cursors(
11095        &self,
11096        window: &mut Window,
11097        cx: &mut Context<Self>,
11098    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11099        let snapshot = self.snapshot(window, cx);
11100        let cursors = self
11101            .selections
11102            .disjoint_anchors_arc()
11103            .iter()
11104            .map(|selection| {
11105                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11106
11107                let breakpoint_position = self
11108                    .breakpoint_at_row(cursor_position.row, window, cx)
11109                    .map(|bp| bp.0)
11110                    .unwrap_or_else(|| {
11111                        snapshot
11112                            .display_snapshot
11113                            .buffer_snapshot()
11114                            .anchor_after(Point::new(cursor_position.row, 0))
11115                    });
11116
11117                let breakpoint = self
11118                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11119                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11120
11121                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11122            })
11123            // 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.
11124            .collect::<HashMap<Anchor, _>>();
11125
11126        cursors.into_iter().collect()
11127    }
11128
11129    pub fn enable_breakpoint(
11130        &mut self,
11131        _: &crate::actions::EnableBreakpoint,
11132        window: &mut Window,
11133        cx: &mut Context<Self>,
11134    ) {
11135        if self.breakpoint_store.is_none() {
11136            return;
11137        }
11138
11139        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11140            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11141                continue;
11142            };
11143            self.edit_breakpoint_at_anchor(
11144                anchor,
11145                breakpoint,
11146                BreakpointEditAction::InvertState,
11147                cx,
11148            );
11149        }
11150    }
11151
11152    pub fn disable_breakpoint(
11153        &mut self,
11154        _: &crate::actions::DisableBreakpoint,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157    ) {
11158        if self.breakpoint_store.is_none() {
11159            return;
11160        }
11161
11162        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11163            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11164                continue;
11165            };
11166            self.edit_breakpoint_at_anchor(
11167                anchor,
11168                breakpoint,
11169                BreakpointEditAction::InvertState,
11170                cx,
11171            );
11172        }
11173    }
11174
11175    pub fn toggle_breakpoint(
11176        &mut self,
11177        _: &crate::actions::ToggleBreakpoint,
11178        window: &mut Window,
11179        cx: &mut Context<Self>,
11180    ) {
11181        if self.breakpoint_store.is_none() {
11182            return;
11183        }
11184
11185        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11186            if let Some(breakpoint) = breakpoint {
11187                self.edit_breakpoint_at_anchor(
11188                    anchor,
11189                    breakpoint,
11190                    BreakpointEditAction::Toggle,
11191                    cx,
11192                );
11193            } else {
11194                self.edit_breakpoint_at_anchor(
11195                    anchor,
11196                    Breakpoint::new_standard(),
11197                    BreakpointEditAction::Toggle,
11198                    cx,
11199                );
11200            }
11201        }
11202    }
11203
11204    pub fn edit_breakpoint_at_anchor(
11205        &mut self,
11206        breakpoint_position: Anchor,
11207        breakpoint: Breakpoint,
11208        edit_action: BreakpointEditAction,
11209        cx: &mut Context<Self>,
11210    ) {
11211        let Some(breakpoint_store) = &self.breakpoint_store else {
11212            return;
11213        };
11214
11215        let Some(buffer) = self
11216            .buffer
11217            .read(cx)
11218            .buffer_for_anchor(breakpoint_position, cx)
11219        else {
11220            return;
11221        };
11222
11223        breakpoint_store.update(cx, |breakpoint_store, cx| {
11224            breakpoint_store.toggle_breakpoint(
11225                buffer,
11226                BreakpointWithPosition {
11227                    position: breakpoint_position.text_anchor,
11228                    bp: breakpoint,
11229                },
11230                edit_action,
11231                cx,
11232            );
11233        });
11234
11235        cx.notify();
11236    }
11237
11238    #[cfg(any(test, feature = "test-support"))]
11239    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11240        self.breakpoint_store.clone()
11241    }
11242
11243    pub fn prepare_restore_change(
11244        &self,
11245        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11246        hunk: &MultiBufferDiffHunk,
11247        cx: &mut App,
11248    ) -> Option<()> {
11249        if hunk.is_created_file() {
11250            return None;
11251        }
11252        let buffer = self.buffer.read(cx);
11253        let diff = buffer.diff_for(hunk.buffer_id)?;
11254        let buffer = buffer.buffer(hunk.buffer_id)?;
11255        let buffer = buffer.read(cx);
11256        let original_text = diff
11257            .read(cx)
11258            .base_text()
11259            .as_rope()
11260            .slice(hunk.diff_base_byte_range.clone());
11261        let buffer_snapshot = buffer.snapshot();
11262        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11263        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11264            probe
11265                .0
11266                .start
11267                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11268                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11269        }) {
11270            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11271            Some(())
11272        } else {
11273            None
11274        }
11275    }
11276
11277    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11278        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11279    }
11280
11281    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11282        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11283    }
11284
11285    fn manipulate_lines<M>(
11286        &mut self,
11287        window: &mut Window,
11288        cx: &mut Context<Self>,
11289        mut manipulate: M,
11290    ) where
11291        M: FnMut(&str) -> LineManipulationResult,
11292    {
11293        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11294
11295        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11296        let buffer = self.buffer.read(cx).snapshot(cx);
11297
11298        let mut edits = Vec::new();
11299
11300        let selections = self.selections.all::<Point>(&display_map);
11301        let mut selections = selections.iter().peekable();
11302        let mut contiguous_row_selections = Vec::new();
11303        let mut new_selections = Vec::new();
11304        let mut added_lines = 0;
11305        let mut removed_lines = 0;
11306
11307        while let Some(selection) = selections.next() {
11308            let (start_row, end_row) = consume_contiguous_rows(
11309                &mut contiguous_row_selections,
11310                selection,
11311                &display_map,
11312                &mut selections,
11313            );
11314
11315            let start_point = Point::new(start_row.0, 0);
11316            let end_point = Point::new(
11317                end_row.previous_row().0,
11318                buffer.line_len(end_row.previous_row()),
11319            );
11320            let text = buffer
11321                .text_for_range(start_point..end_point)
11322                .collect::<String>();
11323
11324            let LineManipulationResult {
11325                new_text,
11326                line_count_before,
11327                line_count_after,
11328            } = manipulate(&text);
11329
11330            edits.push((start_point..end_point, new_text));
11331
11332            // Selections must change based on added and removed line count
11333            let start_row =
11334                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11335            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11336            new_selections.push(Selection {
11337                id: selection.id,
11338                start: start_row,
11339                end: end_row,
11340                goal: SelectionGoal::None,
11341                reversed: selection.reversed,
11342            });
11343
11344            if line_count_after > line_count_before {
11345                added_lines += line_count_after - line_count_before;
11346            } else if line_count_before > line_count_after {
11347                removed_lines += line_count_before - line_count_after;
11348            }
11349        }
11350
11351        self.transact(window, cx, |this, window, cx| {
11352            let buffer = this.buffer.update(cx, |buffer, cx| {
11353                buffer.edit(edits, None, cx);
11354                buffer.snapshot(cx)
11355            });
11356
11357            // Recalculate offsets on newly edited buffer
11358            let new_selections = new_selections
11359                .iter()
11360                .map(|s| {
11361                    let start_point = Point::new(s.start.0, 0);
11362                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11363                    Selection {
11364                        id: s.id,
11365                        start: buffer.point_to_offset(start_point),
11366                        end: buffer.point_to_offset(end_point),
11367                        goal: s.goal,
11368                        reversed: s.reversed,
11369                    }
11370                })
11371                .collect();
11372
11373            this.change_selections(Default::default(), window, cx, |s| {
11374                s.select(new_selections);
11375            });
11376
11377            this.request_autoscroll(Autoscroll::fit(), cx);
11378        });
11379    }
11380
11381    fn manipulate_immutable_lines<Fn>(
11382        &mut self,
11383        window: &mut Window,
11384        cx: &mut Context<Self>,
11385        mut callback: Fn,
11386    ) where
11387        Fn: FnMut(&mut Vec<&str>),
11388    {
11389        self.manipulate_lines(window, cx, |text| {
11390            let mut lines: Vec<&str> = text.split('\n').collect();
11391            let line_count_before = lines.len();
11392
11393            callback(&mut lines);
11394
11395            LineManipulationResult {
11396                new_text: lines.join("\n"),
11397                line_count_before,
11398                line_count_after: lines.len(),
11399            }
11400        });
11401    }
11402
11403    fn manipulate_mutable_lines<Fn>(
11404        &mut self,
11405        window: &mut Window,
11406        cx: &mut Context<Self>,
11407        mut callback: Fn,
11408    ) where
11409        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11410    {
11411        self.manipulate_lines(window, cx, |text| {
11412            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11413            let line_count_before = lines.len();
11414
11415            callback(&mut lines);
11416
11417            LineManipulationResult {
11418                new_text: lines.join("\n"),
11419                line_count_before,
11420                line_count_after: lines.len(),
11421            }
11422        });
11423    }
11424
11425    pub fn convert_indentation_to_spaces(
11426        &mut self,
11427        _: &ConvertIndentationToSpaces,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        let settings = self.buffer.read(cx).language_settings(cx);
11432        let tab_size = settings.tab_size.get() as usize;
11433
11434        self.manipulate_mutable_lines(window, cx, |lines| {
11435            // Allocates a reasonably sized scratch buffer once for the whole loop
11436            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11437            // Avoids recomputing spaces that could be inserted many times
11438            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11439                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11440                .collect();
11441
11442            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11443                let mut chars = line.as_ref().chars();
11444                let mut col = 0;
11445                let mut changed = false;
11446
11447                for ch in chars.by_ref() {
11448                    match ch {
11449                        ' ' => {
11450                            reindented_line.push(' ');
11451                            col += 1;
11452                        }
11453                        '\t' => {
11454                            // \t are converted to spaces depending on the current column
11455                            let spaces_len = tab_size - (col % tab_size);
11456                            reindented_line.extend(&space_cache[spaces_len - 1]);
11457                            col += spaces_len;
11458                            changed = true;
11459                        }
11460                        _ => {
11461                            // If we dont append before break, the character is consumed
11462                            reindented_line.push(ch);
11463                            break;
11464                        }
11465                    }
11466                }
11467
11468                if !changed {
11469                    reindented_line.clear();
11470                    continue;
11471                }
11472                // Append the rest of the line and replace old reference with new one
11473                reindented_line.extend(chars);
11474                *line = Cow::Owned(reindented_line.clone());
11475                reindented_line.clear();
11476            }
11477        });
11478    }
11479
11480    pub fn convert_indentation_to_tabs(
11481        &mut self,
11482        _: &ConvertIndentationToTabs,
11483        window: &mut Window,
11484        cx: &mut Context<Self>,
11485    ) {
11486        let settings = self.buffer.read(cx).language_settings(cx);
11487        let tab_size = settings.tab_size.get() as usize;
11488
11489        self.manipulate_mutable_lines(window, cx, |lines| {
11490            // Allocates a reasonably sized buffer once for the whole loop
11491            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11492            // Avoids recomputing spaces that could be inserted many times
11493            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11494                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11495                .collect();
11496
11497            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11498                let mut chars = line.chars();
11499                let mut spaces_count = 0;
11500                let mut first_non_indent_char = None;
11501                let mut changed = false;
11502
11503                for ch in chars.by_ref() {
11504                    match ch {
11505                        ' ' => {
11506                            // Keep track of spaces. Append \t when we reach tab_size
11507                            spaces_count += 1;
11508                            changed = true;
11509                            if spaces_count == tab_size {
11510                                reindented_line.push('\t');
11511                                spaces_count = 0;
11512                            }
11513                        }
11514                        '\t' => {
11515                            reindented_line.push('\t');
11516                            spaces_count = 0;
11517                        }
11518                        _ => {
11519                            // Dont append it yet, we might have remaining spaces
11520                            first_non_indent_char = Some(ch);
11521                            break;
11522                        }
11523                    }
11524                }
11525
11526                if !changed {
11527                    reindented_line.clear();
11528                    continue;
11529                }
11530                // Remaining spaces that didn't make a full tab stop
11531                if spaces_count > 0 {
11532                    reindented_line.extend(&space_cache[spaces_count - 1]);
11533                }
11534                // If we consume an extra character that was not indentation, add it back
11535                if let Some(extra_char) = first_non_indent_char {
11536                    reindented_line.push(extra_char);
11537                }
11538                // Append the rest of the line and replace old reference with new one
11539                reindented_line.extend(chars);
11540                *line = Cow::Owned(reindented_line.clone());
11541                reindented_line.clear();
11542            }
11543        });
11544    }
11545
11546    pub fn convert_to_upper_case(
11547        &mut self,
11548        _: &ConvertToUpperCase,
11549        window: &mut Window,
11550        cx: &mut Context<Self>,
11551    ) {
11552        self.manipulate_text(window, cx, |text| text.to_uppercase())
11553    }
11554
11555    pub fn convert_to_lower_case(
11556        &mut self,
11557        _: &ConvertToLowerCase,
11558        window: &mut Window,
11559        cx: &mut Context<Self>,
11560    ) {
11561        self.manipulate_text(window, cx, |text| text.to_lowercase())
11562    }
11563
11564    pub fn convert_to_title_case(
11565        &mut self,
11566        _: &ConvertToTitleCase,
11567        window: &mut Window,
11568        cx: &mut Context<Self>,
11569    ) {
11570        self.manipulate_text(window, cx, |text| {
11571            text.split('\n')
11572                .map(|line| line.to_case(Case::Title))
11573                .join("\n")
11574        })
11575    }
11576
11577    pub fn convert_to_snake_case(
11578        &mut self,
11579        _: &ConvertToSnakeCase,
11580        window: &mut Window,
11581        cx: &mut Context<Self>,
11582    ) {
11583        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11584    }
11585
11586    pub fn convert_to_kebab_case(
11587        &mut self,
11588        _: &ConvertToKebabCase,
11589        window: &mut Window,
11590        cx: &mut Context<Self>,
11591    ) {
11592        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11593    }
11594
11595    pub fn convert_to_upper_camel_case(
11596        &mut self,
11597        _: &ConvertToUpperCamelCase,
11598        window: &mut Window,
11599        cx: &mut Context<Self>,
11600    ) {
11601        self.manipulate_text(window, cx, |text| {
11602            text.split('\n')
11603                .map(|line| line.to_case(Case::UpperCamel))
11604                .join("\n")
11605        })
11606    }
11607
11608    pub fn convert_to_lower_camel_case(
11609        &mut self,
11610        _: &ConvertToLowerCamelCase,
11611        window: &mut Window,
11612        cx: &mut Context<Self>,
11613    ) {
11614        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11615    }
11616
11617    pub fn convert_to_opposite_case(
11618        &mut self,
11619        _: &ConvertToOppositeCase,
11620        window: &mut Window,
11621        cx: &mut Context<Self>,
11622    ) {
11623        self.manipulate_text(window, cx, |text| {
11624            text.chars()
11625                .fold(String::with_capacity(text.len()), |mut t, c| {
11626                    if c.is_uppercase() {
11627                        t.extend(c.to_lowercase());
11628                    } else {
11629                        t.extend(c.to_uppercase());
11630                    }
11631                    t
11632                })
11633        })
11634    }
11635
11636    pub fn convert_to_sentence_case(
11637        &mut self,
11638        _: &ConvertToSentenceCase,
11639        window: &mut Window,
11640        cx: &mut Context<Self>,
11641    ) {
11642        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11643    }
11644
11645    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11646        self.manipulate_text(window, cx, |text| {
11647            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11648            if has_upper_case_characters {
11649                text.to_lowercase()
11650            } else {
11651                text.to_uppercase()
11652            }
11653        })
11654    }
11655
11656    pub fn convert_to_rot13(
11657        &mut self,
11658        _: &ConvertToRot13,
11659        window: &mut Window,
11660        cx: &mut Context<Self>,
11661    ) {
11662        self.manipulate_text(window, cx, |text| {
11663            text.chars()
11664                .map(|c| match c {
11665                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11666                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11667                    _ => c,
11668                })
11669                .collect()
11670        })
11671    }
11672
11673    pub fn convert_to_rot47(
11674        &mut self,
11675        _: &ConvertToRot47,
11676        window: &mut Window,
11677        cx: &mut Context<Self>,
11678    ) {
11679        self.manipulate_text(window, cx, |text| {
11680            text.chars()
11681                .map(|c| {
11682                    let code_point = c as u32;
11683                    if code_point >= 33 && code_point <= 126 {
11684                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11685                    }
11686                    c
11687                })
11688                .collect()
11689        })
11690    }
11691
11692    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11693    where
11694        Fn: FnMut(&str) -> String,
11695    {
11696        let buffer = self.buffer.read(cx).snapshot(cx);
11697
11698        let mut new_selections = Vec::new();
11699        let mut edits = Vec::new();
11700        let mut selection_adjustment = 0i32;
11701
11702        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11703            let selection_is_empty = selection.is_empty();
11704
11705            let (start, end) = if selection_is_empty {
11706                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11707                (word_range.start, word_range.end)
11708            } else {
11709                (
11710                    buffer.point_to_offset(selection.start),
11711                    buffer.point_to_offset(selection.end),
11712                )
11713            };
11714
11715            let text = buffer.text_for_range(start..end).collect::<String>();
11716            let old_length = text.len() as i32;
11717            let text = callback(&text);
11718
11719            new_selections.push(Selection {
11720                start: (start as i32 - selection_adjustment) as usize,
11721                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11722                goal: SelectionGoal::None,
11723                id: selection.id,
11724                reversed: selection.reversed,
11725            });
11726
11727            selection_adjustment += old_length - text.len() as i32;
11728
11729            edits.push((start..end, text));
11730        }
11731
11732        self.transact(window, cx, |this, window, cx| {
11733            this.buffer.update(cx, |buffer, cx| {
11734                buffer.edit(edits, None, cx);
11735            });
11736
11737            this.change_selections(Default::default(), window, cx, |s| {
11738                s.select(new_selections);
11739            });
11740
11741            this.request_autoscroll(Autoscroll::fit(), cx);
11742        });
11743    }
11744
11745    pub fn move_selection_on_drop(
11746        &mut self,
11747        selection: &Selection<Anchor>,
11748        target: DisplayPoint,
11749        is_cut: bool,
11750        window: &mut Window,
11751        cx: &mut Context<Self>,
11752    ) {
11753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11754        let buffer = display_map.buffer_snapshot();
11755        let mut edits = Vec::new();
11756        let insert_point = display_map
11757            .clip_point(target, Bias::Left)
11758            .to_point(&display_map);
11759        let text = buffer
11760            .text_for_range(selection.start..selection.end)
11761            .collect::<String>();
11762        if is_cut {
11763            edits.push(((selection.start..selection.end), String::new()));
11764        }
11765        let insert_anchor = buffer.anchor_before(insert_point);
11766        edits.push(((insert_anchor..insert_anchor), text));
11767        let last_edit_start = insert_anchor.bias_left(buffer);
11768        let last_edit_end = insert_anchor.bias_right(buffer);
11769        self.transact(window, cx, |this, window, cx| {
11770            this.buffer.update(cx, |buffer, cx| {
11771                buffer.edit(edits, None, cx);
11772            });
11773            this.change_selections(Default::default(), window, cx, |s| {
11774                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11775            });
11776        });
11777    }
11778
11779    pub fn clear_selection_drag_state(&mut self) {
11780        self.selection_drag_state = SelectionDragState::None;
11781    }
11782
11783    pub fn duplicate(
11784        &mut self,
11785        upwards: bool,
11786        whole_lines: bool,
11787        window: &mut Window,
11788        cx: &mut Context<Self>,
11789    ) {
11790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11791
11792        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11793        let buffer = display_map.buffer_snapshot();
11794        let selections = self.selections.all::<Point>(&display_map);
11795
11796        let mut edits = Vec::new();
11797        let mut selections_iter = selections.iter().peekable();
11798        while let Some(selection) = selections_iter.next() {
11799            let mut rows = selection.spanned_rows(false, &display_map);
11800            // duplicate line-wise
11801            if whole_lines || selection.start == selection.end {
11802                // Avoid duplicating the same lines twice.
11803                while let Some(next_selection) = selections_iter.peek() {
11804                    let next_rows = next_selection.spanned_rows(false, &display_map);
11805                    if next_rows.start < rows.end {
11806                        rows.end = next_rows.end;
11807                        selections_iter.next().unwrap();
11808                    } else {
11809                        break;
11810                    }
11811                }
11812
11813                // Copy the text from the selected row region and splice it either at the start
11814                // or end of the region.
11815                let start = Point::new(rows.start.0, 0);
11816                let end = Point::new(
11817                    rows.end.previous_row().0,
11818                    buffer.line_len(rows.end.previous_row()),
11819                );
11820
11821                let mut text = buffer.text_for_range(start..end).collect::<String>();
11822
11823                let insert_location = if upwards {
11824                    // When duplicating upward, we need to insert before the current line.
11825                    // If we're on the last line and it doesn't end with a newline,
11826                    // we need to add a newline before the duplicated content.
11827                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11828                        && buffer.max_point().column > 0
11829                        && !text.ends_with('\n');
11830
11831                    if needs_leading_newline {
11832                        text.insert(0, '\n');
11833                        end
11834                    } else {
11835                        text.push('\n');
11836                        Point::new(rows.start.0, 0)
11837                    }
11838                } else {
11839                    text.push('\n');
11840                    start
11841                };
11842                edits.push((insert_location..insert_location, text));
11843            } else {
11844                // duplicate character-wise
11845                let start = selection.start;
11846                let end = selection.end;
11847                let text = buffer.text_for_range(start..end).collect::<String>();
11848                edits.push((selection.end..selection.end, text));
11849            }
11850        }
11851
11852        self.transact(window, cx, |this, window, cx| {
11853            this.buffer.update(cx, |buffer, cx| {
11854                buffer.edit(edits, None, cx);
11855            });
11856
11857            // When duplicating upward with whole lines, move the cursor to the duplicated line
11858            if upwards && whole_lines {
11859                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11860
11861                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11862                    let mut new_ranges = Vec::new();
11863                    let selections = s.all::<Point>(&display_map);
11864                    let mut selections_iter = selections.iter().peekable();
11865
11866                    while let Some(first_selection) = selections_iter.next() {
11867                        // Group contiguous selections together to find the total row span
11868                        let mut group_selections = vec![first_selection];
11869                        let mut rows = first_selection.spanned_rows(false, &display_map);
11870
11871                        while let Some(next_selection) = selections_iter.peek() {
11872                            let next_rows = next_selection.spanned_rows(false, &display_map);
11873                            if next_rows.start < rows.end {
11874                                rows.end = next_rows.end;
11875                                group_selections.push(selections_iter.next().unwrap());
11876                            } else {
11877                                break;
11878                            }
11879                        }
11880
11881                        let row_count = rows.end.0 - rows.start.0;
11882
11883                        // Move all selections in this group up by the total number of duplicated rows
11884                        for selection in group_selections {
11885                            let new_start = Point::new(
11886                                selection.start.row.saturating_sub(row_count),
11887                                selection.start.column,
11888                            );
11889
11890                            let new_end = Point::new(
11891                                selection.end.row.saturating_sub(row_count),
11892                                selection.end.column,
11893                            );
11894
11895                            new_ranges.push(new_start..new_end);
11896                        }
11897                    }
11898
11899                    s.select_ranges(new_ranges);
11900                });
11901            }
11902
11903            this.request_autoscroll(Autoscroll::fit(), cx);
11904        });
11905    }
11906
11907    pub fn duplicate_line_up(
11908        &mut self,
11909        _: &DuplicateLineUp,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        self.duplicate(true, true, window, cx);
11914    }
11915
11916    pub fn duplicate_line_down(
11917        &mut self,
11918        _: &DuplicateLineDown,
11919        window: &mut Window,
11920        cx: &mut Context<Self>,
11921    ) {
11922        self.duplicate(false, true, window, cx);
11923    }
11924
11925    pub fn duplicate_selection(
11926        &mut self,
11927        _: &DuplicateSelection,
11928        window: &mut Window,
11929        cx: &mut Context<Self>,
11930    ) {
11931        self.duplicate(false, false, window, cx);
11932    }
11933
11934    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11935        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11936        if self.mode.is_single_line() {
11937            cx.propagate();
11938            return;
11939        }
11940
11941        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11942        let buffer = self.buffer.read(cx).snapshot(cx);
11943
11944        let mut edits = Vec::new();
11945        let mut unfold_ranges = Vec::new();
11946        let mut refold_creases = Vec::new();
11947
11948        let selections = self.selections.all::<Point>(&display_map);
11949        let mut selections = selections.iter().peekable();
11950        let mut contiguous_row_selections = Vec::new();
11951        let mut new_selections = Vec::new();
11952
11953        while let Some(selection) = selections.next() {
11954            // Find all the selections that span a contiguous row range
11955            let (start_row, end_row) = consume_contiguous_rows(
11956                &mut contiguous_row_selections,
11957                selection,
11958                &display_map,
11959                &mut selections,
11960            );
11961
11962            // Move the text spanned by the row range to be before the line preceding the row range
11963            if start_row.0 > 0 {
11964                let range_to_move = Point::new(
11965                    start_row.previous_row().0,
11966                    buffer.line_len(start_row.previous_row()),
11967                )
11968                    ..Point::new(
11969                        end_row.previous_row().0,
11970                        buffer.line_len(end_row.previous_row()),
11971                    );
11972                let insertion_point = display_map
11973                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11974                    .0;
11975
11976                // Don't move lines across excerpts
11977                if buffer
11978                    .excerpt_containing(insertion_point..range_to_move.end)
11979                    .is_some()
11980                {
11981                    let text = buffer
11982                        .text_for_range(range_to_move.clone())
11983                        .flat_map(|s| s.chars())
11984                        .skip(1)
11985                        .chain(['\n'])
11986                        .collect::<String>();
11987
11988                    edits.push((
11989                        buffer.anchor_after(range_to_move.start)
11990                            ..buffer.anchor_before(range_to_move.end),
11991                        String::new(),
11992                    ));
11993                    let insertion_anchor = buffer.anchor_after(insertion_point);
11994                    edits.push((insertion_anchor..insertion_anchor, text));
11995
11996                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11997
11998                    // Move selections up
11999                    new_selections.extend(contiguous_row_selections.drain(..).map(
12000                        |mut selection| {
12001                            selection.start.row -= row_delta;
12002                            selection.end.row -= row_delta;
12003                            selection
12004                        },
12005                    ));
12006
12007                    // Move folds up
12008                    unfold_ranges.push(range_to_move.clone());
12009                    for fold in display_map.folds_in_range(
12010                        buffer.anchor_before(range_to_move.start)
12011                            ..buffer.anchor_after(range_to_move.end),
12012                    ) {
12013                        let mut start = fold.range.start.to_point(&buffer);
12014                        let mut end = fold.range.end.to_point(&buffer);
12015                        start.row -= row_delta;
12016                        end.row -= row_delta;
12017                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12018                    }
12019                }
12020            }
12021
12022            // If we didn't move line(s), preserve the existing selections
12023            new_selections.append(&mut contiguous_row_selections);
12024        }
12025
12026        self.transact(window, cx, |this, window, cx| {
12027            this.unfold_ranges(&unfold_ranges, true, true, cx);
12028            this.buffer.update(cx, |buffer, cx| {
12029                for (range, text) in edits {
12030                    buffer.edit([(range, text)], None, cx);
12031                }
12032            });
12033            this.fold_creases(refold_creases, true, window, cx);
12034            this.change_selections(Default::default(), window, cx, |s| {
12035                s.select(new_selections);
12036            })
12037        });
12038    }
12039
12040    pub fn move_line_down(
12041        &mut self,
12042        _: &MoveLineDown,
12043        window: &mut Window,
12044        cx: &mut Context<Self>,
12045    ) {
12046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12047        if self.mode.is_single_line() {
12048            cx.propagate();
12049            return;
12050        }
12051
12052        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12053        let buffer = self.buffer.read(cx).snapshot(cx);
12054
12055        let mut edits = Vec::new();
12056        let mut unfold_ranges = Vec::new();
12057        let mut refold_creases = Vec::new();
12058
12059        let selections = self.selections.all::<Point>(&display_map);
12060        let mut selections = selections.iter().peekable();
12061        let mut contiguous_row_selections = Vec::new();
12062        let mut new_selections = Vec::new();
12063
12064        while let Some(selection) = selections.next() {
12065            // Find all the selections that span a contiguous row range
12066            let (start_row, end_row) = consume_contiguous_rows(
12067                &mut contiguous_row_selections,
12068                selection,
12069                &display_map,
12070                &mut selections,
12071            );
12072
12073            // Move the text spanned by the row range to be after the last line of the row range
12074            if end_row.0 <= buffer.max_point().row {
12075                let range_to_move =
12076                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12077                let insertion_point = display_map
12078                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12079                    .0;
12080
12081                // Don't move lines across excerpt boundaries
12082                if buffer
12083                    .excerpt_containing(range_to_move.start..insertion_point)
12084                    .is_some()
12085                {
12086                    let mut text = String::from("\n");
12087                    text.extend(buffer.text_for_range(range_to_move.clone()));
12088                    text.pop(); // Drop trailing newline
12089                    edits.push((
12090                        buffer.anchor_after(range_to_move.start)
12091                            ..buffer.anchor_before(range_to_move.end),
12092                        String::new(),
12093                    ));
12094                    let insertion_anchor = buffer.anchor_after(insertion_point);
12095                    edits.push((insertion_anchor..insertion_anchor, text));
12096
12097                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12098
12099                    // Move selections down
12100                    new_selections.extend(contiguous_row_selections.drain(..).map(
12101                        |mut selection| {
12102                            selection.start.row += row_delta;
12103                            selection.end.row += row_delta;
12104                            selection
12105                        },
12106                    ));
12107
12108                    // Move folds down
12109                    unfold_ranges.push(range_to_move.clone());
12110                    for fold in display_map.folds_in_range(
12111                        buffer.anchor_before(range_to_move.start)
12112                            ..buffer.anchor_after(range_to_move.end),
12113                    ) {
12114                        let mut start = fold.range.start.to_point(&buffer);
12115                        let mut end = fold.range.end.to_point(&buffer);
12116                        start.row += row_delta;
12117                        end.row += row_delta;
12118                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12119                    }
12120                }
12121            }
12122
12123            // If we didn't move line(s), preserve the existing selections
12124            new_selections.append(&mut contiguous_row_selections);
12125        }
12126
12127        self.transact(window, cx, |this, window, cx| {
12128            this.unfold_ranges(&unfold_ranges, true, true, cx);
12129            this.buffer.update(cx, |buffer, cx| {
12130                for (range, text) in edits {
12131                    buffer.edit([(range, text)], None, cx);
12132                }
12133            });
12134            this.fold_creases(refold_creases, true, window, cx);
12135            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12136        });
12137    }
12138
12139    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12140        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12141        let text_layout_details = &self.text_layout_details(window);
12142        self.transact(window, cx, |this, window, cx| {
12143            let edits = this.change_selections(Default::default(), window, cx, |s| {
12144                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12145                s.move_with(|display_map, selection| {
12146                    if !selection.is_empty() {
12147                        return;
12148                    }
12149
12150                    let mut head = selection.head();
12151                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12152                    if head.column() == display_map.line_len(head.row()) {
12153                        transpose_offset = display_map
12154                            .buffer_snapshot()
12155                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12156                    }
12157
12158                    if transpose_offset == 0 {
12159                        return;
12160                    }
12161
12162                    *head.column_mut() += 1;
12163                    head = display_map.clip_point(head, Bias::Right);
12164                    let goal = SelectionGoal::HorizontalPosition(
12165                        display_map
12166                            .x_for_display_point(head, text_layout_details)
12167                            .into(),
12168                    );
12169                    selection.collapse_to(head, goal);
12170
12171                    let transpose_start = display_map
12172                        .buffer_snapshot()
12173                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12174                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12175                        let transpose_end = display_map
12176                            .buffer_snapshot()
12177                            .clip_offset(transpose_offset + 1, Bias::Right);
12178                        if let Some(ch) = display_map
12179                            .buffer_snapshot()
12180                            .chars_at(transpose_start)
12181                            .next()
12182                        {
12183                            edits.push((transpose_start..transpose_offset, String::new()));
12184                            edits.push((transpose_end..transpose_end, ch.to_string()));
12185                        }
12186                    }
12187                });
12188                edits
12189            });
12190            this.buffer
12191                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12192            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12193            this.change_selections(Default::default(), window, cx, |s| {
12194                s.select(selections);
12195            });
12196        });
12197    }
12198
12199    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12200        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12201        if self.mode.is_single_line() {
12202            cx.propagate();
12203            return;
12204        }
12205
12206        self.rewrap_impl(RewrapOptions::default(), cx)
12207    }
12208
12209    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12210        let buffer = self.buffer.read(cx).snapshot(cx);
12211        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12212
12213        #[derive(Clone, Debug, PartialEq)]
12214        enum CommentFormat {
12215            /// single line comment, with prefix for line
12216            Line(String),
12217            /// single line within a block comment, with prefix for line
12218            BlockLine(String),
12219            /// a single line of a block comment that includes the initial delimiter
12220            BlockCommentWithStart(BlockCommentConfig),
12221            /// a single line of a block comment that includes the ending delimiter
12222            BlockCommentWithEnd(BlockCommentConfig),
12223        }
12224
12225        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12226        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12227            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12228                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12229                .peekable();
12230
12231            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12232                row
12233            } else {
12234                return Vec::new();
12235            };
12236
12237            let language_settings = buffer.language_settings_at(selection.head(), cx);
12238            let language_scope = buffer.language_scope_at(selection.head());
12239
12240            let indent_and_prefix_for_row =
12241                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12242                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12243                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12244                        &language_scope
12245                    {
12246                        let indent_end = Point::new(row, indent.len);
12247                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12248                        let line_text_after_indent = buffer
12249                            .text_for_range(indent_end..line_end)
12250                            .collect::<String>();
12251
12252                        let is_within_comment_override = buffer
12253                            .language_scope_at(indent_end)
12254                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12255                        let comment_delimiters = if is_within_comment_override {
12256                            // we are within a comment syntax node, but we don't
12257                            // yet know what kind of comment: block, doc or line
12258                            match (
12259                                language_scope.documentation_comment(),
12260                                language_scope.block_comment(),
12261                            ) {
12262                                (Some(config), _) | (_, Some(config))
12263                                    if buffer.contains_str_at(indent_end, &config.start) =>
12264                                {
12265                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12266                                }
12267                                (Some(config), _) | (_, Some(config))
12268                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12269                                {
12270                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12271                                }
12272                                (Some(config), _) | (_, Some(config))
12273                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12274                                {
12275                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12276                                }
12277                                (_, _) => language_scope
12278                                    .line_comment_prefixes()
12279                                    .iter()
12280                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12281                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12282                            }
12283                        } else {
12284                            // we not in an overridden comment node, but we may
12285                            // be within a non-overridden line comment node
12286                            language_scope
12287                                .line_comment_prefixes()
12288                                .iter()
12289                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12290                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12291                        };
12292
12293                        let rewrap_prefix = language_scope
12294                            .rewrap_prefixes()
12295                            .iter()
12296                            .find_map(|prefix_regex| {
12297                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12298                                    if mat.start() == 0 {
12299                                        Some(mat.as_str().to_string())
12300                                    } else {
12301                                        None
12302                                    }
12303                                })
12304                            })
12305                            .flatten();
12306                        (comment_delimiters, rewrap_prefix)
12307                    } else {
12308                        (None, None)
12309                    };
12310                    (indent, comment_prefix, rewrap_prefix)
12311                };
12312
12313            let mut ranges = Vec::new();
12314            let from_empty_selection = selection.is_empty();
12315
12316            let mut current_range_start = first_row;
12317            let mut prev_row = first_row;
12318            let (
12319                mut current_range_indent,
12320                mut current_range_comment_delimiters,
12321                mut current_range_rewrap_prefix,
12322            ) = indent_and_prefix_for_row(first_row);
12323
12324            for row in non_blank_rows_iter.skip(1) {
12325                let has_paragraph_break = row > prev_row + 1;
12326
12327                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12328                    indent_and_prefix_for_row(row);
12329
12330                let has_indent_change = row_indent != current_range_indent;
12331                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12332
12333                let has_boundary_change = has_comment_change
12334                    || row_rewrap_prefix.is_some()
12335                    || (has_indent_change && current_range_comment_delimiters.is_some());
12336
12337                if has_paragraph_break || has_boundary_change {
12338                    ranges.push((
12339                        language_settings.clone(),
12340                        Point::new(current_range_start, 0)
12341                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12342                        current_range_indent,
12343                        current_range_comment_delimiters.clone(),
12344                        current_range_rewrap_prefix.clone(),
12345                        from_empty_selection,
12346                    ));
12347                    current_range_start = row;
12348                    current_range_indent = row_indent;
12349                    current_range_comment_delimiters = row_comment_delimiters;
12350                    current_range_rewrap_prefix = row_rewrap_prefix;
12351                }
12352                prev_row = row;
12353            }
12354
12355            ranges.push((
12356                language_settings.clone(),
12357                Point::new(current_range_start, 0)
12358                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12359                current_range_indent,
12360                current_range_comment_delimiters,
12361                current_range_rewrap_prefix,
12362                from_empty_selection,
12363            ));
12364
12365            ranges
12366        });
12367
12368        let mut edits = Vec::new();
12369        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12370
12371        for (
12372            language_settings,
12373            wrap_range,
12374            mut indent_size,
12375            comment_prefix,
12376            rewrap_prefix,
12377            from_empty_selection,
12378        ) in wrap_ranges
12379        {
12380            let mut start_row = wrap_range.start.row;
12381            let mut end_row = wrap_range.end.row;
12382
12383            // Skip selections that overlap with a range that has already been rewrapped.
12384            let selection_range = start_row..end_row;
12385            if rewrapped_row_ranges
12386                .iter()
12387                .any(|range| range.overlaps(&selection_range))
12388            {
12389                continue;
12390            }
12391
12392            let tab_size = language_settings.tab_size;
12393
12394            let (line_prefix, inside_comment) = match &comment_prefix {
12395                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12396                    (Some(prefix.as_str()), true)
12397                }
12398                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12399                    (Some(prefix.as_ref()), true)
12400                }
12401                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12402                    start: _,
12403                    end: _,
12404                    prefix,
12405                    tab_size,
12406                })) => {
12407                    indent_size.len += tab_size;
12408                    (Some(prefix.as_ref()), true)
12409                }
12410                None => (None, false),
12411            };
12412            let indent_prefix = indent_size.chars().collect::<String>();
12413            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12414
12415            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12416                RewrapBehavior::InComments => inside_comment,
12417                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12418                RewrapBehavior::Anywhere => true,
12419            };
12420
12421            let should_rewrap = options.override_language_settings
12422                || allow_rewrap_based_on_language
12423                || self.hard_wrap.is_some();
12424            if !should_rewrap {
12425                continue;
12426            }
12427
12428            if from_empty_selection {
12429                'expand_upwards: while start_row > 0 {
12430                    let prev_row = start_row - 1;
12431                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12432                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12433                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12434                    {
12435                        start_row = prev_row;
12436                    } else {
12437                        break 'expand_upwards;
12438                    }
12439                }
12440
12441                'expand_downwards: while end_row < buffer.max_point().row {
12442                    let next_row = end_row + 1;
12443                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12444                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12445                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12446                    {
12447                        end_row = next_row;
12448                    } else {
12449                        break 'expand_downwards;
12450                    }
12451                }
12452            }
12453
12454            let start = Point::new(start_row, 0);
12455            let start_offset = ToOffset::to_offset(&start, &buffer);
12456            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12457            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12458            let mut first_line_delimiter = None;
12459            let mut last_line_delimiter = None;
12460            let Some(lines_without_prefixes) = selection_text
12461                .lines()
12462                .enumerate()
12463                .map(|(ix, line)| {
12464                    let line_trimmed = line.trim_start();
12465                    if rewrap_prefix.is_some() && ix > 0 {
12466                        Ok(line_trimmed)
12467                    } else if let Some(
12468                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12469                            start,
12470                            prefix,
12471                            end,
12472                            tab_size,
12473                        })
12474                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12475                            start,
12476                            prefix,
12477                            end,
12478                            tab_size,
12479                        }),
12480                    ) = &comment_prefix
12481                    {
12482                        let line_trimmed = line_trimmed
12483                            .strip_prefix(start.as_ref())
12484                            .map(|s| {
12485                                let mut indent_size = indent_size;
12486                                indent_size.len -= tab_size;
12487                                let indent_prefix: String = indent_size.chars().collect();
12488                                first_line_delimiter = Some((indent_prefix, start));
12489                                s.trim_start()
12490                            })
12491                            .unwrap_or(line_trimmed);
12492                        let line_trimmed = line_trimmed
12493                            .strip_suffix(end.as_ref())
12494                            .map(|s| {
12495                                last_line_delimiter = Some(end);
12496                                s.trim_end()
12497                            })
12498                            .unwrap_or(line_trimmed);
12499                        let line_trimmed = line_trimmed
12500                            .strip_prefix(prefix.as_ref())
12501                            .unwrap_or(line_trimmed);
12502                        Ok(line_trimmed)
12503                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12504                        line_trimmed.strip_prefix(prefix).with_context(|| {
12505                            format!("line did not start with prefix {prefix:?}: {line:?}")
12506                        })
12507                    } else {
12508                        line_trimmed
12509                            .strip_prefix(&line_prefix.trim_start())
12510                            .with_context(|| {
12511                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12512                            })
12513                    }
12514                })
12515                .collect::<Result<Vec<_>, _>>()
12516                .log_err()
12517            else {
12518                continue;
12519            };
12520
12521            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12522                buffer
12523                    .language_settings_at(Point::new(start_row, 0), cx)
12524                    .preferred_line_length as usize
12525            });
12526
12527            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12528                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12529            } else {
12530                line_prefix.clone()
12531            };
12532
12533            let wrapped_text = {
12534                let mut wrapped_text = wrap_with_prefix(
12535                    line_prefix,
12536                    subsequent_lines_prefix,
12537                    lines_without_prefixes.join("\n"),
12538                    wrap_column,
12539                    tab_size,
12540                    options.preserve_existing_whitespace,
12541                );
12542
12543                if let Some((indent, delimiter)) = first_line_delimiter {
12544                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12545                }
12546                if let Some(last_line) = last_line_delimiter {
12547                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12548                }
12549
12550                wrapped_text
12551            };
12552
12553            // TODO: should always use char-based diff while still supporting cursor behavior that
12554            // matches vim.
12555            let mut diff_options = DiffOptions::default();
12556            if options.override_language_settings {
12557                diff_options.max_word_diff_len = 0;
12558                diff_options.max_word_diff_line_count = 0;
12559            } else {
12560                diff_options.max_word_diff_len = usize::MAX;
12561                diff_options.max_word_diff_line_count = usize::MAX;
12562            }
12563
12564            for (old_range, new_text) in
12565                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12566            {
12567                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12568                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12569                edits.push((edit_start..edit_end, new_text));
12570            }
12571
12572            rewrapped_row_ranges.push(start_row..=end_row);
12573        }
12574
12575        self.buffer
12576            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12577    }
12578
12579    pub fn cut_common(
12580        &mut self,
12581        cut_no_selection_line: bool,
12582        window: &mut Window,
12583        cx: &mut Context<Self>,
12584    ) -> ClipboardItem {
12585        let mut text = String::new();
12586        let buffer = self.buffer.read(cx).snapshot(cx);
12587        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12588        let mut clipboard_selections = Vec::with_capacity(selections.len());
12589        {
12590            let max_point = buffer.max_point();
12591            let mut is_first = true;
12592            let mut prev_selection_was_entire_line = false;
12593            for selection in &mut selections {
12594                let is_entire_line =
12595                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12596                if is_entire_line {
12597                    selection.start = Point::new(selection.start.row, 0);
12598                    if !selection.is_empty() && selection.end.column == 0 {
12599                        selection.end = cmp::min(max_point, selection.end);
12600                    } else {
12601                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12602                    }
12603                    selection.goal = SelectionGoal::None;
12604                }
12605                if is_first {
12606                    is_first = false;
12607                } else if !prev_selection_was_entire_line {
12608                    text += "\n";
12609                }
12610                prev_selection_was_entire_line = is_entire_line;
12611                let mut len = 0;
12612                for chunk in buffer.text_for_range(selection.start..selection.end) {
12613                    text.push_str(chunk);
12614                    len += chunk.len();
12615                }
12616                clipboard_selections.push(ClipboardSelection {
12617                    len,
12618                    is_entire_line,
12619                    first_line_indent: buffer
12620                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12621                        .len,
12622                });
12623            }
12624        }
12625
12626        self.transact(window, cx, |this, window, cx| {
12627            this.change_selections(Default::default(), window, cx, |s| {
12628                s.select(selections);
12629            });
12630            this.insert("", window, cx);
12631        });
12632        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12633    }
12634
12635    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12637        let item = self.cut_common(true, window, cx);
12638        cx.write_to_clipboard(item);
12639    }
12640
12641    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12642        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12643        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12644            s.move_with(|snapshot, sel| {
12645                if sel.is_empty() {
12646                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12647                }
12648                if sel.is_empty() {
12649                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12650                }
12651            });
12652        });
12653        let item = self.cut_common(false, window, cx);
12654        cx.set_global(KillRing(item))
12655    }
12656
12657    pub fn kill_ring_yank(
12658        &mut self,
12659        _: &KillRingYank,
12660        window: &mut Window,
12661        cx: &mut Context<Self>,
12662    ) {
12663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12664        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12665            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12666                (kill_ring.text().to_string(), kill_ring.metadata_json())
12667            } else {
12668                return;
12669            }
12670        } else {
12671            return;
12672        };
12673        self.do_paste(&text, metadata, false, window, cx);
12674    }
12675
12676    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12677        self.do_copy(true, cx);
12678    }
12679
12680    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12681        self.do_copy(false, cx);
12682    }
12683
12684    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12685        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12686        let buffer = self.buffer.read(cx).read(cx);
12687        let mut text = String::new();
12688
12689        let mut clipboard_selections = Vec::with_capacity(selections.len());
12690        {
12691            let max_point = buffer.max_point();
12692            let mut is_first = true;
12693            let mut prev_selection_was_entire_line = false;
12694            for selection in &selections {
12695                let mut start = selection.start;
12696                let mut end = selection.end;
12697                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12698                let mut add_trailing_newline = false;
12699                if is_entire_line {
12700                    start = Point::new(start.row, 0);
12701                    let next_line_start = Point::new(end.row + 1, 0);
12702                    if next_line_start <= max_point {
12703                        end = next_line_start;
12704                    } else {
12705                        // We're on the last line without a trailing newline.
12706                        // Copy to the end of the line and add a newline afterwards.
12707                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12708                        add_trailing_newline = true;
12709                    }
12710                }
12711
12712                let mut trimmed_selections = Vec::new();
12713                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12714                    let row = MultiBufferRow(start.row);
12715                    let first_indent = buffer.indent_size_for_line(row);
12716                    if first_indent.len == 0 || start.column > first_indent.len {
12717                        trimmed_selections.push(start..end);
12718                    } else {
12719                        trimmed_selections.push(
12720                            Point::new(row.0, first_indent.len)
12721                                ..Point::new(row.0, buffer.line_len(row)),
12722                        );
12723                        for row in start.row + 1..=end.row {
12724                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12725                            if row == end.row {
12726                                line_len = end.column;
12727                            }
12728                            if line_len == 0 {
12729                                trimmed_selections
12730                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12731                                continue;
12732                            }
12733                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12734                            if row_indent_size.len >= first_indent.len {
12735                                trimmed_selections.push(
12736                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12737                                );
12738                            } else {
12739                                trimmed_selections.clear();
12740                                trimmed_selections.push(start..end);
12741                                break;
12742                            }
12743                        }
12744                    }
12745                } else {
12746                    trimmed_selections.push(start..end);
12747                }
12748
12749                for trimmed_range in trimmed_selections {
12750                    if is_first {
12751                        is_first = false;
12752                    } else if !prev_selection_was_entire_line {
12753                        text += "\n";
12754                    }
12755                    prev_selection_was_entire_line = is_entire_line;
12756                    let mut len = 0;
12757                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12758                        text.push_str(chunk);
12759                        len += chunk.len();
12760                    }
12761                    if add_trailing_newline {
12762                        text.push('\n');
12763                        len += 1;
12764                    }
12765                    clipboard_selections.push(ClipboardSelection {
12766                        len,
12767                        is_entire_line,
12768                        first_line_indent: buffer
12769                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12770                            .len,
12771                    });
12772                }
12773            }
12774        }
12775
12776        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12777            text,
12778            clipboard_selections,
12779        ));
12780    }
12781
12782    pub fn do_paste(
12783        &mut self,
12784        text: &String,
12785        clipboard_selections: Option<Vec<ClipboardSelection>>,
12786        handle_entire_lines: bool,
12787        window: &mut Window,
12788        cx: &mut Context<Self>,
12789    ) {
12790        if self.read_only(cx) {
12791            return;
12792        }
12793
12794        let clipboard_text = Cow::Borrowed(text.as_str());
12795
12796        self.transact(window, cx, |this, window, cx| {
12797            let had_active_edit_prediction = this.has_active_edit_prediction();
12798            let display_map = this.display_snapshot(cx);
12799            let old_selections = this.selections.all::<usize>(&display_map);
12800            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12801
12802            if let Some(mut clipboard_selections) = clipboard_selections {
12803                let all_selections_were_entire_line =
12804                    clipboard_selections.iter().all(|s| s.is_entire_line);
12805                let first_selection_indent_column =
12806                    clipboard_selections.first().map(|s| s.first_line_indent);
12807                if clipboard_selections.len() != old_selections.len() {
12808                    clipboard_selections.drain(..);
12809                }
12810                let mut auto_indent_on_paste = true;
12811
12812                this.buffer.update(cx, |buffer, cx| {
12813                    let snapshot = buffer.read(cx);
12814                    auto_indent_on_paste = snapshot
12815                        .language_settings_at(cursor_offset, cx)
12816                        .auto_indent_on_paste;
12817
12818                    let mut start_offset = 0;
12819                    let mut edits = Vec::new();
12820                    let mut original_indent_columns = Vec::new();
12821                    for (ix, selection) in old_selections.iter().enumerate() {
12822                        let to_insert;
12823                        let entire_line;
12824                        let original_indent_column;
12825                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12826                            let end_offset = start_offset + clipboard_selection.len;
12827                            to_insert = &clipboard_text[start_offset..end_offset];
12828                            entire_line = clipboard_selection.is_entire_line;
12829                            start_offset = if entire_line {
12830                                end_offset
12831                            } else {
12832                                end_offset + 1
12833                            };
12834                            original_indent_column = Some(clipboard_selection.first_line_indent);
12835                        } else {
12836                            to_insert = &*clipboard_text;
12837                            entire_line = all_selections_were_entire_line;
12838                            original_indent_column = first_selection_indent_column
12839                        }
12840
12841                        let (range, to_insert) =
12842                            if selection.is_empty() && handle_entire_lines && entire_line {
12843                                // If the corresponding selection was empty when this slice of the
12844                                // clipboard text was written, then the entire line containing the
12845                                // selection was copied. If this selection is also currently empty,
12846                                // then paste the line before the current line of the buffer.
12847                                let column = selection.start.to_point(&snapshot).column as usize;
12848                                let line_start = selection.start - column;
12849                                (line_start..line_start, Cow::Borrowed(to_insert))
12850                            } else {
12851                                let language = snapshot.language_at(selection.head());
12852                                let range = selection.range();
12853                                if let Some(language) = language
12854                                    && language.name() == "Markdown".into()
12855                                {
12856                                    edit_for_markdown_paste(
12857                                        &snapshot,
12858                                        range,
12859                                        to_insert,
12860                                        url::Url::parse(to_insert).ok(),
12861                                    )
12862                                } else {
12863                                    (range, Cow::Borrowed(to_insert))
12864                                }
12865                            };
12866
12867                        edits.push((range, to_insert));
12868                        original_indent_columns.push(original_indent_column);
12869                    }
12870                    drop(snapshot);
12871
12872                    buffer.edit(
12873                        edits,
12874                        if auto_indent_on_paste {
12875                            Some(AutoindentMode::Block {
12876                                original_indent_columns,
12877                            })
12878                        } else {
12879                            None
12880                        },
12881                        cx,
12882                    );
12883                });
12884
12885                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12886                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12887            } else {
12888                let url = url::Url::parse(&clipboard_text).ok();
12889
12890                let auto_indent_mode = if !clipboard_text.is_empty() {
12891                    Some(AutoindentMode::Block {
12892                        original_indent_columns: Vec::new(),
12893                    })
12894                } else {
12895                    None
12896                };
12897
12898                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12899                    let snapshot = buffer.snapshot(cx);
12900
12901                    let anchors = old_selections
12902                        .iter()
12903                        .map(|s| {
12904                            let anchor = snapshot.anchor_after(s.head());
12905                            s.map(|_| anchor)
12906                        })
12907                        .collect::<Vec<_>>();
12908
12909                    let mut edits = Vec::new();
12910
12911                    for selection in old_selections.iter() {
12912                        let language = snapshot.language_at(selection.head());
12913                        let range = selection.range();
12914
12915                        let (edit_range, edit_text) = if let Some(language) = language
12916                            && language.name() == "Markdown".into()
12917                        {
12918                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12919                        } else {
12920                            (range, clipboard_text.clone())
12921                        };
12922
12923                        edits.push((edit_range, edit_text));
12924                    }
12925
12926                    drop(snapshot);
12927                    buffer.edit(edits, auto_indent_mode, cx);
12928
12929                    anchors
12930                });
12931
12932                this.change_selections(Default::default(), window, cx, |s| {
12933                    s.select_anchors(selection_anchors);
12934                });
12935            }
12936
12937            //   🤔                 |    ..     | show_in_menu |
12938            // | ..                  |   true        true
12939            // | had_edit_prediction |   false       true
12940
12941            let trigger_in_words =
12942                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12943
12944            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12945        });
12946    }
12947
12948    pub fn diff_clipboard_with_selection(
12949        &mut self,
12950        _: &DiffClipboardWithSelection,
12951        window: &mut Window,
12952        cx: &mut Context<Self>,
12953    ) {
12954        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12955
12956        if selections.is_empty() {
12957            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12958            return;
12959        };
12960
12961        let clipboard_text = match cx.read_from_clipboard() {
12962            Some(item) => match item.entries().first() {
12963                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12964                _ => None,
12965            },
12966            None => None,
12967        };
12968
12969        let Some(clipboard_text) = clipboard_text else {
12970            log::warn!("Clipboard doesn't contain text.");
12971            return;
12972        };
12973
12974        window.dispatch_action(
12975            Box::new(DiffClipboardWithSelectionData {
12976                clipboard_text,
12977                editor: cx.entity(),
12978            }),
12979            cx,
12980        );
12981    }
12982
12983    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12984        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12985        if let Some(item) = cx.read_from_clipboard() {
12986            let entries = item.entries();
12987
12988            match entries.first() {
12989                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12990                // of all the pasted entries.
12991                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12992                    .do_paste(
12993                        clipboard_string.text(),
12994                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12995                        true,
12996                        window,
12997                        cx,
12998                    ),
12999                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13000            }
13001        }
13002    }
13003
13004    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13005        if self.read_only(cx) {
13006            return;
13007        }
13008
13009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13010
13011        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13012            if let Some((selections, _)) =
13013                self.selection_history.transaction(transaction_id).cloned()
13014            {
13015                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13016                    s.select_anchors(selections.to_vec());
13017                });
13018            } else {
13019                log::error!(
13020                    "No entry in selection_history found for undo. \
13021                     This may correspond to a bug where undo does not update the selection. \
13022                     If this is occurring, please add details to \
13023                     https://github.com/zed-industries/zed/issues/22692"
13024                );
13025            }
13026            self.request_autoscroll(Autoscroll::fit(), cx);
13027            self.unmark_text(window, cx);
13028            self.refresh_edit_prediction(true, false, window, cx);
13029            cx.emit(EditorEvent::Edited { transaction_id });
13030            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13031        }
13032    }
13033
13034    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13035        if self.read_only(cx) {
13036            return;
13037        }
13038
13039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13040
13041        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13042            if let Some((_, Some(selections))) =
13043                self.selection_history.transaction(transaction_id).cloned()
13044            {
13045                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13046                    s.select_anchors(selections.to_vec());
13047                });
13048            } else {
13049                log::error!(
13050                    "No entry in selection_history found for redo. \
13051                     This may correspond to a bug where undo does not update the selection. \
13052                     If this is occurring, please add details to \
13053                     https://github.com/zed-industries/zed/issues/22692"
13054                );
13055            }
13056            self.request_autoscroll(Autoscroll::fit(), cx);
13057            self.unmark_text(window, cx);
13058            self.refresh_edit_prediction(true, false, window, cx);
13059            cx.emit(EditorEvent::Edited { transaction_id });
13060        }
13061    }
13062
13063    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13064        self.buffer
13065            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13066    }
13067
13068    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13069        self.buffer
13070            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13071    }
13072
13073    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13075        self.change_selections(Default::default(), window, cx, |s| {
13076            s.move_with(|map, selection| {
13077                let cursor = if selection.is_empty() {
13078                    movement::left(map, selection.start)
13079                } else {
13080                    selection.start
13081                };
13082                selection.collapse_to(cursor, SelectionGoal::None);
13083            });
13084        })
13085    }
13086
13087    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13089        self.change_selections(Default::default(), window, cx, |s| {
13090            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13091        })
13092    }
13093
13094    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13096        self.change_selections(Default::default(), window, cx, |s| {
13097            s.move_with(|map, selection| {
13098                let cursor = if selection.is_empty() {
13099                    movement::right(map, selection.end)
13100                } else {
13101                    selection.end
13102                };
13103                selection.collapse_to(cursor, SelectionGoal::None)
13104            });
13105        })
13106    }
13107
13108    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13110        self.change_selections(Default::default(), window, cx, |s| {
13111            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13112        });
13113    }
13114
13115    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13116        if self.take_rename(true, window, cx).is_some() {
13117            return;
13118        }
13119
13120        if self.mode.is_single_line() {
13121            cx.propagate();
13122            return;
13123        }
13124
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13126
13127        let text_layout_details = &self.text_layout_details(window);
13128        let selection_count = self.selections.count();
13129        let first_selection = self.selections.first_anchor();
13130
13131        self.change_selections(Default::default(), window, cx, |s| {
13132            s.move_with(|map, selection| {
13133                if !selection.is_empty() {
13134                    selection.goal = SelectionGoal::None;
13135                }
13136                let (cursor, goal) = movement::up(
13137                    map,
13138                    selection.start,
13139                    selection.goal,
13140                    false,
13141                    text_layout_details,
13142                );
13143                selection.collapse_to(cursor, goal);
13144            });
13145        });
13146
13147        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13148        {
13149            cx.propagate();
13150        }
13151    }
13152
13153    pub fn move_up_by_lines(
13154        &mut self,
13155        action: &MoveUpByLines,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if self.take_rename(true, window, cx).is_some() {
13160            return;
13161        }
13162
13163        if self.mode.is_single_line() {
13164            cx.propagate();
13165            return;
13166        }
13167
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13169
13170        let text_layout_details = &self.text_layout_details(window);
13171
13172        self.change_selections(Default::default(), window, cx, |s| {
13173            s.move_with(|map, selection| {
13174                if !selection.is_empty() {
13175                    selection.goal = SelectionGoal::None;
13176                }
13177                let (cursor, goal) = movement::up_by_rows(
13178                    map,
13179                    selection.start,
13180                    action.lines,
13181                    selection.goal,
13182                    false,
13183                    text_layout_details,
13184                );
13185                selection.collapse_to(cursor, goal);
13186            });
13187        })
13188    }
13189
13190    pub fn move_down_by_lines(
13191        &mut self,
13192        action: &MoveDownByLines,
13193        window: &mut Window,
13194        cx: &mut Context<Self>,
13195    ) {
13196        if self.take_rename(true, window, cx).is_some() {
13197            return;
13198        }
13199
13200        if self.mode.is_single_line() {
13201            cx.propagate();
13202            return;
13203        }
13204
13205        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13206
13207        let text_layout_details = &self.text_layout_details(window);
13208
13209        self.change_selections(Default::default(), window, cx, |s| {
13210            s.move_with(|map, selection| {
13211                if !selection.is_empty() {
13212                    selection.goal = SelectionGoal::None;
13213                }
13214                let (cursor, goal) = movement::down_by_rows(
13215                    map,
13216                    selection.start,
13217                    action.lines,
13218                    selection.goal,
13219                    false,
13220                    text_layout_details,
13221                );
13222                selection.collapse_to(cursor, goal);
13223            });
13224        })
13225    }
13226
13227    pub fn select_down_by_lines(
13228        &mut self,
13229        action: &SelectDownByLines,
13230        window: &mut Window,
13231        cx: &mut Context<Self>,
13232    ) {
13233        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13234        let text_layout_details = &self.text_layout_details(window);
13235        self.change_selections(Default::default(), window, cx, |s| {
13236            s.move_heads_with(|map, head, goal| {
13237                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13238            })
13239        })
13240    }
13241
13242    pub fn select_up_by_lines(
13243        &mut self,
13244        action: &SelectUpByLines,
13245        window: &mut Window,
13246        cx: &mut Context<Self>,
13247    ) {
13248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13249        let text_layout_details = &self.text_layout_details(window);
13250        self.change_selections(Default::default(), window, cx, |s| {
13251            s.move_heads_with(|map, head, goal| {
13252                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13253            })
13254        })
13255    }
13256
13257    pub fn select_page_up(
13258        &mut self,
13259        _: &SelectPageUp,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        let Some(row_count) = self.visible_row_count() else {
13264            return;
13265        };
13266
13267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13268
13269        let text_layout_details = &self.text_layout_details(window);
13270
13271        self.change_selections(Default::default(), window, cx, |s| {
13272            s.move_heads_with(|map, head, goal| {
13273                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13274            })
13275        })
13276    }
13277
13278    pub fn move_page_up(
13279        &mut self,
13280        action: &MovePageUp,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        if self.take_rename(true, window, cx).is_some() {
13285            return;
13286        }
13287
13288        if self
13289            .context_menu
13290            .borrow_mut()
13291            .as_mut()
13292            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13293            .unwrap_or(false)
13294        {
13295            return;
13296        }
13297
13298        if matches!(self.mode, EditorMode::SingleLine) {
13299            cx.propagate();
13300            return;
13301        }
13302
13303        let Some(row_count) = self.visible_row_count() else {
13304            return;
13305        };
13306
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13308
13309        let effects = if action.center_cursor {
13310            SelectionEffects::scroll(Autoscroll::center())
13311        } else {
13312            SelectionEffects::default()
13313        };
13314
13315        let text_layout_details = &self.text_layout_details(window);
13316
13317        self.change_selections(effects, window, cx, |s| {
13318            s.move_with(|map, selection| {
13319                if !selection.is_empty() {
13320                    selection.goal = SelectionGoal::None;
13321                }
13322                let (cursor, goal) = movement::up_by_rows(
13323                    map,
13324                    selection.end,
13325                    row_count,
13326                    selection.goal,
13327                    false,
13328                    text_layout_details,
13329                );
13330                selection.collapse_to(cursor, goal);
13331            });
13332        });
13333    }
13334
13335    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13337        let text_layout_details = &self.text_layout_details(window);
13338        self.change_selections(Default::default(), window, cx, |s| {
13339            s.move_heads_with(|map, head, goal| {
13340                movement::up(map, head, goal, false, text_layout_details)
13341            })
13342        })
13343    }
13344
13345    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13346        self.take_rename(true, window, cx);
13347
13348        if self.mode.is_single_line() {
13349            cx.propagate();
13350            return;
13351        }
13352
13353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13354
13355        let text_layout_details = &self.text_layout_details(window);
13356        let selection_count = self.selections.count();
13357        let first_selection = self.selections.first_anchor();
13358
13359        self.change_selections(Default::default(), window, cx, |s| {
13360            s.move_with(|map, selection| {
13361                if !selection.is_empty() {
13362                    selection.goal = SelectionGoal::None;
13363                }
13364                let (cursor, goal) = movement::down(
13365                    map,
13366                    selection.end,
13367                    selection.goal,
13368                    false,
13369                    text_layout_details,
13370                );
13371                selection.collapse_to(cursor, goal);
13372            });
13373        });
13374
13375        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13376        {
13377            cx.propagate();
13378        }
13379    }
13380
13381    pub fn select_page_down(
13382        &mut self,
13383        _: &SelectPageDown,
13384        window: &mut Window,
13385        cx: &mut Context<Self>,
13386    ) {
13387        let Some(row_count) = self.visible_row_count() else {
13388            return;
13389        };
13390
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13392
13393        let text_layout_details = &self.text_layout_details(window);
13394
13395        self.change_selections(Default::default(), window, cx, |s| {
13396            s.move_heads_with(|map, head, goal| {
13397                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13398            })
13399        })
13400    }
13401
13402    pub fn move_page_down(
13403        &mut self,
13404        action: &MovePageDown,
13405        window: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        if self.take_rename(true, window, cx).is_some() {
13409            return;
13410        }
13411
13412        if self
13413            .context_menu
13414            .borrow_mut()
13415            .as_mut()
13416            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13417            .unwrap_or(false)
13418        {
13419            return;
13420        }
13421
13422        if matches!(self.mode, EditorMode::SingleLine) {
13423            cx.propagate();
13424            return;
13425        }
13426
13427        let Some(row_count) = self.visible_row_count() else {
13428            return;
13429        };
13430
13431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13432
13433        let effects = if action.center_cursor {
13434            SelectionEffects::scroll(Autoscroll::center())
13435        } else {
13436            SelectionEffects::default()
13437        };
13438
13439        let text_layout_details = &self.text_layout_details(window);
13440        self.change_selections(effects, window, cx, |s| {
13441            s.move_with(|map, selection| {
13442                if !selection.is_empty() {
13443                    selection.goal = SelectionGoal::None;
13444                }
13445                let (cursor, goal) = movement::down_by_rows(
13446                    map,
13447                    selection.end,
13448                    row_count,
13449                    selection.goal,
13450                    false,
13451                    text_layout_details,
13452                );
13453                selection.collapse_to(cursor, goal);
13454            });
13455        });
13456    }
13457
13458    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13460        let text_layout_details = &self.text_layout_details(window);
13461        self.change_selections(Default::default(), window, cx, |s| {
13462            s.move_heads_with(|map, head, goal| {
13463                movement::down(map, head, goal, false, text_layout_details)
13464            })
13465        });
13466    }
13467
13468    pub fn context_menu_first(
13469        &mut self,
13470        _: &ContextMenuFirst,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13475            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13476        }
13477    }
13478
13479    pub fn context_menu_prev(
13480        &mut self,
13481        _: &ContextMenuPrevious,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13486            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13487        }
13488    }
13489
13490    pub fn context_menu_next(
13491        &mut self,
13492        _: &ContextMenuNext,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13497            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13498        }
13499    }
13500
13501    pub fn context_menu_last(
13502        &mut self,
13503        _: &ContextMenuLast,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) {
13507        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13508            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13509        }
13510    }
13511
13512    pub fn signature_help_prev(
13513        &mut self,
13514        _: &SignatureHelpPrevious,
13515        _: &mut Window,
13516        cx: &mut Context<Self>,
13517    ) {
13518        if let Some(popover) = self.signature_help_state.popover_mut() {
13519            if popover.current_signature == 0 {
13520                popover.current_signature = popover.signatures.len() - 1;
13521            } else {
13522                popover.current_signature -= 1;
13523            }
13524            cx.notify();
13525        }
13526    }
13527
13528    pub fn signature_help_next(
13529        &mut self,
13530        _: &SignatureHelpNext,
13531        _: &mut Window,
13532        cx: &mut Context<Self>,
13533    ) {
13534        if let Some(popover) = self.signature_help_state.popover_mut() {
13535            if popover.current_signature + 1 == popover.signatures.len() {
13536                popover.current_signature = 0;
13537            } else {
13538                popover.current_signature += 1;
13539            }
13540            cx.notify();
13541        }
13542    }
13543
13544    pub fn move_to_previous_word_start(
13545        &mut self,
13546        _: &MoveToPreviousWordStart,
13547        window: &mut Window,
13548        cx: &mut Context<Self>,
13549    ) {
13550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13551        self.change_selections(Default::default(), window, cx, |s| {
13552            s.move_cursors_with(|map, head, _| {
13553                (
13554                    movement::previous_word_start(map, head),
13555                    SelectionGoal::None,
13556                )
13557            });
13558        })
13559    }
13560
13561    pub fn move_to_previous_subword_start(
13562        &mut self,
13563        _: &MoveToPreviousSubwordStart,
13564        window: &mut Window,
13565        cx: &mut Context<Self>,
13566    ) {
13567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13568        self.change_selections(Default::default(), window, cx, |s| {
13569            s.move_cursors_with(|map, head, _| {
13570                (
13571                    movement::previous_subword_start(map, head),
13572                    SelectionGoal::None,
13573                )
13574            });
13575        })
13576    }
13577
13578    pub fn select_to_previous_word_start(
13579        &mut self,
13580        _: &SelectToPreviousWordStart,
13581        window: &mut Window,
13582        cx: &mut Context<Self>,
13583    ) {
13584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13585        self.change_selections(Default::default(), window, cx, |s| {
13586            s.move_heads_with(|map, head, _| {
13587                (
13588                    movement::previous_word_start(map, head),
13589                    SelectionGoal::None,
13590                )
13591            });
13592        })
13593    }
13594
13595    pub fn select_to_previous_subword_start(
13596        &mut self,
13597        _: &SelectToPreviousSubwordStart,
13598        window: &mut Window,
13599        cx: &mut Context<Self>,
13600    ) {
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602        self.change_selections(Default::default(), window, cx, |s| {
13603            s.move_heads_with(|map, head, _| {
13604                (
13605                    movement::previous_subword_start(map, head),
13606                    SelectionGoal::None,
13607                )
13608            });
13609        })
13610    }
13611
13612    pub fn delete_to_previous_word_start(
13613        &mut self,
13614        action: &DeleteToPreviousWordStart,
13615        window: &mut Window,
13616        cx: &mut Context<Self>,
13617    ) {
13618        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13619        self.transact(window, cx, |this, window, cx| {
13620            this.select_autoclose_pair(window, cx);
13621            this.change_selections(Default::default(), window, cx, |s| {
13622                s.move_with(|map, selection| {
13623                    if selection.is_empty() {
13624                        let mut cursor = if action.ignore_newlines {
13625                            movement::previous_word_start(map, selection.head())
13626                        } else {
13627                            movement::previous_word_start_or_newline(map, selection.head())
13628                        };
13629                        cursor = movement::adjust_greedy_deletion(
13630                            map,
13631                            selection.head(),
13632                            cursor,
13633                            action.ignore_brackets,
13634                        );
13635                        selection.set_head(cursor, SelectionGoal::None);
13636                    }
13637                });
13638            });
13639            this.insert("", window, cx);
13640        });
13641    }
13642
13643    pub fn delete_to_previous_subword_start(
13644        &mut self,
13645        _: &DeleteToPreviousSubwordStart,
13646        window: &mut Window,
13647        cx: &mut Context<Self>,
13648    ) {
13649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13650        self.transact(window, cx, |this, window, cx| {
13651            this.select_autoclose_pair(window, cx);
13652            this.change_selections(Default::default(), window, cx, |s| {
13653                s.move_with(|map, selection| {
13654                    if selection.is_empty() {
13655                        let mut cursor = movement::previous_subword_start(map, selection.head());
13656                        cursor =
13657                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13658                        selection.set_head(cursor, SelectionGoal::None);
13659                    }
13660                });
13661            });
13662            this.insert("", window, cx);
13663        });
13664    }
13665
13666    pub fn move_to_next_word_end(
13667        &mut self,
13668        _: &MoveToNextWordEnd,
13669        window: &mut Window,
13670        cx: &mut Context<Self>,
13671    ) {
13672        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13673        self.change_selections(Default::default(), window, cx, |s| {
13674            s.move_cursors_with(|map, head, _| {
13675                (movement::next_word_end(map, head), SelectionGoal::None)
13676            });
13677        })
13678    }
13679
13680    pub fn move_to_next_subword_end(
13681        &mut self,
13682        _: &MoveToNextSubwordEnd,
13683        window: &mut Window,
13684        cx: &mut Context<Self>,
13685    ) {
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13687        self.change_selections(Default::default(), window, cx, |s| {
13688            s.move_cursors_with(|map, head, _| {
13689                (movement::next_subword_end(map, head), SelectionGoal::None)
13690            });
13691        })
13692    }
13693
13694    pub fn select_to_next_word_end(
13695        &mut self,
13696        _: &SelectToNextWordEnd,
13697        window: &mut Window,
13698        cx: &mut Context<Self>,
13699    ) {
13700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13701        self.change_selections(Default::default(), window, cx, |s| {
13702            s.move_heads_with(|map, head, _| {
13703                (movement::next_word_end(map, head), SelectionGoal::None)
13704            });
13705        })
13706    }
13707
13708    pub fn select_to_next_subword_end(
13709        &mut self,
13710        _: &SelectToNextSubwordEnd,
13711        window: &mut Window,
13712        cx: &mut Context<Self>,
13713    ) {
13714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13715        self.change_selections(Default::default(), window, cx, |s| {
13716            s.move_heads_with(|map, head, _| {
13717                (movement::next_subword_end(map, head), SelectionGoal::None)
13718            });
13719        })
13720    }
13721
13722    pub fn delete_to_next_word_end(
13723        &mut self,
13724        action: &DeleteToNextWordEnd,
13725        window: &mut Window,
13726        cx: &mut Context<Self>,
13727    ) {
13728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13729        self.transact(window, cx, |this, window, cx| {
13730            this.change_selections(Default::default(), window, cx, |s| {
13731                s.move_with(|map, selection| {
13732                    if selection.is_empty() {
13733                        let mut cursor = if action.ignore_newlines {
13734                            movement::next_word_end(map, selection.head())
13735                        } else {
13736                            movement::next_word_end_or_newline(map, selection.head())
13737                        };
13738                        cursor = movement::adjust_greedy_deletion(
13739                            map,
13740                            selection.head(),
13741                            cursor,
13742                            action.ignore_brackets,
13743                        );
13744                        selection.set_head(cursor, SelectionGoal::None);
13745                    }
13746                });
13747            });
13748            this.insert("", window, cx);
13749        });
13750    }
13751
13752    pub fn delete_to_next_subword_end(
13753        &mut self,
13754        _: &DeleteToNextSubwordEnd,
13755        window: &mut Window,
13756        cx: &mut Context<Self>,
13757    ) {
13758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13759        self.transact(window, cx, |this, window, cx| {
13760            this.change_selections(Default::default(), window, cx, |s| {
13761                s.move_with(|map, selection| {
13762                    if selection.is_empty() {
13763                        let mut cursor = movement::next_subword_end(map, selection.head());
13764                        cursor =
13765                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13766                        selection.set_head(cursor, SelectionGoal::None);
13767                    }
13768                });
13769            });
13770            this.insert("", window, cx);
13771        });
13772    }
13773
13774    pub fn move_to_beginning_of_line(
13775        &mut self,
13776        action: &MoveToBeginningOfLine,
13777        window: &mut Window,
13778        cx: &mut Context<Self>,
13779    ) {
13780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13781        self.change_selections(Default::default(), window, cx, |s| {
13782            s.move_cursors_with(|map, head, _| {
13783                (
13784                    movement::indented_line_beginning(
13785                        map,
13786                        head,
13787                        action.stop_at_soft_wraps,
13788                        action.stop_at_indent,
13789                    ),
13790                    SelectionGoal::None,
13791                )
13792            });
13793        })
13794    }
13795
13796    pub fn select_to_beginning_of_line(
13797        &mut self,
13798        action: &SelectToBeginningOfLine,
13799        window: &mut Window,
13800        cx: &mut Context<Self>,
13801    ) {
13802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13803        self.change_selections(Default::default(), window, cx, |s| {
13804            s.move_heads_with(|map, head, _| {
13805                (
13806                    movement::indented_line_beginning(
13807                        map,
13808                        head,
13809                        action.stop_at_soft_wraps,
13810                        action.stop_at_indent,
13811                    ),
13812                    SelectionGoal::None,
13813                )
13814            });
13815        });
13816    }
13817
13818    pub fn delete_to_beginning_of_line(
13819        &mut self,
13820        action: &DeleteToBeginningOfLine,
13821        window: &mut Window,
13822        cx: &mut Context<Self>,
13823    ) {
13824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13825        self.transact(window, cx, |this, window, cx| {
13826            this.change_selections(Default::default(), window, cx, |s| {
13827                s.move_with(|_, selection| {
13828                    selection.reversed = true;
13829                });
13830            });
13831
13832            this.select_to_beginning_of_line(
13833                &SelectToBeginningOfLine {
13834                    stop_at_soft_wraps: false,
13835                    stop_at_indent: action.stop_at_indent,
13836                },
13837                window,
13838                cx,
13839            );
13840            this.backspace(&Backspace, window, cx);
13841        });
13842    }
13843
13844    pub fn move_to_end_of_line(
13845        &mut self,
13846        action: &MoveToEndOfLine,
13847        window: &mut Window,
13848        cx: &mut Context<Self>,
13849    ) {
13850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13851        self.change_selections(Default::default(), window, cx, |s| {
13852            s.move_cursors_with(|map, head, _| {
13853                (
13854                    movement::line_end(map, head, action.stop_at_soft_wraps),
13855                    SelectionGoal::None,
13856                )
13857            });
13858        })
13859    }
13860
13861    pub fn select_to_end_of_line(
13862        &mut self,
13863        action: &SelectToEndOfLine,
13864        window: &mut Window,
13865        cx: &mut Context<Self>,
13866    ) {
13867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13868        self.change_selections(Default::default(), window, cx, |s| {
13869            s.move_heads_with(|map, head, _| {
13870                (
13871                    movement::line_end(map, head, action.stop_at_soft_wraps),
13872                    SelectionGoal::None,
13873                )
13874            });
13875        })
13876    }
13877
13878    pub fn delete_to_end_of_line(
13879        &mut self,
13880        _: &DeleteToEndOfLine,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13885        self.transact(window, cx, |this, window, cx| {
13886            this.select_to_end_of_line(
13887                &SelectToEndOfLine {
13888                    stop_at_soft_wraps: false,
13889                },
13890                window,
13891                cx,
13892            );
13893            this.delete(&Delete, window, cx);
13894        });
13895    }
13896
13897    pub fn cut_to_end_of_line(
13898        &mut self,
13899        action: &CutToEndOfLine,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13904        self.transact(window, cx, |this, window, cx| {
13905            this.select_to_end_of_line(
13906                &SelectToEndOfLine {
13907                    stop_at_soft_wraps: false,
13908                },
13909                window,
13910                cx,
13911            );
13912            if !action.stop_at_newlines {
13913                this.change_selections(Default::default(), window, cx, |s| {
13914                    s.move_with(|_, sel| {
13915                        if sel.is_empty() {
13916                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13917                        }
13918                    });
13919                });
13920            }
13921            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13922            let item = this.cut_common(false, window, cx);
13923            cx.write_to_clipboard(item);
13924        });
13925    }
13926
13927    pub fn move_to_start_of_paragraph(
13928        &mut self,
13929        _: &MoveToStartOfParagraph,
13930        window: &mut Window,
13931        cx: &mut Context<Self>,
13932    ) {
13933        if matches!(self.mode, EditorMode::SingleLine) {
13934            cx.propagate();
13935            return;
13936        }
13937        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13938        self.change_selections(Default::default(), window, cx, |s| {
13939            s.move_with(|map, selection| {
13940                selection.collapse_to(
13941                    movement::start_of_paragraph(map, selection.head(), 1),
13942                    SelectionGoal::None,
13943                )
13944            });
13945        })
13946    }
13947
13948    pub fn move_to_end_of_paragraph(
13949        &mut self,
13950        _: &MoveToEndOfParagraph,
13951        window: &mut Window,
13952        cx: &mut Context<Self>,
13953    ) {
13954        if matches!(self.mode, EditorMode::SingleLine) {
13955            cx.propagate();
13956            return;
13957        }
13958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13959        self.change_selections(Default::default(), window, cx, |s| {
13960            s.move_with(|map, selection| {
13961                selection.collapse_to(
13962                    movement::end_of_paragraph(map, selection.head(), 1),
13963                    SelectionGoal::None,
13964                )
13965            });
13966        })
13967    }
13968
13969    pub fn select_to_start_of_paragraph(
13970        &mut self,
13971        _: &SelectToStartOfParagraph,
13972        window: &mut Window,
13973        cx: &mut Context<Self>,
13974    ) {
13975        if matches!(self.mode, EditorMode::SingleLine) {
13976            cx.propagate();
13977            return;
13978        }
13979        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13980        self.change_selections(Default::default(), window, cx, |s| {
13981            s.move_heads_with(|map, head, _| {
13982                (
13983                    movement::start_of_paragraph(map, head, 1),
13984                    SelectionGoal::None,
13985                )
13986            });
13987        })
13988    }
13989
13990    pub fn select_to_end_of_paragraph(
13991        &mut self,
13992        _: &SelectToEndOfParagraph,
13993        window: &mut Window,
13994        cx: &mut Context<Self>,
13995    ) {
13996        if matches!(self.mode, EditorMode::SingleLine) {
13997            cx.propagate();
13998            return;
13999        }
14000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14001        self.change_selections(Default::default(), window, cx, |s| {
14002            s.move_heads_with(|map, head, _| {
14003                (
14004                    movement::end_of_paragraph(map, head, 1),
14005                    SelectionGoal::None,
14006                )
14007            });
14008        })
14009    }
14010
14011    pub fn move_to_start_of_excerpt(
14012        &mut self,
14013        _: &MoveToStartOfExcerpt,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) {
14017        if matches!(self.mode, EditorMode::SingleLine) {
14018            cx.propagate();
14019            return;
14020        }
14021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14022        self.change_selections(Default::default(), window, cx, |s| {
14023            s.move_with(|map, selection| {
14024                selection.collapse_to(
14025                    movement::start_of_excerpt(
14026                        map,
14027                        selection.head(),
14028                        workspace::searchable::Direction::Prev,
14029                    ),
14030                    SelectionGoal::None,
14031                )
14032            });
14033        })
14034    }
14035
14036    pub fn move_to_start_of_next_excerpt(
14037        &mut self,
14038        _: &MoveToStartOfNextExcerpt,
14039        window: &mut Window,
14040        cx: &mut Context<Self>,
14041    ) {
14042        if matches!(self.mode, EditorMode::SingleLine) {
14043            cx.propagate();
14044            return;
14045        }
14046
14047        self.change_selections(Default::default(), window, cx, |s| {
14048            s.move_with(|map, selection| {
14049                selection.collapse_to(
14050                    movement::start_of_excerpt(
14051                        map,
14052                        selection.head(),
14053                        workspace::searchable::Direction::Next,
14054                    ),
14055                    SelectionGoal::None,
14056                )
14057            });
14058        })
14059    }
14060
14061    pub fn move_to_end_of_excerpt(
14062        &mut self,
14063        _: &MoveToEndOfExcerpt,
14064        window: &mut Window,
14065        cx: &mut Context<Self>,
14066    ) {
14067        if matches!(self.mode, EditorMode::SingleLine) {
14068            cx.propagate();
14069            return;
14070        }
14071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14072        self.change_selections(Default::default(), window, cx, |s| {
14073            s.move_with(|map, selection| {
14074                selection.collapse_to(
14075                    movement::end_of_excerpt(
14076                        map,
14077                        selection.head(),
14078                        workspace::searchable::Direction::Next,
14079                    ),
14080                    SelectionGoal::None,
14081                )
14082            });
14083        })
14084    }
14085
14086    pub fn move_to_end_of_previous_excerpt(
14087        &mut self,
14088        _: &MoveToEndOfPreviousExcerpt,
14089        window: &mut Window,
14090        cx: &mut Context<Self>,
14091    ) {
14092        if matches!(self.mode, EditorMode::SingleLine) {
14093            cx.propagate();
14094            return;
14095        }
14096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14097        self.change_selections(Default::default(), window, cx, |s| {
14098            s.move_with(|map, selection| {
14099                selection.collapse_to(
14100                    movement::end_of_excerpt(
14101                        map,
14102                        selection.head(),
14103                        workspace::searchable::Direction::Prev,
14104                    ),
14105                    SelectionGoal::None,
14106                )
14107            });
14108        })
14109    }
14110
14111    pub fn select_to_start_of_excerpt(
14112        &mut self,
14113        _: &SelectToStartOfExcerpt,
14114        window: &mut Window,
14115        cx: &mut Context<Self>,
14116    ) {
14117        if matches!(self.mode, EditorMode::SingleLine) {
14118            cx.propagate();
14119            return;
14120        }
14121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14122        self.change_selections(Default::default(), window, cx, |s| {
14123            s.move_heads_with(|map, head, _| {
14124                (
14125                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14126                    SelectionGoal::None,
14127                )
14128            });
14129        })
14130    }
14131
14132    pub fn select_to_start_of_next_excerpt(
14133        &mut self,
14134        _: &SelectToStartOfNextExcerpt,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) {
14138        if matches!(self.mode, EditorMode::SingleLine) {
14139            cx.propagate();
14140            return;
14141        }
14142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14143        self.change_selections(Default::default(), window, cx, |s| {
14144            s.move_heads_with(|map, head, _| {
14145                (
14146                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14147                    SelectionGoal::None,
14148                )
14149            });
14150        })
14151    }
14152
14153    pub fn select_to_end_of_excerpt(
14154        &mut self,
14155        _: &SelectToEndOfExcerpt,
14156        window: &mut Window,
14157        cx: &mut Context<Self>,
14158    ) {
14159        if matches!(self.mode, EditorMode::SingleLine) {
14160            cx.propagate();
14161            return;
14162        }
14163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14164        self.change_selections(Default::default(), window, cx, |s| {
14165            s.move_heads_with(|map, head, _| {
14166                (
14167                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14168                    SelectionGoal::None,
14169                )
14170            });
14171        })
14172    }
14173
14174    pub fn select_to_end_of_previous_excerpt(
14175        &mut self,
14176        _: &SelectToEndOfPreviousExcerpt,
14177        window: &mut Window,
14178        cx: &mut Context<Self>,
14179    ) {
14180        if matches!(self.mode, EditorMode::SingleLine) {
14181            cx.propagate();
14182            return;
14183        }
14184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14185        self.change_selections(Default::default(), window, cx, |s| {
14186            s.move_heads_with(|map, head, _| {
14187                (
14188                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14189                    SelectionGoal::None,
14190                )
14191            });
14192        })
14193    }
14194
14195    pub fn move_to_beginning(
14196        &mut self,
14197        _: &MoveToBeginning,
14198        window: &mut Window,
14199        cx: &mut Context<Self>,
14200    ) {
14201        if matches!(self.mode, EditorMode::SingleLine) {
14202            cx.propagate();
14203            return;
14204        }
14205        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14206        self.change_selections(Default::default(), window, cx, |s| {
14207            s.select_ranges(vec![0..0]);
14208        });
14209    }
14210
14211    pub fn select_to_beginning(
14212        &mut self,
14213        _: &SelectToBeginning,
14214        window: &mut Window,
14215        cx: &mut Context<Self>,
14216    ) {
14217        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14218        selection.set_head(Point::zero(), SelectionGoal::None);
14219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14220        self.change_selections(Default::default(), window, cx, |s| {
14221            s.select(vec![selection]);
14222        });
14223    }
14224
14225    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14226        if matches!(self.mode, EditorMode::SingleLine) {
14227            cx.propagate();
14228            return;
14229        }
14230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14231        let cursor = self.buffer.read(cx).read(cx).len();
14232        self.change_selections(Default::default(), window, cx, |s| {
14233            s.select_ranges(vec![cursor..cursor])
14234        });
14235    }
14236
14237    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14238        self.nav_history = nav_history;
14239    }
14240
14241    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14242        self.nav_history.as_ref()
14243    }
14244
14245    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14246        self.push_to_nav_history(
14247            self.selections.newest_anchor().head(),
14248            None,
14249            false,
14250            true,
14251            cx,
14252        );
14253    }
14254
14255    fn push_to_nav_history(
14256        &mut self,
14257        cursor_anchor: Anchor,
14258        new_position: Option<Point>,
14259        is_deactivate: bool,
14260        always: bool,
14261        cx: &mut Context<Self>,
14262    ) {
14263        if let Some(nav_history) = self.nav_history.as_mut() {
14264            let buffer = self.buffer.read(cx).read(cx);
14265            let cursor_position = cursor_anchor.to_point(&buffer);
14266            let scroll_state = self.scroll_manager.anchor();
14267            let scroll_top_row = scroll_state.top_row(&buffer);
14268            drop(buffer);
14269
14270            if let Some(new_position) = new_position {
14271                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14272                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14273                    return;
14274                }
14275            }
14276
14277            nav_history.push(
14278                Some(NavigationData {
14279                    cursor_anchor,
14280                    cursor_position,
14281                    scroll_anchor: scroll_state,
14282                    scroll_top_row,
14283                }),
14284                cx,
14285            );
14286            cx.emit(EditorEvent::PushedToNavHistory {
14287                anchor: cursor_anchor,
14288                is_deactivate,
14289            })
14290        }
14291    }
14292
14293    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14295        let buffer = self.buffer.read(cx).snapshot(cx);
14296        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14297        selection.set_head(buffer.len(), SelectionGoal::None);
14298        self.change_selections(Default::default(), window, cx, |s| {
14299            s.select(vec![selection]);
14300        });
14301    }
14302
14303    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14304        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14305        let end = self.buffer.read(cx).read(cx).len();
14306        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14307            s.select_ranges(vec![0..end]);
14308        });
14309    }
14310
14311    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14313        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14314        let mut selections = self.selections.all::<Point>(&display_map);
14315        let max_point = display_map.buffer_snapshot().max_point();
14316        for selection in &mut selections {
14317            let rows = selection.spanned_rows(true, &display_map);
14318            selection.start = Point::new(rows.start.0, 0);
14319            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14320            selection.reversed = false;
14321        }
14322        self.change_selections(Default::default(), window, cx, |s| {
14323            s.select(selections);
14324        });
14325    }
14326
14327    pub fn split_selection_into_lines(
14328        &mut self,
14329        action: &SplitSelectionIntoLines,
14330        window: &mut Window,
14331        cx: &mut Context<Self>,
14332    ) {
14333        let selections = self
14334            .selections
14335            .all::<Point>(&self.display_snapshot(cx))
14336            .into_iter()
14337            .map(|selection| selection.start..selection.end)
14338            .collect::<Vec<_>>();
14339        self.unfold_ranges(&selections, true, true, cx);
14340
14341        let mut new_selection_ranges = Vec::new();
14342        {
14343            let buffer = self.buffer.read(cx).read(cx);
14344            for selection in selections {
14345                for row in selection.start.row..selection.end.row {
14346                    let line_start = Point::new(row, 0);
14347                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14348
14349                    if action.keep_selections {
14350                        // Keep the selection range for each line
14351                        let selection_start = if row == selection.start.row {
14352                            selection.start
14353                        } else {
14354                            line_start
14355                        };
14356                        new_selection_ranges.push(selection_start..line_end);
14357                    } else {
14358                        // Collapse to cursor at end of line
14359                        new_selection_ranges.push(line_end..line_end);
14360                    }
14361                }
14362
14363                let is_multiline_selection = selection.start.row != selection.end.row;
14364                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14365                // so this action feels more ergonomic when paired with other selection operations
14366                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14367                if !should_skip_last {
14368                    if action.keep_selections {
14369                        if is_multiline_selection {
14370                            let line_start = Point::new(selection.end.row, 0);
14371                            new_selection_ranges.push(line_start..selection.end);
14372                        } else {
14373                            new_selection_ranges.push(selection.start..selection.end);
14374                        }
14375                    } else {
14376                        new_selection_ranges.push(selection.end..selection.end);
14377                    }
14378                }
14379            }
14380        }
14381        self.change_selections(Default::default(), window, cx, |s| {
14382            s.select_ranges(new_selection_ranges);
14383        });
14384    }
14385
14386    pub fn add_selection_above(
14387        &mut self,
14388        action: &AddSelectionAbove,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) {
14392        self.add_selection(true, action.skip_soft_wrap, window, cx);
14393    }
14394
14395    pub fn add_selection_below(
14396        &mut self,
14397        action: &AddSelectionBelow,
14398        window: &mut Window,
14399        cx: &mut Context<Self>,
14400    ) {
14401        self.add_selection(false, action.skip_soft_wrap, window, cx);
14402    }
14403
14404    fn add_selection(
14405        &mut self,
14406        above: bool,
14407        skip_soft_wrap: bool,
14408        window: &mut Window,
14409        cx: &mut Context<Self>,
14410    ) {
14411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14412
14413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14414        let all_selections = self.selections.all::<Point>(&display_map);
14415        let text_layout_details = self.text_layout_details(window);
14416
14417        let (mut columnar_selections, new_selections_to_columnarize) = {
14418            if let Some(state) = self.add_selections_state.as_ref() {
14419                let columnar_selection_ids: HashSet<_> = state
14420                    .groups
14421                    .iter()
14422                    .flat_map(|group| group.stack.iter())
14423                    .copied()
14424                    .collect();
14425
14426                all_selections
14427                    .into_iter()
14428                    .partition(|s| columnar_selection_ids.contains(&s.id))
14429            } else {
14430                (Vec::new(), all_selections)
14431            }
14432        };
14433
14434        let mut state = self
14435            .add_selections_state
14436            .take()
14437            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14438
14439        for selection in new_selections_to_columnarize {
14440            let range = selection.display_range(&display_map).sorted();
14441            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14442            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14443            let positions = start_x.min(end_x)..start_x.max(end_x);
14444            let mut stack = Vec::new();
14445            for row in range.start.row().0..=range.end.row().0 {
14446                if let Some(selection) = self.selections.build_columnar_selection(
14447                    &display_map,
14448                    DisplayRow(row),
14449                    &positions,
14450                    selection.reversed,
14451                    &text_layout_details,
14452                ) {
14453                    stack.push(selection.id);
14454                    columnar_selections.push(selection);
14455                }
14456            }
14457            if !stack.is_empty() {
14458                if above {
14459                    stack.reverse();
14460                }
14461                state.groups.push(AddSelectionsGroup { above, stack });
14462            }
14463        }
14464
14465        let mut final_selections = Vec::new();
14466        let end_row = if above {
14467            DisplayRow(0)
14468        } else {
14469            display_map.max_point().row()
14470        };
14471
14472        let mut last_added_item_per_group = HashMap::default();
14473        for group in state.groups.iter_mut() {
14474            if let Some(last_id) = group.stack.last() {
14475                last_added_item_per_group.insert(*last_id, group);
14476            }
14477        }
14478
14479        for selection in columnar_selections {
14480            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14481                if above == group.above {
14482                    let range = selection.display_range(&display_map).sorted();
14483                    debug_assert_eq!(range.start.row(), range.end.row());
14484                    let mut row = range.start.row();
14485                    let positions =
14486                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14487                            Pixels::from(start)..Pixels::from(end)
14488                        } else {
14489                            let start_x =
14490                                display_map.x_for_display_point(range.start, &text_layout_details);
14491                            let end_x =
14492                                display_map.x_for_display_point(range.end, &text_layout_details);
14493                            start_x.min(end_x)..start_x.max(end_x)
14494                        };
14495
14496                    let mut maybe_new_selection = None;
14497                    let direction = if above { -1 } else { 1 };
14498
14499                    while row != end_row {
14500                        if skip_soft_wrap {
14501                            row = display_map
14502                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14503                                .row();
14504                        } else if above {
14505                            row.0 -= 1;
14506                        } else {
14507                            row.0 += 1;
14508                        }
14509
14510                        if let Some(new_selection) = self.selections.build_columnar_selection(
14511                            &display_map,
14512                            row,
14513                            &positions,
14514                            selection.reversed,
14515                            &text_layout_details,
14516                        ) {
14517                            maybe_new_selection = Some(new_selection);
14518                            break;
14519                        }
14520                    }
14521
14522                    if let Some(new_selection) = maybe_new_selection {
14523                        group.stack.push(new_selection.id);
14524                        if above {
14525                            final_selections.push(new_selection);
14526                            final_selections.push(selection);
14527                        } else {
14528                            final_selections.push(selection);
14529                            final_selections.push(new_selection);
14530                        }
14531                    } else {
14532                        final_selections.push(selection);
14533                    }
14534                } else {
14535                    group.stack.pop();
14536                }
14537            } else {
14538                final_selections.push(selection);
14539            }
14540        }
14541
14542        self.change_selections(Default::default(), window, cx, |s| {
14543            s.select(final_selections);
14544        });
14545
14546        let final_selection_ids: HashSet<_> = self
14547            .selections
14548            .all::<Point>(&display_map)
14549            .iter()
14550            .map(|s| s.id)
14551            .collect();
14552        state.groups.retain_mut(|group| {
14553            // selections might get merged above so we remove invalid items from stacks
14554            group.stack.retain(|id| final_selection_ids.contains(id));
14555
14556            // single selection in stack can be treated as initial state
14557            group.stack.len() > 1
14558        });
14559
14560        if !state.groups.is_empty() {
14561            self.add_selections_state = Some(state);
14562        }
14563    }
14564
14565    fn select_match_ranges(
14566        &mut self,
14567        range: Range<usize>,
14568        reversed: bool,
14569        replace_newest: bool,
14570        auto_scroll: Option<Autoscroll>,
14571        window: &mut Window,
14572        cx: &mut Context<Editor>,
14573    ) {
14574        self.unfold_ranges(
14575            std::slice::from_ref(&range),
14576            false,
14577            auto_scroll.is_some(),
14578            cx,
14579        );
14580        let effects = if let Some(scroll) = auto_scroll {
14581            SelectionEffects::scroll(scroll)
14582        } else {
14583            SelectionEffects::no_scroll()
14584        };
14585        self.change_selections(effects, window, cx, |s| {
14586            if replace_newest {
14587                s.delete(s.newest_anchor().id);
14588            }
14589            if reversed {
14590                s.insert_range(range.end..range.start);
14591            } else {
14592                s.insert_range(range);
14593            }
14594        });
14595    }
14596
14597    pub fn select_next_match_internal(
14598        &mut self,
14599        display_map: &DisplaySnapshot,
14600        replace_newest: bool,
14601        autoscroll: Option<Autoscroll>,
14602        window: &mut Window,
14603        cx: &mut Context<Self>,
14604    ) -> Result<()> {
14605        let buffer = display_map.buffer_snapshot();
14606        let mut selections = self.selections.all::<usize>(&display_map);
14607        if let Some(mut select_next_state) = self.select_next_state.take() {
14608            let query = &select_next_state.query;
14609            if !select_next_state.done {
14610                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14611                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14612                let mut next_selected_range = None;
14613
14614                let bytes_after_last_selection =
14615                    buffer.bytes_in_range(last_selection.end..buffer.len());
14616                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14617                let query_matches = query
14618                    .stream_find_iter(bytes_after_last_selection)
14619                    .map(|result| (last_selection.end, result))
14620                    .chain(
14621                        query
14622                            .stream_find_iter(bytes_before_first_selection)
14623                            .map(|result| (0, result)),
14624                    );
14625
14626                for (start_offset, query_match) in query_matches {
14627                    let query_match = query_match.unwrap(); // can only fail due to I/O
14628                    let offset_range =
14629                        start_offset + query_match.start()..start_offset + query_match.end();
14630
14631                    if !select_next_state.wordwise
14632                        || (!buffer.is_inside_word(offset_range.start, None)
14633                            && !buffer.is_inside_word(offset_range.end, None))
14634                    {
14635                        let idx = selections
14636                            .partition_point(|selection| selection.end <= offset_range.start);
14637                        let overlaps = selections
14638                            .get(idx)
14639                            .map_or(false, |selection| selection.start < offset_range.end);
14640
14641                        if !overlaps {
14642                            next_selected_range = Some(offset_range);
14643                            break;
14644                        }
14645                    }
14646                }
14647
14648                if let Some(next_selected_range) = next_selected_range {
14649                    self.select_match_ranges(
14650                        next_selected_range,
14651                        last_selection.reversed,
14652                        replace_newest,
14653                        autoscroll,
14654                        window,
14655                        cx,
14656                    );
14657                } else {
14658                    select_next_state.done = true;
14659                }
14660            }
14661
14662            self.select_next_state = Some(select_next_state);
14663        } else {
14664            let mut only_carets = true;
14665            let mut same_text_selected = true;
14666            let mut selected_text = None;
14667
14668            let mut selections_iter = selections.iter().peekable();
14669            while let Some(selection) = selections_iter.next() {
14670                if selection.start != selection.end {
14671                    only_carets = false;
14672                }
14673
14674                if same_text_selected {
14675                    if selected_text.is_none() {
14676                        selected_text =
14677                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14678                    }
14679
14680                    if let Some(next_selection) = selections_iter.peek() {
14681                        if next_selection.range().len() == selection.range().len() {
14682                            let next_selected_text = buffer
14683                                .text_for_range(next_selection.range())
14684                                .collect::<String>();
14685                            if Some(next_selected_text) != selected_text {
14686                                same_text_selected = false;
14687                                selected_text = None;
14688                            }
14689                        } else {
14690                            same_text_selected = false;
14691                            selected_text = None;
14692                        }
14693                    }
14694                }
14695            }
14696
14697            if only_carets {
14698                for selection in &mut selections {
14699                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14700                    selection.start = word_range.start;
14701                    selection.end = word_range.end;
14702                    selection.goal = SelectionGoal::None;
14703                    selection.reversed = false;
14704                    self.select_match_ranges(
14705                        selection.start..selection.end,
14706                        selection.reversed,
14707                        replace_newest,
14708                        autoscroll,
14709                        window,
14710                        cx,
14711                    );
14712                }
14713
14714                if selections.len() == 1 {
14715                    let selection = selections
14716                        .last()
14717                        .expect("ensured that there's only one selection");
14718                    let query = buffer
14719                        .text_for_range(selection.start..selection.end)
14720                        .collect::<String>();
14721                    let is_empty = query.is_empty();
14722                    let select_state = SelectNextState {
14723                        query: self.build_query(&[query], cx)?,
14724                        wordwise: true,
14725                        done: is_empty,
14726                    };
14727                    self.select_next_state = Some(select_state);
14728                } else {
14729                    self.select_next_state = None;
14730                }
14731            } else if let Some(selected_text) = selected_text {
14732                self.select_next_state = Some(SelectNextState {
14733                    query: self.build_query(&[selected_text], cx)?,
14734                    wordwise: false,
14735                    done: false,
14736                });
14737                self.select_next_match_internal(
14738                    display_map,
14739                    replace_newest,
14740                    autoscroll,
14741                    window,
14742                    cx,
14743                )?;
14744            }
14745        }
14746        Ok(())
14747    }
14748
14749    pub fn select_all_matches(
14750        &mut self,
14751        _action: &SelectAllMatches,
14752        window: &mut Window,
14753        cx: &mut Context<Self>,
14754    ) -> Result<()> {
14755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14756
14757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14758
14759        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14760        let Some(select_next_state) = self.select_next_state.as_mut() else {
14761            return Ok(());
14762        };
14763        if select_next_state.done {
14764            return Ok(());
14765        }
14766
14767        let mut new_selections = Vec::new();
14768
14769        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14770        let buffer = display_map.buffer_snapshot();
14771        let query_matches = select_next_state
14772            .query
14773            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14774
14775        for query_match in query_matches.into_iter() {
14776            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14777            let offset_range = if reversed {
14778                query_match.end()..query_match.start()
14779            } else {
14780                query_match.start()..query_match.end()
14781            };
14782
14783            if !select_next_state.wordwise
14784                || (!buffer.is_inside_word(offset_range.start, None)
14785                    && !buffer.is_inside_word(offset_range.end, None))
14786            {
14787                new_selections.push(offset_range.start..offset_range.end);
14788            }
14789        }
14790
14791        select_next_state.done = true;
14792
14793        if new_selections.is_empty() {
14794            log::error!("bug: new_selections is empty in select_all_matches");
14795            return Ok(());
14796        }
14797
14798        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14799        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14800            selections.select_ranges(new_selections)
14801        });
14802
14803        Ok(())
14804    }
14805
14806    pub fn select_next(
14807        &mut self,
14808        action: &SelectNext,
14809        window: &mut Window,
14810        cx: &mut Context<Self>,
14811    ) -> Result<()> {
14812        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14813        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14814        self.select_next_match_internal(
14815            &display_map,
14816            action.replace_newest,
14817            Some(Autoscroll::newest()),
14818            window,
14819            cx,
14820        )?;
14821        Ok(())
14822    }
14823
14824    pub fn select_previous(
14825        &mut self,
14826        action: &SelectPrevious,
14827        window: &mut Window,
14828        cx: &mut Context<Self>,
14829    ) -> Result<()> {
14830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14831        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14832        let buffer = display_map.buffer_snapshot();
14833        let mut selections = self.selections.all::<usize>(&display_map);
14834        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14835            let query = &select_prev_state.query;
14836            if !select_prev_state.done {
14837                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14838                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14839                let mut next_selected_range = None;
14840                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14841                let bytes_before_last_selection =
14842                    buffer.reversed_bytes_in_range(0..last_selection.start);
14843                let bytes_after_first_selection =
14844                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14845                let query_matches = query
14846                    .stream_find_iter(bytes_before_last_selection)
14847                    .map(|result| (last_selection.start, result))
14848                    .chain(
14849                        query
14850                            .stream_find_iter(bytes_after_first_selection)
14851                            .map(|result| (buffer.len(), result)),
14852                    );
14853                for (end_offset, query_match) in query_matches {
14854                    let query_match = query_match.unwrap(); // can only fail due to I/O
14855                    let offset_range =
14856                        end_offset - query_match.end()..end_offset - query_match.start();
14857
14858                    if !select_prev_state.wordwise
14859                        || (!buffer.is_inside_word(offset_range.start, None)
14860                            && !buffer.is_inside_word(offset_range.end, None))
14861                    {
14862                        next_selected_range = Some(offset_range);
14863                        break;
14864                    }
14865                }
14866
14867                if let Some(next_selected_range) = next_selected_range {
14868                    self.select_match_ranges(
14869                        next_selected_range,
14870                        last_selection.reversed,
14871                        action.replace_newest,
14872                        Some(Autoscroll::newest()),
14873                        window,
14874                        cx,
14875                    );
14876                } else {
14877                    select_prev_state.done = true;
14878                }
14879            }
14880
14881            self.select_prev_state = Some(select_prev_state);
14882        } else {
14883            let mut only_carets = true;
14884            let mut same_text_selected = true;
14885            let mut selected_text = None;
14886
14887            let mut selections_iter = selections.iter().peekable();
14888            while let Some(selection) = selections_iter.next() {
14889                if selection.start != selection.end {
14890                    only_carets = false;
14891                }
14892
14893                if same_text_selected {
14894                    if selected_text.is_none() {
14895                        selected_text =
14896                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14897                    }
14898
14899                    if let Some(next_selection) = selections_iter.peek() {
14900                        if next_selection.range().len() == selection.range().len() {
14901                            let next_selected_text = buffer
14902                                .text_for_range(next_selection.range())
14903                                .collect::<String>();
14904                            if Some(next_selected_text) != selected_text {
14905                                same_text_selected = false;
14906                                selected_text = None;
14907                            }
14908                        } else {
14909                            same_text_selected = false;
14910                            selected_text = None;
14911                        }
14912                    }
14913                }
14914            }
14915
14916            if only_carets {
14917                for selection in &mut selections {
14918                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14919                    selection.start = word_range.start;
14920                    selection.end = word_range.end;
14921                    selection.goal = SelectionGoal::None;
14922                    selection.reversed = false;
14923                    self.select_match_ranges(
14924                        selection.start..selection.end,
14925                        selection.reversed,
14926                        action.replace_newest,
14927                        Some(Autoscroll::newest()),
14928                        window,
14929                        cx,
14930                    );
14931                }
14932                if selections.len() == 1 {
14933                    let selection = selections
14934                        .last()
14935                        .expect("ensured that there's only one selection");
14936                    let query = buffer
14937                        .text_for_range(selection.start..selection.end)
14938                        .collect::<String>();
14939                    let is_empty = query.is_empty();
14940                    let select_state = SelectNextState {
14941                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14942                        wordwise: true,
14943                        done: is_empty,
14944                    };
14945                    self.select_prev_state = Some(select_state);
14946                } else {
14947                    self.select_prev_state = None;
14948                }
14949            } else if let Some(selected_text) = selected_text {
14950                self.select_prev_state = Some(SelectNextState {
14951                    query: self
14952                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
14953                    wordwise: false,
14954                    done: false,
14955                });
14956                self.select_previous(action, window, cx)?;
14957            }
14958        }
14959        Ok(())
14960    }
14961
14962    /// Builds an `AhoCorasick` automaton from the provided patterns, while
14963    /// setting the case sensitivity based on the global
14964    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
14965    /// editor's settings.
14966    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
14967    where
14968        I: IntoIterator<Item = P>,
14969        P: AsRef<[u8]>,
14970    {
14971        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
14972            || EditorSettings::get_global(cx).search.case_sensitive,
14973            |value| value,
14974        );
14975
14976        let mut builder = AhoCorasickBuilder::new();
14977        builder.ascii_case_insensitive(!case_sensitive);
14978        builder.build(patterns)
14979    }
14980
14981    pub fn find_next_match(
14982        &mut self,
14983        _: &FindNextMatch,
14984        window: &mut Window,
14985        cx: &mut Context<Self>,
14986    ) -> Result<()> {
14987        let selections = self.selections.disjoint_anchors_arc();
14988        match selections.first() {
14989            Some(first) if selections.len() >= 2 => {
14990                self.change_selections(Default::default(), window, cx, |s| {
14991                    s.select_ranges([first.range()]);
14992                });
14993            }
14994            _ => self.select_next(
14995                &SelectNext {
14996                    replace_newest: true,
14997                },
14998                window,
14999                cx,
15000            )?,
15001        }
15002        Ok(())
15003    }
15004
15005    pub fn find_previous_match(
15006        &mut self,
15007        _: &FindPreviousMatch,
15008        window: &mut Window,
15009        cx: &mut Context<Self>,
15010    ) -> Result<()> {
15011        let selections = self.selections.disjoint_anchors_arc();
15012        match selections.last() {
15013            Some(last) if selections.len() >= 2 => {
15014                self.change_selections(Default::default(), window, cx, |s| {
15015                    s.select_ranges([last.range()]);
15016                });
15017            }
15018            _ => self.select_previous(
15019                &SelectPrevious {
15020                    replace_newest: true,
15021                },
15022                window,
15023                cx,
15024            )?,
15025        }
15026        Ok(())
15027    }
15028
15029    pub fn toggle_comments(
15030        &mut self,
15031        action: &ToggleComments,
15032        window: &mut Window,
15033        cx: &mut Context<Self>,
15034    ) {
15035        if self.read_only(cx) {
15036            return;
15037        }
15038        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15039        let text_layout_details = &self.text_layout_details(window);
15040        self.transact(window, cx, |this, window, cx| {
15041            let mut selections = this
15042                .selections
15043                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15044            let mut edits = Vec::new();
15045            let mut selection_edit_ranges = Vec::new();
15046            let mut last_toggled_row = None;
15047            let snapshot = this.buffer.read(cx).read(cx);
15048            let empty_str: Arc<str> = Arc::default();
15049            let mut suffixes_inserted = Vec::new();
15050            let ignore_indent = action.ignore_indent;
15051
15052            fn comment_prefix_range(
15053                snapshot: &MultiBufferSnapshot,
15054                row: MultiBufferRow,
15055                comment_prefix: &str,
15056                comment_prefix_whitespace: &str,
15057                ignore_indent: bool,
15058            ) -> Range<Point> {
15059                let indent_size = if ignore_indent {
15060                    0
15061                } else {
15062                    snapshot.indent_size_for_line(row).len
15063                };
15064
15065                let start = Point::new(row.0, indent_size);
15066
15067                let mut line_bytes = snapshot
15068                    .bytes_in_range(start..snapshot.max_point())
15069                    .flatten()
15070                    .copied();
15071
15072                // If this line currently begins with the line comment prefix, then record
15073                // the range containing the prefix.
15074                if line_bytes
15075                    .by_ref()
15076                    .take(comment_prefix.len())
15077                    .eq(comment_prefix.bytes())
15078                {
15079                    // Include any whitespace that matches the comment prefix.
15080                    let matching_whitespace_len = line_bytes
15081                        .zip(comment_prefix_whitespace.bytes())
15082                        .take_while(|(a, b)| a == b)
15083                        .count() as u32;
15084                    let end = Point::new(
15085                        start.row,
15086                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15087                    );
15088                    start..end
15089                } else {
15090                    start..start
15091                }
15092            }
15093
15094            fn comment_suffix_range(
15095                snapshot: &MultiBufferSnapshot,
15096                row: MultiBufferRow,
15097                comment_suffix: &str,
15098                comment_suffix_has_leading_space: bool,
15099            ) -> Range<Point> {
15100                let end = Point::new(row.0, snapshot.line_len(row));
15101                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15102
15103                let mut line_end_bytes = snapshot
15104                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15105                    .flatten()
15106                    .copied();
15107
15108                let leading_space_len = if suffix_start_column > 0
15109                    && line_end_bytes.next() == Some(b' ')
15110                    && comment_suffix_has_leading_space
15111                {
15112                    1
15113                } else {
15114                    0
15115                };
15116
15117                // If this line currently begins with the line comment prefix, then record
15118                // the range containing the prefix.
15119                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15120                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15121                    start..end
15122                } else {
15123                    end..end
15124                }
15125            }
15126
15127            // TODO: Handle selections that cross excerpts
15128            for selection in &mut selections {
15129                let start_column = snapshot
15130                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15131                    .len;
15132                let language = if let Some(language) =
15133                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15134                {
15135                    language
15136                } else {
15137                    continue;
15138                };
15139
15140                selection_edit_ranges.clear();
15141
15142                // If multiple selections contain a given row, avoid processing that
15143                // row more than once.
15144                let mut start_row = MultiBufferRow(selection.start.row);
15145                if last_toggled_row == Some(start_row) {
15146                    start_row = start_row.next_row();
15147                }
15148                let end_row =
15149                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15150                        MultiBufferRow(selection.end.row - 1)
15151                    } else {
15152                        MultiBufferRow(selection.end.row)
15153                    };
15154                last_toggled_row = Some(end_row);
15155
15156                if start_row > end_row {
15157                    continue;
15158                }
15159
15160                // If the language has line comments, toggle those.
15161                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15162
15163                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15164                if ignore_indent {
15165                    full_comment_prefixes = full_comment_prefixes
15166                        .into_iter()
15167                        .map(|s| Arc::from(s.trim_end()))
15168                        .collect();
15169                }
15170
15171                if !full_comment_prefixes.is_empty() {
15172                    let first_prefix = full_comment_prefixes
15173                        .first()
15174                        .expect("prefixes is non-empty");
15175                    let prefix_trimmed_lengths = full_comment_prefixes
15176                        .iter()
15177                        .map(|p| p.trim_end_matches(' ').len())
15178                        .collect::<SmallVec<[usize; 4]>>();
15179
15180                    let mut all_selection_lines_are_comments = true;
15181
15182                    for row in start_row.0..=end_row.0 {
15183                        let row = MultiBufferRow(row);
15184                        if start_row < end_row && snapshot.is_line_blank(row) {
15185                            continue;
15186                        }
15187
15188                        let prefix_range = full_comment_prefixes
15189                            .iter()
15190                            .zip(prefix_trimmed_lengths.iter().copied())
15191                            .map(|(prefix, trimmed_prefix_len)| {
15192                                comment_prefix_range(
15193                                    snapshot.deref(),
15194                                    row,
15195                                    &prefix[..trimmed_prefix_len],
15196                                    &prefix[trimmed_prefix_len..],
15197                                    ignore_indent,
15198                                )
15199                            })
15200                            .max_by_key(|range| range.end.column - range.start.column)
15201                            .expect("prefixes is non-empty");
15202
15203                        if prefix_range.is_empty() {
15204                            all_selection_lines_are_comments = false;
15205                        }
15206
15207                        selection_edit_ranges.push(prefix_range);
15208                    }
15209
15210                    if all_selection_lines_are_comments {
15211                        edits.extend(
15212                            selection_edit_ranges
15213                                .iter()
15214                                .cloned()
15215                                .map(|range| (range, empty_str.clone())),
15216                        );
15217                    } else {
15218                        let min_column = selection_edit_ranges
15219                            .iter()
15220                            .map(|range| range.start.column)
15221                            .min()
15222                            .unwrap_or(0);
15223                        edits.extend(selection_edit_ranges.iter().map(|range| {
15224                            let position = Point::new(range.start.row, min_column);
15225                            (position..position, first_prefix.clone())
15226                        }));
15227                    }
15228                } else if let Some(BlockCommentConfig {
15229                    start: full_comment_prefix,
15230                    end: comment_suffix,
15231                    ..
15232                }) = language.block_comment()
15233                {
15234                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15235                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15236                    let prefix_range = comment_prefix_range(
15237                        snapshot.deref(),
15238                        start_row,
15239                        comment_prefix,
15240                        comment_prefix_whitespace,
15241                        ignore_indent,
15242                    );
15243                    let suffix_range = comment_suffix_range(
15244                        snapshot.deref(),
15245                        end_row,
15246                        comment_suffix.trim_start_matches(' '),
15247                        comment_suffix.starts_with(' '),
15248                    );
15249
15250                    if prefix_range.is_empty() || suffix_range.is_empty() {
15251                        edits.push((
15252                            prefix_range.start..prefix_range.start,
15253                            full_comment_prefix.clone(),
15254                        ));
15255                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15256                        suffixes_inserted.push((end_row, comment_suffix.len()));
15257                    } else {
15258                        edits.push((prefix_range, empty_str.clone()));
15259                        edits.push((suffix_range, empty_str.clone()));
15260                    }
15261                } else {
15262                    continue;
15263                }
15264            }
15265
15266            drop(snapshot);
15267            this.buffer.update(cx, |buffer, cx| {
15268                buffer.edit(edits, None, cx);
15269            });
15270
15271            // Adjust selections so that they end before any comment suffixes that
15272            // were inserted.
15273            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15274            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15275            let snapshot = this.buffer.read(cx).read(cx);
15276            for selection in &mut selections {
15277                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15278                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15279                        Ordering::Less => {
15280                            suffixes_inserted.next();
15281                            continue;
15282                        }
15283                        Ordering::Greater => break,
15284                        Ordering::Equal => {
15285                            if selection.end.column == snapshot.line_len(row) {
15286                                if selection.is_empty() {
15287                                    selection.start.column -= suffix_len as u32;
15288                                }
15289                                selection.end.column -= suffix_len as u32;
15290                            }
15291                            break;
15292                        }
15293                    }
15294                }
15295            }
15296
15297            drop(snapshot);
15298            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15299
15300            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15301            let selections_on_single_row = selections.windows(2).all(|selections| {
15302                selections[0].start.row == selections[1].start.row
15303                    && selections[0].end.row == selections[1].end.row
15304                    && selections[0].start.row == selections[0].end.row
15305            });
15306            let selections_selecting = selections
15307                .iter()
15308                .any(|selection| selection.start != selection.end);
15309            let advance_downwards = action.advance_downwards
15310                && selections_on_single_row
15311                && !selections_selecting
15312                && !matches!(this.mode, EditorMode::SingleLine);
15313
15314            if advance_downwards {
15315                let snapshot = this.buffer.read(cx).snapshot(cx);
15316
15317                this.change_selections(Default::default(), window, cx, |s| {
15318                    s.move_cursors_with(|display_snapshot, display_point, _| {
15319                        let mut point = display_point.to_point(display_snapshot);
15320                        point.row += 1;
15321                        point = snapshot.clip_point(point, Bias::Left);
15322                        let display_point = point.to_display_point(display_snapshot);
15323                        let goal = SelectionGoal::HorizontalPosition(
15324                            display_snapshot
15325                                .x_for_display_point(display_point, text_layout_details)
15326                                .into(),
15327                        );
15328                        (display_point, goal)
15329                    })
15330                });
15331            }
15332        });
15333    }
15334
15335    pub fn select_enclosing_symbol(
15336        &mut self,
15337        _: &SelectEnclosingSymbol,
15338        window: &mut Window,
15339        cx: &mut Context<Self>,
15340    ) {
15341        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15342
15343        let buffer = self.buffer.read(cx).snapshot(cx);
15344        let old_selections = self
15345            .selections
15346            .all::<usize>(&self.display_snapshot(cx))
15347            .into_boxed_slice();
15348
15349        fn update_selection(
15350            selection: &Selection<usize>,
15351            buffer_snap: &MultiBufferSnapshot,
15352        ) -> Option<Selection<usize>> {
15353            let cursor = selection.head();
15354            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15355            for symbol in symbols.iter().rev() {
15356                let start = symbol.range.start.to_offset(buffer_snap);
15357                let end = symbol.range.end.to_offset(buffer_snap);
15358                let new_range = start..end;
15359                if start < selection.start || end > selection.end {
15360                    return Some(Selection {
15361                        id: selection.id,
15362                        start: new_range.start,
15363                        end: new_range.end,
15364                        goal: SelectionGoal::None,
15365                        reversed: selection.reversed,
15366                    });
15367                }
15368            }
15369            None
15370        }
15371
15372        let mut selected_larger_symbol = false;
15373        let new_selections = old_selections
15374            .iter()
15375            .map(|selection| match update_selection(selection, &buffer) {
15376                Some(new_selection) => {
15377                    if new_selection.range() != selection.range() {
15378                        selected_larger_symbol = true;
15379                    }
15380                    new_selection
15381                }
15382                None => selection.clone(),
15383            })
15384            .collect::<Vec<_>>();
15385
15386        if selected_larger_symbol {
15387            self.change_selections(Default::default(), window, cx, |s| {
15388                s.select(new_selections);
15389            });
15390        }
15391    }
15392
15393    pub fn select_larger_syntax_node(
15394        &mut self,
15395        _: &SelectLargerSyntaxNode,
15396        window: &mut Window,
15397        cx: &mut Context<Self>,
15398    ) {
15399        let Some(visible_row_count) = self.visible_row_count() else {
15400            return;
15401        };
15402        let old_selections: Box<[_]> = self
15403            .selections
15404            .all::<usize>(&self.display_snapshot(cx))
15405            .into();
15406        if old_selections.is_empty() {
15407            return;
15408        }
15409
15410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15411
15412        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15413        let buffer = self.buffer.read(cx).snapshot(cx);
15414
15415        let mut selected_larger_node = false;
15416        let mut new_selections = old_selections
15417            .iter()
15418            .map(|selection| {
15419                let old_range = selection.start..selection.end;
15420
15421                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15422                    // manually select word at selection
15423                    if ["string_content", "inline"].contains(&node.kind()) {
15424                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15425                        // ignore if word is already selected
15426                        if !word_range.is_empty() && old_range != word_range {
15427                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15428                            // only select word if start and end point belongs to same word
15429                            if word_range == last_word_range {
15430                                selected_larger_node = true;
15431                                return Selection {
15432                                    id: selection.id,
15433                                    start: word_range.start,
15434                                    end: word_range.end,
15435                                    goal: SelectionGoal::None,
15436                                    reversed: selection.reversed,
15437                                };
15438                            }
15439                        }
15440                    }
15441                }
15442
15443                let mut new_range = old_range.clone();
15444                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15445                    new_range = range;
15446                    if !node.is_named() {
15447                        continue;
15448                    }
15449                    if !display_map.intersects_fold(new_range.start)
15450                        && !display_map.intersects_fold(new_range.end)
15451                    {
15452                        break;
15453                    }
15454                }
15455
15456                selected_larger_node |= new_range != old_range;
15457                Selection {
15458                    id: selection.id,
15459                    start: new_range.start,
15460                    end: new_range.end,
15461                    goal: SelectionGoal::None,
15462                    reversed: selection.reversed,
15463                }
15464            })
15465            .collect::<Vec<_>>();
15466
15467        if !selected_larger_node {
15468            return; // don't put this call in the history
15469        }
15470
15471        // scroll based on transformation done to the last selection created by the user
15472        let (last_old, last_new) = old_selections
15473            .last()
15474            .zip(new_selections.last().cloned())
15475            .expect("old_selections isn't empty");
15476
15477        // revert selection
15478        let is_selection_reversed = {
15479            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15480            new_selections.last_mut().expect("checked above").reversed =
15481                should_newest_selection_be_reversed;
15482            should_newest_selection_be_reversed
15483        };
15484
15485        if selected_larger_node {
15486            self.select_syntax_node_history.disable_clearing = true;
15487            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15488                s.select(new_selections.clone());
15489            });
15490            self.select_syntax_node_history.disable_clearing = false;
15491        }
15492
15493        let start_row = last_new.start.to_display_point(&display_map).row().0;
15494        let end_row = last_new.end.to_display_point(&display_map).row().0;
15495        let selection_height = end_row - start_row + 1;
15496        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15497
15498        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15499        let scroll_behavior = if fits_on_the_screen {
15500            self.request_autoscroll(Autoscroll::fit(), cx);
15501            SelectSyntaxNodeScrollBehavior::FitSelection
15502        } else if is_selection_reversed {
15503            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15504            SelectSyntaxNodeScrollBehavior::CursorTop
15505        } else {
15506            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15507            SelectSyntaxNodeScrollBehavior::CursorBottom
15508        };
15509
15510        self.select_syntax_node_history.push((
15511            old_selections,
15512            scroll_behavior,
15513            is_selection_reversed,
15514        ));
15515    }
15516
15517    pub fn select_smaller_syntax_node(
15518        &mut self,
15519        _: &SelectSmallerSyntaxNode,
15520        window: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) {
15523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15524
15525        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15526            self.select_syntax_node_history.pop()
15527        {
15528            if let Some(selection) = selections.last_mut() {
15529                selection.reversed = is_selection_reversed;
15530            }
15531
15532            self.select_syntax_node_history.disable_clearing = true;
15533            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15534                s.select(selections.to_vec());
15535            });
15536            self.select_syntax_node_history.disable_clearing = false;
15537
15538            match scroll_behavior {
15539                SelectSyntaxNodeScrollBehavior::CursorTop => {
15540                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15541                }
15542                SelectSyntaxNodeScrollBehavior::FitSelection => {
15543                    self.request_autoscroll(Autoscroll::fit(), cx);
15544                }
15545                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15546                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15547                }
15548            }
15549        }
15550    }
15551
15552    pub fn unwrap_syntax_node(
15553        &mut self,
15554        _: &UnwrapSyntaxNode,
15555        window: &mut Window,
15556        cx: &mut Context<Self>,
15557    ) {
15558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15559
15560        let buffer = self.buffer.read(cx).snapshot(cx);
15561        let selections = self
15562            .selections
15563            .all::<usize>(&self.display_snapshot(cx))
15564            .into_iter()
15565            // subtracting the offset requires sorting
15566            .sorted_by_key(|i| i.start);
15567
15568        let full_edits = selections
15569            .into_iter()
15570            .filter_map(|selection| {
15571                let child = if selection.is_empty()
15572                    && let Some((_, ancestor_range)) =
15573                        buffer.syntax_ancestor(selection.start..selection.end)
15574                {
15575                    ancestor_range
15576                } else {
15577                    selection.range()
15578                };
15579
15580                let mut parent = child.clone();
15581                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15582                    parent = ancestor_range;
15583                    if parent.start < child.start || parent.end > child.end {
15584                        break;
15585                    }
15586                }
15587
15588                if parent == child {
15589                    return None;
15590                }
15591                let text = buffer.text_for_range(child).collect::<String>();
15592                Some((selection.id, parent, text))
15593            })
15594            .collect::<Vec<_>>();
15595        if full_edits.is_empty() {
15596            return;
15597        }
15598
15599        self.transact(window, cx, |this, window, cx| {
15600            this.buffer.update(cx, |buffer, cx| {
15601                buffer.edit(
15602                    full_edits
15603                        .iter()
15604                        .map(|(_, p, t)| (p.clone(), t.clone()))
15605                        .collect::<Vec<_>>(),
15606                    None,
15607                    cx,
15608                );
15609            });
15610            this.change_selections(Default::default(), window, cx, |s| {
15611                let mut offset = 0;
15612                let mut selections = vec![];
15613                for (id, parent, text) in full_edits {
15614                    let start = parent.start - offset;
15615                    offset += parent.len() - text.len();
15616                    selections.push(Selection {
15617                        id,
15618                        start,
15619                        end: start + text.len(),
15620                        reversed: false,
15621                        goal: Default::default(),
15622                    });
15623                }
15624                s.select(selections);
15625            });
15626        });
15627    }
15628
15629    pub fn select_next_syntax_node(
15630        &mut self,
15631        _: &SelectNextSyntaxNode,
15632        window: &mut Window,
15633        cx: &mut Context<Self>,
15634    ) {
15635        let old_selections: Box<[_]> = self
15636            .selections
15637            .all::<usize>(&self.display_snapshot(cx))
15638            .into();
15639        if old_selections.is_empty() {
15640            return;
15641        }
15642
15643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15644
15645        let buffer = self.buffer.read(cx).snapshot(cx);
15646        let mut selected_sibling = false;
15647
15648        let new_selections = old_selections
15649            .iter()
15650            .map(|selection| {
15651                let old_range = selection.start..selection.end;
15652
15653                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15654                    let new_range = node.byte_range();
15655                    selected_sibling = true;
15656                    Selection {
15657                        id: selection.id,
15658                        start: new_range.start,
15659                        end: new_range.end,
15660                        goal: SelectionGoal::None,
15661                        reversed: selection.reversed,
15662                    }
15663                } else {
15664                    selection.clone()
15665                }
15666            })
15667            .collect::<Vec<_>>();
15668
15669        if selected_sibling {
15670            self.change_selections(
15671                SelectionEffects::scroll(Autoscroll::fit()),
15672                window,
15673                cx,
15674                |s| {
15675                    s.select(new_selections);
15676                },
15677            );
15678        }
15679    }
15680
15681    pub fn select_prev_syntax_node(
15682        &mut self,
15683        _: &SelectPreviousSyntaxNode,
15684        window: &mut Window,
15685        cx: &mut Context<Self>,
15686    ) {
15687        let old_selections: Box<[_]> = self
15688            .selections
15689            .all::<usize>(&self.display_snapshot(cx))
15690            .into();
15691        if old_selections.is_empty() {
15692            return;
15693        }
15694
15695        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15696
15697        let buffer = self.buffer.read(cx).snapshot(cx);
15698        let mut selected_sibling = false;
15699
15700        let new_selections = old_selections
15701            .iter()
15702            .map(|selection| {
15703                let old_range = selection.start..selection.end;
15704
15705                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15706                    let new_range = node.byte_range();
15707                    selected_sibling = true;
15708                    Selection {
15709                        id: selection.id,
15710                        start: new_range.start,
15711                        end: new_range.end,
15712                        goal: SelectionGoal::None,
15713                        reversed: selection.reversed,
15714                    }
15715                } else {
15716                    selection.clone()
15717                }
15718            })
15719            .collect::<Vec<_>>();
15720
15721        if selected_sibling {
15722            self.change_selections(
15723                SelectionEffects::scroll(Autoscroll::fit()),
15724                window,
15725                cx,
15726                |s| {
15727                    s.select(new_selections);
15728                },
15729            );
15730        }
15731    }
15732
15733    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15734        if !EditorSettings::get_global(cx).gutter.runnables {
15735            self.clear_tasks();
15736            return Task::ready(());
15737        }
15738        let project = self.project().map(Entity::downgrade);
15739        let task_sources = self.lsp_task_sources(cx);
15740        let multi_buffer = self.buffer.downgrade();
15741        cx.spawn_in(window, async move |editor, cx| {
15742            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15743            let Some(project) = project.and_then(|p| p.upgrade()) else {
15744                return;
15745            };
15746            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15747                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15748            }) else {
15749                return;
15750            };
15751
15752            let hide_runnables = project
15753                .update(cx, |project, _| project.is_via_collab())
15754                .unwrap_or(true);
15755            if hide_runnables {
15756                return;
15757            }
15758            let new_rows =
15759                cx.background_spawn({
15760                    let snapshot = display_snapshot.clone();
15761                    async move {
15762                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15763                    }
15764                })
15765                    .await;
15766            let Ok(lsp_tasks) =
15767                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15768            else {
15769                return;
15770            };
15771            let lsp_tasks = lsp_tasks.await;
15772
15773            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15774                lsp_tasks
15775                    .into_iter()
15776                    .flat_map(|(kind, tasks)| {
15777                        tasks.into_iter().filter_map(move |(location, task)| {
15778                            Some((kind.clone(), location?, task))
15779                        })
15780                    })
15781                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15782                        let buffer = location.target.buffer;
15783                        let buffer_snapshot = buffer.read(cx).snapshot();
15784                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15785                            |(excerpt_id, snapshot, _)| {
15786                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15787                                    display_snapshot
15788                                        .buffer_snapshot()
15789                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15790                                } else {
15791                                    None
15792                                }
15793                            },
15794                        );
15795                        if let Some(offset) = offset {
15796                            let task_buffer_range =
15797                                location.target.range.to_point(&buffer_snapshot);
15798                            let context_buffer_range =
15799                                task_buffer_range.to_offset(&buffer_snapshot);
15800                            let context_range = BufferOffset(context_buffer_range.start)
15801                                ..BufferOffset(context_buffer_range.end);
15802
15803                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15804                                .or_insert_with(|| RunnableTasks {
15805                                    templates: Vec::new(),
15806                                    offset,
15807                                    column: task_buffer_range.start.column,
15808                                    extra_variables: HashMap::default(),
15809                                    context_range,
15810                                })
15811                                .templates
15812                                .push((kind, task.original_task().clone()));
15813                        }
15814
15815                        acc
15816                    })
15817            }) else {
15818                return;
15819            };
15820
15821            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15822                buffer.language_settings(cx).tasks.prefer_lsp
15823            }) else {
15824                return;
15825            };
15826
15827            let rows = Self::runnable_rows(
15828                project,
15829                display_snapshot,
15830                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15831                new_rows,
15832                cx.clone(),
15833            )
15834            .await;
15835            editor
15836                .update(cx, |editor, _| {
15837                    editor.clear_tasks();
15838                    for (key, mut value) in rows {
15839                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15840                            value.templates.extend(lsp_tasks.templates);
15841                        }
15842
15843                        editor.insert_tasks(key, value);
15844                    }
15845                    for (key, value) in lsp_tasks_by_rows {
15846                        editor.insert_tasks(key, value);
15847                    }
15848                })
15849                .ok();
15850        })
15851    }
15852    fn fetch_runnable_ranges(
15853        snapshot: &DisplaySnapshot,
15854        range: Range<Anchor>,
15855    ) -> Vec<language::RunnableRange> {
15856        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15857    }
15858
15859    fn runnable_rows(
15860        project: Entity<Project>,
15861        snapshot: DisplaySnapshot,
15862        prefer_lsp: bool,
15863        runnable_ranges: Vec<RunnableRange>,
15864        cx: AsyncWindowContext,
15865    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15866        cx.spawn(async move |cx| {
15867            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15868            for mut runnable in runnable_ranges {
15869                let Some(tasks) = cx
15870                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15871                    .ok()
15872                else {
15873                    continue;
15874                };
15875                let mut tasks = tasks.await;
15876
15877                if prefer_lsp {
15878                    tasks.retain(|(task_kind, _)| {
15879                        !matches!(task_kind, TaskSourceKind::Language { .. })
15880                    });
15881                }
15882                if tasks.is_empty() {
15883                    continue;
15884                }
15885
15886                let point = runnable
15887                    .run_range
15888                    .start
15889                    .to_point(&snapshot.buffer_snapshot());
15890                let Some(row) = snapshot
15891                    .buffer_snapshot()
15892                    .buffer_line_for_row(MultiBufferRow(point.row))
15893                    .map(|(_, range)| range.start.row)
15894                else {
15895                    continue;
15896                };
15897
15898                let context_range =
15899                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15900                runnable_rows.push((
15901                    (runnable.buffer_id, row),
15902                    RunnableTasks {
15903                        templates: tasks,
15904                        offset: snapshot
15905                            .buffer_snapshot()
15906                            .anchor_before(runnable.run_range.start),
15907                        context_range,
15908                        column: point.column,
15909                        extra_variables: runnable.extra_captures,
15910                    },
15911                ));
15912            }
15913            runnable_rows
15914        })
15915    }
15916
15917    fn templates_with_tags(
15918        project: &Entity<Project>,
15919        runnable: &mut Runnable,
15920        cx: &mut App,
15921    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15922        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15923            let (worktree_id, file) = project
15924                .buffer_for_id(runnable.buffer, cx)
15925                .and_then(|buffer| buffer.read(cx).file())
15926                .map(|file| (file.worktree_id(cx), file.clone()))
15927                .unzip();
15928
15929            (
15930                project.task_store().read(cx).task_inventory().cloned(),
15931                worktree_id,
15932                file,
15933            )
15934        });
15935
15936        let tags = mem::take(&mut runnable.tags);
15937        let language = runnable.language.clone();
15938        cx.spawn(async move |cx| {
15939            let mut templates_with_tags = Vec::new();
15940            if let Some(inventory) = inventory {
15941                for RunnableTag(tag) in tags {
15942                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15943                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15944                    }) else {
15945                        return templates_with_tags;
15946                    };
15947                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15948                        move |(_, template)| {
15949                            template.tags.iter().any(|source_tag| source_tag == &tag)
15950                        },
15951                    ));
15952                }
15953            }
15954            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15955
15956            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15957                // Strongest source wins; if we have worktree tag binding, prefer that to
15958                // global and language bindings;
15959                // if we have a global binding, prefer that to language binding.
15960                let first_mismatch = templates_with_tags
15961                    .iter()
15962                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15963                if let Some(index) = first_mismatch {
15964                    templates_with_tags.truncate(index);
15965                }
15966            }
15967
15968            templates_with_tags
15969        })
15970    }
15971
15972    pub fn move_to_enclosing_bracket(
15973        &mut self,
15974        _: &MoveToEnclosingBracket,
15975        window: &mut Window,
15976        cx: &mut Context<Self>,
15977    ) {
15978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15979        self.change_selections(Default::default(), window, cx, |s| {
15980            s.move_offsets_with(|snapshot, selection| {
15981                let Some(enclosing_bracket_ranges) =
15982                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15983                else {
15984                    return;
15985                };
15986
15987                let mut best_length = usize::MAX;
15988                let mut best_inside = false;
15989                let mut best_in_bracket_range = false;
15990                let mut best_destination = None;
15991                for (open, close) in enclosing_bracket_ranges {
15992                    let close = close.to_inclusive();
15993                    let length = close.end() - open.start;
15994                    let inside = selection.start >= open.end && selection.end <= *close.start();
15995                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15996                        || close.contains(&selection.head());
15997
15998                    // If best is next to a bracket and current isn't, skip
15999                    if !in_bracket_range && best_in_bracket_range {
16000                        continue;
16001                    }
16002
16003                    // Prefer smaller lengths unless best is inside and current isn't
16004                    if length > best_length && (best_inside || !inside) {
16005                        continue;
16006                    }
16007
16008                    best_length = length;
16009                    best_inside = inside;
16010                    best_in_bracket_range = in_bracket_range;
16011                    best_destination = Some(
16012                        if close.contains(&selection.start) && close.contains(&selection.end) {
16013                            if inside { open.end } else { open.start }
16014                        } else if inside {
16015                            *close.start()
16016                        } else {
16017                            *close.end()
16018                        },
16019                    );
16020                }
16021
16022                if let Some(destination) = best_destination {
16023                    selection.collapse_to(destination, SelectionGoal::None);
16024                }
16025            })
16026        });
16027    }
16028
16029    pub fn undo_selection(
16030        &mut self,
16031        _: &UndoSelection,
16032        window: &mut Window,
16033        cx: &mut Context<Self>,
16034    ) {
16035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16036        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16037            self.selection_history.mode = SelectionHistoryMode::Undoing;
16038            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16039                this.end_selection(window, cx);
16040                this.change_selections(
16041                    SelectionEffects::scroll(Autoscroll::newest()),
16042                    window,
16043                    cx,
16044                    |s| s.select_anchors(entry.selections.to_vec()),
16045                );
16046            });
16047            self.selection_history.mode = SelectionHistoryMode::Normal;
16048
16049            self.select_next_state = entry.select_next_state;
16050            self.select_prev_state = entry.select_prev_state;
16051            self.add_selections_state = entry.add_selections_state;
16052        }
16053    }
16054
16055    pub fn redo_selection(
16056        &mut self,
16057        _: &RedoSelection,
16058        window: &mut Window,
16059        cx: &mut Context<Self>,
16060    ) {
16061        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16062        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16063            self.selection_history.mode = SelectionHistoryMode::Redoing;
16064            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16065                this.end_selection(window, cx);
16066                this.change_selections(
16067                    SelectionEffects::scroll(Autoscroll::newest()),
16068                    window,
16069                    cx,
16070                    |s| s.select_anchors(entry.selections.to_vec()),
16071                );
16072            });
16073            self.selection_history.mode = SelectionHistoryMode::Normal;
16074
16075            self.select_next_state = entry.select_next_state;
16076            self.select_prev_state = entry.select_prev_state;
16077            self.add_selections_state = entry.add_selections_state;
16078        }
16079    }
16080
16081    pub fn expand_excerpts(
16082        &mut self,
16083        action: &ExpandExcerpts,
16084        _: &mut Window,
16085        cx: &mut Context<Self>,
16086    ) {
16087        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16088    }
16089
16090    pub fn expand_excerpts_down(
16091        &mut self,
16092        action: &ExpandExcerptsDown,
16093        _: &mut Window,
16094        cx: &mut Context<Self>,
16095    ) {
16096        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16097    }
16098
16099    pub fn expand_excerpts_up(
16100        &mut self,
16101        action: &ExpandExcerptsUp,
16102        _: &mut Window,
16103        cx: &mut Context<Self>,
16104    ) {
16105        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16106    }
16107
16108    pub fn expand_excerpts_for_direction(
16109        &mut self,
16110        lines: u32,
16111        direction: ExpandExcerptDirection,
16112
16113        cx: &mut Context<Self>,
16114    ) {
16115        let selections = self.selections.disjoint_anchors_arc();
16116
16117        let lines = if lines == 0 {
16118            EditorSettings::get_global(cx).expand_excerpt_lines
16119        } else {
16120            lines
16121        };
16122
16123        self.buffer.update(cx, |buffer, cx| {
16124            let snapshot = buffer.snapshot(cx);
16125            let mut excerpt_ids = selections
16126                .iter()
16127                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16128                .collect::<Vec<_>>();
16129            excerpt_ids.sort();
16130            excerpt_ids.dedup();
16131            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16132        })
16133    }
16134
16135    pub fn expand_excerpt(
16136        &mut self,
16137        excerpt: ExcerptId,
16138        direction: ExpandExcerptDirection,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        let current_scroll_position = self.scroll_position(cx);
16143        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16144        let mut scroll = None;
16145
16146        if direction == ExpandExcerptDirection::Down {
16147            let multi_buffer = self.buffer.read(cx);
16148            let snapshot = multi_buffer.snapshot(cx);
16149            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16150                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16151                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16152            {
16153                let buffer_snapshot = buffer.read(cx).snapshot();
16154                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16155                let last_row = buffer_snapshot.max_point().row;
16156                let lines_below = last_row.saturating_sub(excerpt_end_row);
16157                if lines_below >= lines_to_expand {
16158                    scroll = Some(
16159                        current_scroll_position
16160                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16161                    );
16162                }
16163            }
16164        }
16165        if direction == ExpandExcerptDirection::Up
16166            && self
16167                .buffer
16168                .read(cx)
16169                .snapshot(cx)
16170                .excerpt_before(excerpt)
16171                .is_none()
16172        {
16173            scroll = Some(current_scroll_position);
16174        }
16175
16176        self.buffer.update(cx, |buffer, cx| {
16177            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16178        });
16179
16180        if let Some(new_scroll_position) = scroll {
16181            self.set_scroll_position(new_scroll_position, window, cx);
16182        }
16183    }
16184
16185    pub fn go_to_singleton_buffer_point(
16186        &mut self,
16187        point: Point,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        self.go_to_singleton_buffer_range(point..point, window, cx);
16192    }
16193
16194    pub fn go_to_singleton_buffer_range(
16195        &mut self,
16196        range: Range<Point>,
16197        window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) {
16200        let multibuffer = self.buffer().read(cx);
16201        let Some(buffer) = multibuffer.as_singleton() else {
16202            return;
16203        };
16204        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16205            return;
16206        };
16207        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16208            return;
16209        };
16210        self.change_selections(
16211            SelectionEffects::default().nav_history(true),
16212            window,
16213            cx,
16214            |s| s.select_anchor_ranges([start..end]),
16215        );
16216    }
16217
16218    pub fn go_to_diagnostic(
16219        &mut self,
16220        action: &GoToDiagnostic,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) {
16224        if !self.diagnostics_enabled() {
16225            return;
16226        }
16227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16228        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16229    }
16230
16231    pub fn go_to_prev_diagnostic(
16232        &mut self,
16233        action: &GoToPreviousDiagnostic,
16234        window: &mut Window,
16235        cx: &mut Context<Self>,
16236    ) {
16237        if !self.diagnostics_enabled() {
16238            return;
16239        }
16240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16241        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16242    }
16243
16244    pub fn go_to_diagnostic_impl(
16245        &mut self,
16246        direction: Direction,
16247        severity: GoToDiagnosticSeverityFilter,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) {
16251        let buffer = self.buffer.read(cx).snapshot(cx);
16252        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16253
16254        let mut active_group_id = None;
16255        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16256            && active_group.active_range.start.to_offset(&buffer) == selection.start
16257        {
16258            active_group_id = Some(active_group.group_id);
16259        }
16260
16261        fn filtered<'a>(
16262            severity: GoToDiagnosticSeverityFilter,
16263            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16264        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16265            diagnostics
16266                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16267                .filter(|entry| entry.range.start != entry.range.end)
16268                .filter(|entry| !entry.diagnostic.is_unnecessary)
16269        }
16270
16271        let before = filtered(
16272            severity,
16273            buffer
16274                .diagnostics_in_range(0..selection.start)
16275                .filter(|entry| entry.range.start <= selection.start),
16276        );
16277        let after = filtered(
16278            severity,
16279            buffer
16280                .diagnostics_in_range(selection.start..buffer.len())
16281                .filter(|entry| entry.range.start >= selection.start),
16282        );
16283
16284        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16285        if direction == Direction::Prev {
16286            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16287            {
16288                for diagnostic in prev_diagnostics.into_iter().rev() {
16289                    if diagnostic.range.start != selection.start
16290                        || active_group_id
16291                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16292                    {
16293                        found = Some(diagnostic);
16294                        break 'outer;
16295                    }
16296                }
16297            }
16298        } else {
16299            for diagnostic in after.chain(before) {
16300                if diagnostic.range.start != selection.start
16301                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16302                {
16303                    found = Some(diagnostic);
16304                    break;
16305                }
16306            }
16307        }
16308        let Some(next_diagnostic) = found else {
16309            return;
16310        };
16311
16312        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16313        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16314            return;
16315        };
16316        let snapshot = self.snapshot(window, cx);
16317        if snapshot.intersects_fold(next_diagnostic.range.start) {
16318            self.unfold_ranges(
16319                std::slice::from_ref(&next_diagnostic.range),
16320                true,
16321                false,
16322                cx,
16323            );
16324        }
16325        self.change_selections(Default::default(), window, cx, |s| {
16326            s.select_ranges(vec![
16327                next_diagnostic.range.start..next_diagnostic.range.start,
16328            ])
16329        });
16330        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16331        self.refresh_edit_prediction(false, true, window, cx);
16332    }
16333
16334    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16336        let snapshot = self.snapshot(window, cx);
16337        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16338        self.go_to_hunk_before_or_after_position(
16339            &snapshot,
16340            selection.head(),
16341            Direction::Next,
16342            window,
16343            cx,
16344        );
16345    }
16346
16347    pub fn go_to_hunk_before_or_after_position(
16348        &mut self,
16349        snapshot: &EditorSnapshot,
16350        position: Point,
16351        direction: Direction,
16352        window: &mut Window,
16353        cx: &mut Context<Editor>,
16354    ) {
16355        let row = if direction == Direction::Next {
16356            self.hunk_after_position(snapshot, position)
16357                .map(|hunk| hunk.row_range.start)
16358        } else {
16359            self.hunk_before_position(snapshot, position)
16360        };
16361
16362        if let Some(row) = row {
16363            let destination = Point::new(row.0, 0);
16364            let autoscroll = Autoscroll::center();
16365
16366            self.unfold_ranges(&[destination..destination], false, false, cx);
16367            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16368                s.select_ranges([destination..destination]);
16369            });
16370        }
16371    }
16372
16373    fn hunk_after_position(
16374        &mut self,
16375        snapshot: &EditorSnapshot,
16376        position: Point,
16377    ) -> Option<MultiBufferDiffHunk> {
16378        snapshot
16379            .buffer_snapshot()
16380            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16381            .find(|hunk| hunk.row_range.start.0 > position.row)
16382            .or_else(|| {
16383                snapshot
16384                    .buffer_snapshot()
16385                    .diff_hunks_in_range(Point::zero()..position)
16386                    .find(|hunk| hunk.row_range.end.0 < position.row)
16387            })
16388    }
16389
16390    fn go_to_prev_hunk(
16391        &mut self,
16392        _: &GoToPreviousHunk,
16393        window: &mut Window,
16394        cx: &mut Context<Self>,
16395    ) {
16396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16397        let snapshot = self.snapshot(window, cx);
16398        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16399        self.go_to_hunk_before_or_after_position(
16400            &snapshot,
16401            selection.head(),
16402            Direction::Prev,
16403            window,
16404            cx,
16405        );
16406    }
16407
16408    fn hunk_before_position(
16409        &mut self,
16410        snapshot: &EditorSnapshot,
16411        position: Point,
16412    ) -> Option<MultiBufferRow> {
16413        snapshot
16414            .buffer_snapshot()
16415            .diff_hunk_before(position)
16416            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16417    }
16418
16419    fn go_to_next_change(
16420        &mut self,
16421        _: &GoToNextChange,
16422        window: &mut Window,
16423        cx: &mut Context<Self>,
16424    ) {
16425        if let Some(selections) = self
16426            .change_list
16427            .next_change(1, Direction::Next)
16428            .map(|s| s.to_vec())
16429        {
16430            self.change_selections(Default::default(), window, cx, |s| {
16431                let map = s.display_snapshot();
16432                s.select_display_ranges(selections.iter().map(|a| {
16433                    let point = a.to_display_point(&map);
16434                    point..point
16435                }))
16436            })
16437        }
16438    }
16439
16440    fn go_to_previous_change(
16441        &mut self,
16442        _: &GoToPreviousChange,
16443        window: &mut Window,
16444        cx: &mut Context<Self>,
16445    ) {
16446        if let Some(selections) = self
16447            .change_list
16448            .next_change(1, Direction::Prev)
16449            .map(|s| s.to_vec())
16450        {
16451            self.change_selections(Default::default(), window, cx, |s| {
16452                let map = s.display_snapshot();
16453                s.select_display_ranges(selections.iter().map(|a| {
16454                    let point = a.to_display_point(&map);
16455                    point..point
16456                }))
16457            })
16458        }
16459    }
16460
16461    pub fn go_to_next_document_highlight(
16462        &mut self,
16463        _: &GoToNextDocumentHighlight,
16464        window: &mut Window,
16465        cx: &mut Context<Self>,
16466    ) {
16467        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16468    }
16469
16470    pub fn go_to_prev_document_highlight(
16471        &mut self,
16472        _: &GoToPreviousDocumentHighlight,
16473        window: &mut Window,
16474        cx: &mut Context<Self>,
16475    ) {
16476        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16477    }
16478
16479    pub fn go_to_document_highlight_before_or_after_position(
16480        &mut self,
16481        direction: Direction,
16482        window: &mut Window,
16483        cx: &mut Context<Editor>,
16484    ) {
16485        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16486        let snapshot = self.snapshot(window, cx);
16487        let buffer = &snapshot.buffer_snapshot();
16488        let position = self
16489            .selections
16490            .newest::<Point>(&snapshot.display_snapshot)
16491            .head();
16492        let anchor_position = buffer.anchor_after(position);
16493
16494        // Get all document highlights (both read and write)
16495        let mut all_highlights = Vec::new();
16496
16497        if let Some((_, read_highlights)) = self
16498            .background_highlights
16499            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16500        {
16501            all_highlights.extend(read_highlights.iter());
16502        }
16503
16504        if let Some((_, write_highlights)) = self
16505            .background_highlights
16506            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16507        {
16508            all_highlights.extend(write_highlights.iter());
16509        }
16510
16511        if all_highlights.is_empty() {
16512            return;
16513        }
16514
16515        // Sort highlights by position
16516        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16517
16518        let target_highlight = match direction {
16519            Direction::Next => {
16520                // Find the first highlight after the current position
16521                all_highlights
16522                    .iter()
16523                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16524            }
16525            Direction::Prev => {
16526                // Find the last highlight before the current position
16527                all_highlights
16528                    .iter()
16529                    .rev()
16530                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16531            }
16532        };
16533
16534        if let Some(highlight) = target_highlight {
16535            let destination = highlight.start.to_point(buffer);
16536            let autoscroll = Autoscroll::center();
16537
16538            self.unfold_ranges(&[destination..destination], false, false, cx);
16539            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16540                s.select_ranges([destination..destination]);
16541            });
16542        }
16543    }
16544
16545    fn go_to_line<T: 'static>(
16546        &mut self,
16547        position: Anchor,
16548        highlight_color: Option<Hsla>,
16549        window: &mut Window,
16550        cx: &mut Context<Self>,
16551    ) {
16552        let snapshot = self.snapshot(window, cx).display_snapshot;
16553        let position = position.to_point(&snapshot.buffer_snapshot());
16554        let start = snapshot
16555            .buffer_snapshot()
16556            .clip_point(Point::new(position.row, 0), Bias::Left);
16557        let end = start + Point::new(1, 0);
16558        let start = snapshot.buffer_snapshot().anchor_before(start);
16559        let end = snapshot.buffer_snapshot().anchor_before(end);
16560
16561        self.highlight_rows::<T>(
16562            start..end,
16563            highlight_color
16564                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16565            Default::default(),
16566            cx,
16567        );
16568
16569        if self.buffer.read(cx).is_singleton() {
16570            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16571        }
16572    }
16573
16574    pub fn go_to_definition(
16575        &mut self,
16576        _: &GoToDefinition,
16577        window: &mut Window,
16578        cx: &mut Context<Self>,
16579    ) -> Task<Result<Navigated>> {
16580        let definition =
16581            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16582        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16583        cx.spawn_in(window, async move |editor, cx| {
16584            if definition.await? == Navigated::Yes {
16585                return Ok(Navigated::Yes);
16586            }
16587            match fallback_strategy {
16588                GoToDefinitionFallback::None => Ok(Navigated::No),
16589                GoToDefinitionFallback::FindAllReferences => {
16590                    match editor.update_in(cx, |editor, window, cx| {
16591                        editor.find_all_references(&FindAllReferences, window, cx)
16592                    })? {
16593                        Some(references) => references.await,
16594                        None => Ok(Navigated::No),
16595                    }
16596                }
16597            }
16598        })
16599    }
16600
16601    pub fn go_to_declaration(
16602        &mut self,
16603        _: &GoToDeclaration,
16604        window: &mut Window,
16605        cx: &mut Context<Self>,
16606    ) -> Task<Result<Navigated>> {
16607        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16608    }
16609
16610    pub fn go_to_declaration_split(
16611        &mut self,
16612        _: &GoToDeclaration,
16613        window: &mut Window,
16614        cx: &mut Context<Self>,
16615    ) -> Task<Result<Navigated>> {
16616        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16617    }
16618
16619    pub fn go_to_implementation(
16620        &mut self,
16621        _: &GoToImplementation,
16622        window: &mut Window,
16623        cx: &mut Context<Self>,
16624    ) -> Task<Result<Navigated>> {
16625        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16626    }
16627
16628    pub fn go_to_implementation_split(
16629        &mut self,
16630        _: &GoToImplementationSplit,
16631        window: &mut Window,
16632        cx: &mut Context<Self>,
16633    ) -> Task<Result<Navigated>> {
16634        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16635    }
16636
16637    pub fn go_to_type_definition(
16638        &mut self,
16639        _: &GoToTypeDefinition,
16640        window: &mut Window,
16641        cx: &mut Context<Self>,
16642    ) -> Task<Result<Navigated>> {
16643        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16644    }
16645
16646    pub fn go_to_definition_split(
16647        &mut self,
16648        _: &GoToDefinitionSplit,
16649        window: &mut Window,
16650        cx: &mut Context<Self>,
16651    ) -> Task<Result<Navigated>> {
16652        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16653    }
16654
16655    pub fn go_to_type_definition_split(
16656        &mut self,
16657        _: &GoToTypeDefinitionSplit,
16658        window: &mut Window,
16659        cx: &mut Context<Self>,
16660    ) -> Task<Result<Navigated>> {
16661        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16662    }
16663
16664    fn go_to_definition_of_kind(
16665        &mut self,
16666        kind: GotoDefinitionKind,
16667        split: bool,
16668        window: &mut Window,
16669        cx: &mut Context<Self>,
16670    ) -> Task<Result<Navigated>> {
16671        let Some(provider) = self.semantics_provider.clone() else {
16672            return Task::ready(Ok(Navigated::No));
16673        };
16674        let head = self
16675            .selections
16676            .newest::<usize>(&self.display_snapshot(cx))
16677            .head();
16678        let buffer = self.buffer.read(cx);
16679        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16680            return Task::ready(Ok(Navigated::No));
16681        };
16682        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16683            return Task::ready(Ok(Navigated::No));
16684        };
16685
16686        cx.spawn_in(window, async move |editor, cx| {
16687            let Some(definitions) = definitions.await? else {
16688                return Ok(Navigated::No);
16689            };
16690            let navigated = editor
16691                .update_in(cx, |editor, window, cx| {
16692                    editor.navigate_to_hover_links(
16693                        Some(kind),
16694                        definitions
16695                            .into_iter()
16696                            .filter(|location| {
16697                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16698                            })
16699                            .map(HoverLink::Text)
16700                            .collect::<Vec<_>>(),
16701                        split,
16702                        window,
16703                        cx,
16704                    )
16705                })?
16706                .await?;
16707            anyhow::Ok(navigated)
16708        })
16709    }
16710
16711    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16712        let selection = self.selections.newest_anchor();
16713        let head = selection.head();
16714        let tail = selection.tail();
16715
16716        let Some((buffer, start_position)) =
16717            self.buffer.read(cx).text_anchor_for_position(head, cx)
16718        else {
16719            return;
16720        };
16721
16722        let end_position = if head != tail {
16723            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16724                return;
16725            };
16726            Some(pos)
16727        } else {
16728            None
16729        };
16730
16731        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16732            let url = if let Some(end_pos) = end_position {
16733                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16734            } else {
16735                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16736            };
16737
16738            if let Some(url) = url {
16739                cx.update(|window, cx| {
16740                    if parse_zed_link(&url, cx).is_some() {
16741                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16742                    } else {
16743                        cx.open_url(&url);
16744                    }
16745                })?;
16746            }
16747
16748            anyhow::Ok(())
16749        });
16750
16751        url_finder.detach();
16752    }
16753
16754    pub fn open_selected_filename(
16755        &mut self,
16756        _: &OpenSelectedFilename,
16757        window: &mut Window,
16758        cx: &mut Context<Self>,
16759    ) {
16760        let Some(workspace) = self.workspace() else {
16761            return;
16762        };
16763
16764        let position = self.selections.newest_anchor().head();
16765
16766        let Some((buffer, buffer_position)) =
16767            self.buffer.read(cx).text_anchor_for_position(position, cx)
16768        else {
16769            return;
16770        };
16771
16772        let project = self.project.clone();
16773
16774        cx.spawn_in(window, async move |_, cx| {
16775            let result = find_file(&buffer, project, buffer_position, cx).await;
16776
16777            if let Some((_, path)) = result {
16778                workspace
16779                    .update_in(cx, |workspace, window, cx| {
16780                        workspace.open_resolved_path(path, window, cx)
16781                    })?
16782                    .await?;
16783            }
16784            anyhow::Ok(())
16785        })
16786        .detach();
16787    }
16788
16789    pub(crate) fn navigate_to_hover_links(
16790        &mut self,
16791        kind: Option<GotoDefinitionKind>,
16792        definitions: Vec<HoverLink>,
16793        split: bool,
16794        window: &mut Window,
16795        cx: &mut Context<Editor>,
16796    ) -> Task<Result<Navigated>> {
16797        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16798        let mut first_url_or_file = None;
16799        let definitions: Vec<_> = definitions
16800            .into_iter()
16801            .filter_map(|def| match def {
16802                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16803                HoverLink::InlayHint(lsp_location, server_id) => {
16804                    let computation =
16805                        self.compute_target_location(lsp_location, server_id, window, cx);
16806                    Some(cx.background_spawn(computation))
16807                }
16808                HoverLink::Url(url) => {
16809                    first_url_or_file = Some(Either::Left(url));
16810                    None
16811                }
16812                HoverLink::File(path) => {
16813                    first_url_or_file = Some(Either::Right(path));
16814                    None
16815                }
16816            })
16817            .collect();
16818
16819        let workspace = self.workspace();
16820
16821        cx.spawn_in(window, async move |editor, cx| {
16822            let locations: Vec<Location> = future::join_all(definitions)
16823                .await
16824                .into_iter()
16825                .filter_map(|location| location.transpose())
16826                .collect::<Result<_>>()
16827                .context("location tasks")?;
16828            let mut locations = cx.update(|_, cx| {
16829                locations
16830                    .into_iter()
16831                    .map(|location| {
16832                        let buffer = location.buffer.read(cx);
16833                        (location.buffer, location.range.to_point(buffer))
16834                    })
16835                    .into_group_map()
16836            })?;
16837            let mut num_locations = 0;
16838            for ranges in locations.values_mut() {
16839                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16840                ranges.dedup();
16841                num_locations += ranges.len();
16842            }
16843
16844            if num_locations > 1 {
16845                let Some(workspace) = workspace else {
16846                    return Ok(Navigated::No);
16847                };
16848
16849                let tab_kind = match kind {
16850                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16851                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16852                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16853                    Some(GotoDefinitionKind::Type) => "Types",
16854                };
16855                let title = editor
16856                    .update_in(cx, |_, _, cx| {
16857                        let target = locations
16858                            .iter()
16859                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16860                            .map(|(buffer, location)| {
16861                                buffer
16862                                    .read(cx)
16863                                    .text_for_range(location.clone())
16864                                    .collect::<String>()
16865                            })
16866                            .filter(|text| !text.contains('\n'))
16867                            .unique()
16868                            .take(3)
16869                            .join(", ");
16870                        if target.is_empty() {
16871                            tab_kind.to_owned()
16872                        } else {
16873                            format!("{tab_kind} for {target}")
16874                        }
16875                    })
16876                    .context("buffer title")?;
16877
16878                let opened = workspace
16879                    .update_in(cx, |workspace, window, cx| {
16880                        Self::open_locations_in_multibuffer(
16881                            workspace,
16882                            locations,
16883                            title,
16884                            split,
16885                            MultibufferSelectionMode::First,
16886                            window,
16887                            cx,
16888                        )
16889                    })
16890                    .is_ok();
16891
16892                anyhow::Ok(Navigated::from_bool(opened))
16893            } else if num_locations == 0 {
16894                // If there is one url or file, open it directly
16895                match first_url_or_file {
16896                    Some(Either::Left(url)) => {
16897                        cx.update(|_, cx| cx.open_url(&url))?;
16898                        Ok(Navigated::Yes)
16899                    }
16900                    Some(Either::Right(path)) => {
16901                        let Some(workspace) = workspace else {
16902                            return Ok(Navigated::No);
16903                        };
16904
16905                        workspace
16906                            .update_in(cx, |workspace, window, cx| {
16907                                workspace.open_resolved_path(path, window, cx)
16908                            })?
16909                            .await?;
16910                        Ok(Navigated::Yes)
16911                    }
16912                    None => Ok(Navigated::No),
16913                }
16914            } else {
16915                let Some(workspace) = workspace else {
16916                    return Ok(Navigated::No);
16917                };
16918
16919                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16920                let target_range = target_ranges.first().unwrap().clone();
16921
16922                editor.update_in(cx, |editor, window, cx| {
16923                    let range = target_range.to_point(target_buffer.read(cx));
16924                    let range = editor.range_for_match(&range, false);
16925                    let range = collapse_multiline_range(range);
16926
16927                    if !split
16928                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16929                    {
16930                        editor.go_to_singleton_buffer_range(range, window, cx);
16931                    } else {
16932                        let pane = workspace.read(cx).active_pane().clone();
16933                        window.defer(cx, move |window, cx| {
16934                            let target_editor: Entity<Self> =
16935                                workspace.update(cx, |workspace, cx| {
16936                                    let pane = if split {
16937                                        workspace.adjacent_pane(window, cx)
16938                                    } else {
16939                                        workspace.active_pane().clone()
16940                                    };
16941
16942                                    workspace.open_project_item(
16943                                        pane,
16944                                        target_buffer.clone(),
16945                                        true,
16946                                        true,
16947                                        window,
16948                                        cx,
16949                                    )
16950                                });
16951                            target_editor.update(cx, |target_editor, cx| {
16952                                // When selecting a definition in a different buffer, disable the nav history
16953                                // to avoid creating a history entry at the previous cursor location.
16954                                pane.update(cx, |pane, _| pane.disable_history());
16955                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16956                                pane.update(cx, |pane, _| pane.enable_history());
16957                            });
16958                        });
16959                    }
16960                    Navigated::Yes
16961                })
16962            }
16963        })
16964    }
16965
16966    fn compute_target_location(
16967        &self,
16968        lsp_location: lsp::Location,
16969        server_id: LanguageServerId,
16970        window: &mut Window,
16971        cx: &mut Context<Self>,
16972    ) -> Task<anyhow::Result<Option<Location>>> {
16973        let Some(project) = self.project.clone() else {
16974            return Task::ready(Ok(None));
16975        };
16976
16977        cx.spawn_in(window, async move |editor, cx| {
16978            let location_task = editor.update(cx, |_, cx| {
16979                project.update(cx, |project, cx| {
16980                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16981                })
16982            })?;
16983            let location = Some({
16984                let target_buffer_handle = location_task.await.context("open local buffer")?;
16985                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16986                    let target_start = target_buffer
16987                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16988                    let target_end = target_buffer
16989                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16990                    target_buffer.anchor_after(target_start)
16991                        ..target_buffer.anchor_before(target_end)
16992                })?;
16993                Location {
16994                    buffer: target_buffer_handle,
16995                    range,
16996                }
16997            });
16998            Ok(location)
16999        })
17000    }
17001
17002    fn go_to_next_reference(
17003        &mut self,
17004        _: &GoToNextReference,
17005        window: &mut Window,
17006        cx: &mut Context<Self>,
17007    ) {
17008        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17009        if let Some(task) = task {
17010            task.detach();
17011        };
17012    }
17013
17014    fn go_to_prev_reference(
17015        &mut self,
17016        _: &GoToPreviousReference,
17017        window: &mut Window,
17018        cx: &mut Context<Self>,
17019    ) {
17020        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17021        if let Some(task) = task {
17022            task.detach();
17023        };
17024    }
17025
17026    pub fn go_to_reference_before_or_after_position(
17027        &mut self,
17028        direction: Direction,
17029        count: usize,
17030        window: &mut Window,
17031        cx: &mut Context<Self>,
17032    ) -> Option<Task<Result<()>>> {
17033        let selection = self.selections.newest_anchor();
17034        let head = selection.head();
17035
17036        let multi_buffer = self.buffer.read(cx);
17037
17038        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17039        let workspace = self.workspace()?;
17040        let project = workspace.read(cx).project().clone();
17041        let references =
17042            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17043        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17044            let Some(locations) = references.await? else {
17045                return Ok(());
17046            };
17047
17048            if locations.is_empty() {
17049                // totally normal - the cursor may be on something which is not
17050                // a symbol (e.g. a keyword)
17051                log::info!("no references found under cursor");
17052                return Ok(());
17053            }
17054
17055            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17056
17057            let multi_buffer_snapshot =
17058                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
17059
17060            let (locations, current_location_index) =
17061                multi_buffer.update(cx, |multi_buffer, cx| {
17062                    let mut locations = locations
17063                        .into_iter()
17064                        .filter_map(|loc| {
17065                            let start = multi_buffer.buffer_anchor_to_anchor(
17066                                &loc.buffer,
17067                                loc.range.start,
17068                                cx,
17069                            )?;
17070                            let end = multi_buffer.buffer_anchor_to_anchor(
17071                                &loc.buffer,
17072                                loc.range.end,
17073                                cx,
17074                            )?;
17075                            Some(start..end)
17076                        })
17077                        .collect::<Vec<_>>();
17078
17079                    // There is an O(n) implementation, but given this list will be
17080                    // small (usually <100 items), the extra O(log(n)) factor isn't
17081                    // worth the (surprisingly large amount of) extra complexity.
17082                    locations
17083                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17084
17085                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17086
17087                    let current_location_index = locations.iter().position(|loc| {
17088                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17089                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17090                    });
17091
17092                    (locations, current_location_index)
17093                })?;
17094
17095            let Some(current_location_index) = current_location_index else {
17096                // This indicates something has gone wrong, because we already
17097                // handle the "no references" case above
17098                log::error!(
17099                    "failed to find current reference under cursor. Total references: {}",
17100                    locations.len()
17101                );
17102                return Ok(());
17103            };
17104
17105            let destination_location_index = match direction {
17106                Direction::Next => (current_location_index + count) % locations.len(),
17107                Direction::Prev => {
17108                    (current_location_index + locations.len() - count % locations.len())
17109                        % locations.len()
17110                }
17111            };
17112
17113            // TODO(cameron): is this needed?
17114            // the thinking is to avoid "jumping to the current location" (avoid
17115            // polluting "jumplist" in vim terms)
17116            if current_location_index == destination_location_index {
17117                return Ok(());
17118            }
17119
17120            let Range { start, end } = locations[destination_location_index];
17121
17122            editor.update_in(cx, |editor, window, cx| {
17123                let effects = SelectionEffects::default();
17124
17125                editor.unfold_ranges(&[start..end], false, false, cx);
17126                editor.change_selections(effects, window, cx, |s| {
17127                    s.select_ranges([start..start]);
17128                });
17129            })?;
17130
17131            Ok(())
17132        }))
17133    }
17134
17135    pub fn find_all_references(
17136        &mut self,
17137        _: &FindAllReferences,
17138        window: &mut Window,
17139        cx: &mut Context<Self>,
17140    ) -> Option<Task<Result<Navigated>>> {
17141        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17142        let multi_buffer = self.buffer.read(cx);
17143        let head = selection.head();
17144
17145        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17146        let head_anchor = multi_buffer_snapshot.anchor_at(
17147            head,
17148            if head < selection.tail() {
17149                Bias::Right
17150            } else {
17151                Bias::Left
17152            },
17153        );
17154
17155        match self
17156            .find_all_references_task_sources
17157            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17158        {
17159            Ok(_) => {
17160                log::info!(
17161                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17162                );
17163                return None;
17164            }
17165            Err(i) => {
17166                self.find_all_references_task_sources.insert(i, head_anchor);
17167            }
17168        }
17169
17170        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17171        let workspace = self.workspace()?;
17172        let project = workspace.read(cx).project().clone();
17173        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17174        Some(cx.spawn_in(window, async move |editor, cx| {
17175            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17176                if let Ok(i) = editor
17177                    .find_all_references_task_sources
17178                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17179                {
17180                    editor.find_all_references_task_sources.remove(i);
17181                }
17182            });
17183
17184            let Some(locations) = references.await? else {
17185                return anyhow::Ok(Navigated::No);
17186            };
17187            let mut locations = cx.update(|_, cx| {
17188                locations
17189                    .into_iter()
17190                    .map(|location| {
17191                        let buffer = location.buffer.read(cx);
17192                        (location.buffer, location.range.to_point(buffer))
17193                    })
17194                    .into_group_map()
17195            })?;
17196            if locations.is_empty() {
17197                return anyhow::Ok(Navigated::No);
17198            }
17199            for ranges in locations.values_mut() {
17200                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17201                ranges.dedup();
17202            }
17203
17204            workspace.update_in(cx, |workspace, window, cx| {
17205                let target = locations
17206                    .iter()
17207                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17208                    .map(|(buffer, location)| {
17209                        buffer
17210                            .read(cx)
17211                            .text_for_range(location.clone())
17212                            .collect::<String>()
17213                    })
17214                    .filter(|text| !text.contains('\n'))
17215                    .unique()
17216                    .take(3)
17217                    .join(", ");
17218                let title = if target.is_empty() {
17219                    "References".to_owned()
17220                } else {
17221                    format!("References to {target}")
17222                };
17223                Self::open_locations_in_multibuffer(
17224                    workspace,
17225                    locations,
17226                    title,
17227                    false,
17228                    MultibufferSelectionMode::First,
17229                    window,
17230                    cx,
17231                );
17232                Navigated::Yes
17233            })
17234        }))
17235    }
17236
17237    /// Opens a multibuffer with the given project locations in it
17238    pub fn open_locations_in_multibuffer(
17239        workspace: &mut Workspace,
17240        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17241        title: String,
17242        split: bool,
17243        multibuffer_selection_mode: MultibufferSelectionMode,
17244        window: &mut Window,
17245        cx: &mut Context<Workspace>,
17246    ) {
17247        if locations.is_empty() {
17248            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17249            return;
17250        }
17251
17252        let capability = workspace.project().read(cx).capability();
17253        let mut ranges = <Vec<Range<Anchor>>>::new();
17254
17255        // a key to find existing multibuffer editors with the same set of locations
17256        // to prevent us from opening more and more multibuffer tabs for searches and the like
17257        let mut key = (title.clone(), vec![]);
17258        let excerpt_buffer = cx.new(|cx| {
17259            let key = &mut key.1;
17260            let mut multibuffer = MultiBuffer::new(capability);
17261            for (buffer, mut ranges_for_buffer) in locations {
17262                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17263                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17264                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17265                    PathKey::for_buffer(&buffer, cx),
17266                    buffer.clone(),
17267                    ranges_for_buffer,
17268                    multibuffer_context_lines(cx),
17269                    cx,
17270                );
17271                ranges.extend(new_ranges)
17272            }
17273
17274            multibuffer.with_title(title)
17275        });
17276        let existing = workspace.active_pane().update(cx, |pane, cx| {
17277            pane.items()
17278                .filter_map(|item| item.downcast::<Editor>())
17279                .find(|editor| {
17280                    editor
17281                        .read(cx)
17282                        .lookup_key
17283                        .as_ref()
17284                        .and_then(|it| {
17285                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17286                        })
17287                        .is_some_and(|it| *it == key)
17288                })
17289        });
17290        let editor = existing.unwrap_or_else(|| {
17291            cx.new(|cx| {
17292                let mut editor = Editor::for_multibuffer(
17293                    excerpt_buffer,
17294                    Some(workspace.project().clone()),
17295                    window,
17296                    cx,
17297                );
17298                editor.lookup_key = Some(Box::new(key));
17299                editor
17300            })
17301        });
17302        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17303            MultibufferSelectionMode::First => {
17304                if let Some(first_range) = ranges.first() {
17305                    editor.change_selections(
17306                        SelectionEffects::no_scroll(),
17307                        window,
17308                        cx,
17309                        |selections| {
17310                            selections.clear_disjoint();
17311                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17312                        },
17313                    );
17314                }
17315                editor.highlight_background::<Self>(
17316                    &ranges,
17317                    |theme| theme.colors().editor_highlighted_line_background,
17318                    cx,
17319                );
17320            }
17321            MultibufferSelectionMode::All => {
17322                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17323                    selections.clear_disjoint();
17324                    selections.select_anchor_ranges(ranges);
17325                });
17326            }
17327        });
17328
17329        let item = Box::new(editor);
17330        let item_id = item.item_id();
17331
17332        if split {
17333            let pane = workspace.adjacent_pane(window, cx);
17334            workspace.add_item(pane, item, None, true, true, window, cx);
17335        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17336            let (preview_item_id, preview_item_idx) =
17337                workspace.active_pane().read_with(cx, |pane, _| {
17338                    (pane.preview_item_id(), pane.preview_item_idx())
17339                });
17340
17341            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17342
17343            if let Some(preview_item_id) = preview_item_id {
17344                workspace.active_pane().update(cx, |pane, cx| {
17345                    pane.remove_item(preview_item_id, false, false, window, cx);
17346                });
17347            }
17348        } else {
17349            workspace.add_item_to_active_pane(item, None, true, window, cx);
17350        }
17351        workspace.active_pane().update(cx, |pane, cx| {
17352            pane.set_preview_item_id(Some(item_id), cx);
17353        });
17354    }
17355
17356    pub fn rename(
17357        &mut self,
17358        _: &Rename,
17359        window: &mut Window,
17360        cx: &mut Context<Self>,
17361    ) -> Option<Task<Result<()>>> {
17362        use language::ToOffset as _;
17363
17364        let provider = self.semantics_provider.clone()?;
17365        let selection = self.selections.newest_anchor().clone();
17366        let (cursor_buffer, cursor_buffer_position) = self
17367            .buffer
17368            .read(cx)
17369            .text_anchor_for_position(selection.head(), cx)?;
17370        let (tail_buffer, cursor_buffer_position_end) = self
17371            .buffer
17372            .read(cx)
17373            .text_anchor_for_position(selection.tail(), cx)?;
17374        if tail_buffer != cursor_buffer {
17375            return None;
17376        }
17377
17378        let snapshot = cursor_buffer.read(cx).snapshot();
17379        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17380        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17381        let prepare_rename = provider
17382            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17383            .unwrap_or_else(|| Task::ready(Ok(None)));
17384        drop(snapshot);
17385
17386        Some(cx.spawn_in(window, async move |this, cx| {
17387            let rename_range = if let Some(range) = prepare_rename.await? {
17388                Some(range)
17389            } else {
17390                this.update(cx, |this, cx| {
17391                    let buffer = this.buffer.read(cx).snapshot(cx);
17392                    let mut buffer_highlights = this
17393                        .document_highlights_for_position(selection.head(), &buffer)
17394                        .filter(|highlight| {
17395                            highlight.start.excerpt_id == selection.head().excerpt_id
17396                                && highlight.end.excerpt_id == selection.head().excerpt_id
17397                        });
17398                    buffer_highlights
17399                        .next()
17400                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17401                })?
17402            };
17403            if let Some(rename_range) = rename_range {
17404                this.update_in(cx, |this, window, cx| {
17405                    let snapshot = cursor_buffer.read(cx).snapshot();
17406                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17407                    let cursor_offset_in_rename_range =
17408                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17409                    let cursor_offset_in_rename_range_end =
17410                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17411
17412                    this.take_rename(false, window, cx);
17413                    let buffer = this.buffer.read(cx).read(cx);
17414                    let cursor_offset = selection.head().to_offset(&buffer);
17415                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17416                    let rename_end = rename_start + rename_buffer_range.len();
17417                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17418                    let mut old_highlight_id = None;
17419                    let old_name: Arc<str> = buffer
17420                        .chunks(rename_start..rename_end, true)
17421                        .map(|chunk| {
17422                            if old_highlight_id.is_none() {
17423                                old_highlight_id = chunk.syntax_highlight_id;
17424                            }
17425                            chunk.text
17426                        })
17427                        .collect::<String>()
17428                        .into();
17429
17430                    drop(buffer);
17431
17432                    // Position the selection in the rename editor so that it matches the current selection.
17433                    this.show_local_selections = false;
17434                    let rename_editor = cx.new(|cx| {
17435                        let mut editor = Editor::single_line(window, cx);
17436                        editor.buffer.update(cx, |buffer, cx| {
17437                            buffer.edit([(0..0, old_name.clone())], None, cx)
17438                        });
17439                        let rename_selection_range = match cursor_offset_in_rename_range
17440                            .cmp(&cursor_offset_in_rename_range_end)
17441                        {
17442                            Ordering::Equal => {
17443                                editor.select_all(&SelectAll, window, cx);
17444                                return editor;
17445                            }
17446                            Ordering::Less => {
17447                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17448                            }
17449                            Ordering::Greater => {
17450                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17451                            }
17452                        };
17453                        if rename_selection_range.end > old_name.len() {
17454                            editor.select_all(&SelectAll, window, cx);
17455                        } else {
17456                            editor.change_selections(Default::default(), window, cx, |s| {
17457                                s.select_ranges([rename_selection_range]);
17458                            });
17459                        }
17460                        editor
17461                    });
17462                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17463                        if e == &EditorEvent::Focused {
17464                            cx.emit(EditorEvent::FocusedIn)
17465                        }
17466                    })
17467                    .detach();
17468
17469                    let write_highlights =
17470                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17471                    let read_highlights =
17472                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17473                    let ranges = write_highlights
17474                        .iter()
17475                        .flat_map(|(_, ranges)| ranges.iter())
17476                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17477                        .cloned()
17478                        .collect();
17479
17480                    this.highlight_text::<Rename>(
17481                        ranges,
17482                        HighlightStyle {
17483                            fade_out: Some(0.6),
17484                            ..Default::default()
17485                        },
17486                        cx,
17487                    );
17488                    let rename_focus_handle = rename_editor.focus_handle(cx);
17489                    window.focus(&rename_focus_handle);
17490                    let block_id = this.insert_blocks(
17491                        [BlockProperties {
17492                            style: BlockStyle::Flex,
17493                            placement: BlockPlacement::Below(range.start),
17494                            height: Some(1),
17495                            render: Arc::new({
17496                                let rename_editor = rename_editor.clone();
17497                                move |cx: &mut BlockContext| {
17498                                    let mut text_style = cx.editor_style.text.clone();
17499                                    if let Some(highlight_style) = old_highlight_id
17500                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17501                                    {
17502                                        text_style = text_style.highlight(highlight_style);
17503                                    }
17504                                    div()
17505                                        .block_mouse_except_scroll()
17506                                        .pl(cx.anchor_x)
17507                                        .child(EditorElement::new(
17508                                            &rename_editor,
17509                                            EditorStyle {
17510                                                background: cx.theme().system().transparent,
17511                                                local_player: cx.editor_style.local_player,
17512                                                text: text_style,
17513                                                scrollbar_width: cx.editor_style.scrollbar_width,
17514                                                syntax: cx.editor_style.syntax.clone(),
17515                                                status: cx.editor_style.status.clone(),
17516                                                inlay_hints_style: HighlightStyle {
17517                                                    font_weight: Some(FontWeight::BOLD),
17518                                                    ..make_inlay_hints_style(cx.app)
17519                                                },
17520                                                edit_prediction_styles: make_suggestion_styles(
17521                                                    cx.app,
17522                                                ),
17523                                                ..EditorStyle::default()
17524                                            },
17525                                        ))
17526                                        .into_any_element()
17527                                }
17528                            }),
17529                            priority: 0,
17530                        }],
17531                        Some(Autoscroll::fit()),
17532                        cx,
17533                    )[0];
17534                    this.pending_rename = Some(RenameState {
17535                        range,
17536                        old_name,
17537                        editor: rename_editor,
17538                        block_id,
17539                    });
17540                })?;
17541            }
17542
17543            Ok(())
17544        }))
17545    }
17546
17547    pub fn confirm_rename(
17548        &mut self,
17549        _: &ConfirmRename,
17550        window: &mut Window,
17551        cx: &mut Context<Self>,
17552    ) -> Option<Task<Result<()>>> {
17553        let rename = self.take_rename(false, window, cx)?;
17554        let workspace = self.workspace()?.downgrade();
17555        let (buffer, start) = self
17556            .buffer
17557            .read(cx)
17558            .text_anchor_for_position(rename.range.start, cx)?;
17559        let (end_buffer, _) = self
17560            .buffer
17561            .read(cx)
17562            .text_anchor_for_position(rename.range.end, cx)?;
17563        if buffer != end_buffer {
17564            return None;
17565        }
17566
17567        let old_name = rename.old_name;
17568        let new_name = rename.editor.read(cx).text(cx);
17569
17570        let rename = self.semantics_provider.as_ref()?.perform_rename(
17571            &buffer,
17572            start,
17573            new_name.clone(),
17574            cx,
17575        )?;
17576
17577        Some(cx.spawn_in(window, async move |editor, cx| {
17578            let project_transaction = rename.await?;
17579            Self::open_project_transaction(
17580                &editor,
17581                workspace,
17582                project_transaction,
17583                format!("Rename: {}{}", old_name, new_name),
17584                cx,
17585            )
17586            .await?;
17587
17588            editor.update(cx, |editor, cx| {
17589                editor.refresh_document_highlights(cx);
17590            })?;
17591            Ok(())
17592        }))
17593    }
17594
17595    fn take_rename(
17596        &mut self,
17597        moving_cursor: bool,
17598        window: &mut Window,
17599        cx: &mut Context<Self>,
17600    ) -> Option<RenameState> {
17601        let rename = self.pending_rename.take()?;
17602        if rename.editor.focus_handle(cx).is_focused(window) {
17603            window.focus(&self.focus_handle);
17604        }
17605
17606        self.remove_blocks(
17607            [rename.block_id].into_iter().collect(),
17608            Some(Autoscroll::fit()),
17609            cx,
17610        );
17611        self.clear_highlights::<Rename>(cx);
17612        self.show_local_selections = true;
17613
17614        if moving_cursor {
17615            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17616                editor
17617                    .selections
17618                    .newest::<usize>(&editor.display_snapshot(cx))
17619                    .head()
17620            });
17621
17622            // Update the selection to match the position of the selection inside
17623            // the rename editor.
17624            let snapshot = self.buffer.read(cx).read(cx);
17625            let rename_range = rename.range.to_offset(&snapshot);
17626            let cursor_in_editor = snapshot
17627                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17628                .min(rename_range.end);
17629            drop(snapshot);
17630
17631            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17632                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17633            });
17634        } else {
17635            self.refresh_document_highlights(cx);
17636        }
17637
17638        Some(rename)
17639    }
17640
17641    pub fn pending_rename(&self) -> Option<&RenameState> {
17642        self.pending_rename.as_ref()
17643    }
17644
17645    fn format(
17646        &mut self,
17647        _: &Format,
17648        window: &mut Window,
17649        cx: &mut Context<Self>,
17650    ) -> Option<Task<Result<()>>> {
17651        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17652
17653        let project = match &self.project {
17654            Some(project) => project.clone(),
17655            None => return None,
17656        };
17657
17658        Some(self.perform_format(
17659            project,
17660            FormatTrigger::Manual,
17661            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17662            window,
17663            cx,
17664        ))
17665    }
17666
17667    fn format_selections(
17668        &mut self,
17669        _: &FormatSelections,
17670        window: &mut Window,
17671        cx: &mut Context<Self>,
17672    ) -> Option<Task<Result<()>>> {
17673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17674
17675        let project = match &self.project {
17676            Some(project) => project.clone(),
17677            None => return None,
17678        };
17679
17680        let ranges = self
17681            .selections
17682            .all_adjusted(&self.display_snapshot(cx))
17683            .into_iter()
17684            .map(|selection| selection.range())
17685            .collect_vec();
17686
17687        Some(self.perform_format(
17688            project,
17689            FormatTrigger::Manual,
17690            FormatTarget::Ranges(ranges),
17691            window,
17692            cx,
17693        ))
17694    }
17695
17696    fn perform_format(
17697        &mut self,
17698        project: Entity<Project>,
17699        trigger: FormatTrigger,
17700        target: FormatTarget,
17701        window: &mut Window,
17702        cx: &mut Context<Self>,
17703    ) -> Task<Result<()>> {
17704        let buffer = self.buffer.clone();
17705        let (buffers, target) = match target {
17706            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17707            FormatTarget::Ranges(selection_ranges) => {
17708                let multi_buffer = buffer.read(cx);
17709                let snapshot = multi_buffer.read(cx);
17710                let mut buffers = HashSet::default();
17711                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17712                    BTreeMap::new();
17713                for selection_range in selection_ranges {
17714                    for (buffer, buffer_range, _) in
17715                        snapshot.range_to_buffer_ranges(selection_range)
17716                    {
17717                        let buffer_id = buffer.remote_id();
17718                        let start = buffer.anchor_before(buffer_range.start);
17719                        let end = buffer.anchor_after(buffer_range.end);
17720                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17721                        buffer_id_to_ranges
17722                            .entry(buffer_id)
17723                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17724                            .or_insert_with(|| vec![start..end]);
17725                    }
17726                }
17727                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17728            }
17729        };
17730
17731        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17732        let selections_prev = transaction_id_prev
17733            .and_then(|transaction_id_prev| {
17734                // default to selections as they were after the last edit, if we have them,
17735                // instead of how they are now.
17736                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17737                // will take you back to where you made the last edit, instead of staying where you scrolled
17738                self.selection_history
17739                    .transaction(transaction_id_prev)
17740                    .map(|t| t.0.clone())
17741            })
17742            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17743
17744        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17745        let format = project.update(cx, |project, cx| {
17746            project.format(buffers, target, true, trigger, cx)
17747        });
17748
17749        cx.spawn_in(window, async move |editor, cx| {
17750            let transaction = futures::select_biased! {
17751                transaction = format.log_err().fuse() => transaction,
17752                () = timeout => {
17753                    log::warn!("timed out waiting for formatting");
17754                    None
17755                }
17756            };
17757
17758            buffer
17759                .update(cx, |buffer, cx| {
17760                    if let Some(transaction) = transaction
17761                        && !buffer.is_singleton()
17762                    {
17763                        buffer.push_transaction(&transaction.0, cx);
17764                    }
17765                    cx.notify();
17766                })
17767                .ok();
17768
17769            if let Some(transaction_id_now) =
17770                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17771            {
17772                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17773                if has_new_transaction {
17774                    _ = editor.update(cx, |editor, _| {
17775                        editor
17776                            .selection_history
17777                            .insert_transaction(transaction_id_now, selections_prev);
17778                    });
17779                }
17780            }
17781
17782            Ok(())
17783        })
17784    }
17785
17786    fn organize_imports(
17787        &mut self,
17788        _: &OrganizeImports,
17789        window: &mut Window,
17790        cx: &mut Context<Self>,
17791    ) -> Option<Task<Result<()>>> {
17792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17793        let project = match &self.project {
17794            Some(project) => project.clone(),
17795            None => return None,
17796        };
17797        Some(self.perform_code_action_kind(
17798            project,
17799            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17800            window,
17801            cx,
17802        ))
17803    }
17804
17805    fn perform_code_action_kind(
17806        &mut self,
17807        project: Entity<Project>,
17808        kind: CodeActionKind,
17809        window: &mut Window,
17810        cx: &mut Context<Self>,
17811    ) -> Task<Result<()>> {
17812        let buffer = self.buffer.clone();
17813        let buffers = buffer.read(cx).all_buffers();
17814        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17815        let apply_action = project.update(cx, |project, cx| {
17816            project.apply_code_action_kind(buffers, kind, true, cx)
17817        });
17818        cx.spawn_in(window, async move |_, cx| {
17819            let transaction = futures::select_biased! {
17820                () = timeout => {
17821                    log::warn!("timed out waiting for executing code action");
17822                    None
17823                }
17824                transaction = apply_action.log_err().fuse() => transaction,
17825            };
17826            buffer
17827                .update(cx, |buffer, cx| {
17828                    // check if we need this
17829                    if let Some(transaction) = transaction
17830                        && !buffer.is_singleton()
17831                    {
17832                        buffer.push_transaction(&transaction.0, cx);
17833                    }
17834                    cx.notify();
17835                })
17836                .ok();
17837            Ok(())
17838        })
17839    }
17840
17841    pub fn restart_language_server(
17842        &mut self,
17843        _: &RestartLanguageServer,
17844        _: &mut Window,
17845        cx: &mut Context<Self>,
17846    ) {
17847        if let Some(project) = self.project.clone() {
17848            self.buffer.update(cx, |multi_buffer, cx| {
17849                project.update(cx, |project, cx| {
17850                    project.restart_language_servers_for_buffers(
17851                        multi_buffer.all_buffers().into_iter().collect(),
17852                        HashSet::default(),
17853                        cx,
17854                    );
17855                });
17856            })
17857        }
17858    }
17859
17860    pub fn stop_language_server(
17861        &mut self,
17862        _: &StopLanguageServer,
17863        _: &mut Window,
17864        cx: &mut Context<Self>,
17865    ) {
17866        if let Some(project) = self.project.clone() {
17867            self.buffer.update(cx, |multi_buffer, cx| {
17868                project.update(cx, |project, cx| {
17869                    project.stop_language_servers_for_buffers(
17870                        multi_buffer.all_buffers().into_iter().collect(),
17871                        HashSet::default(),
17872                        cx,
17873                    );
17874                });
17875            });
17876            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17877        }
17878    }
17879
17880    fn cancel_language_server_work(
17881        workspace: &mut Workspace,
17882        _: &actions::CancelLanguageServerWork,
17883        _: &mut Window,
17884        cx: &mut Context<Workspace>,
17885    ) {
17886        let project = workspace.project();
17887        let buffers = workspace
17888            .active_item(cx)
17889            .and_then(|item| item.act_as::<Editor>(cx))
17890            .map_or(HashSet::default(), |editor| {
17891                editor.read(cx).buffer.read(cx).all_buffers()
17892            });
17893        project.update(cx, |project, cx| {
17894            project.cancel_language_server_work_for_buffers(buffers, cx);
17895        });
17896    }
17897
17898    fn show_character_palette(
17899        &mut self,
17900        _: &ShowCharacterPalette,
17901        window: &mut Window,
17902        _: &mut Context<Self>,
17903    ) {
17904        window.show_character_palette();
17905    }
17906
17907    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17908        if !self.diagnostics_enabled() {
17909            return;
17910        }
17911
17912        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17913            let buffer = self.buffer.read(cx).snapshot(cx);
17914            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17915            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17916            let is_valid = buffer
17917                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17918                .any(|entry| {
17919                    entry.diagnostic.is_primary
17920                        && !entry.range.is_empty()
17921                        && entry.range.start == primary_range_start
17922                        && entry.diagnostic.message == active_diagnostics.active_message
17923                });
17924
17925            if !is_valid {
17926                self.dismiss_diagnostics(cx);
17927            }
17928        }
17929    }
17930
17931    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17932        match &self.active_diagnostics {
17933            ActiveDiagnostic::Group(group) => Some(group),
17934            _ => None,
17935        }
17936    }
17937
17938    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17939        if !self.diagnostics_enabled() {
17940            return;
17941        }
17942        self.dismiss_diagnostics(cx);
17943        self.active_diagnostics = ActiveDiagnostic::All;
17944    }
17945
17946    fn activate_diagnostics(
17947        &mut self,
17948        buffer_id: BufferId,
17949        diagnostic: DiagnosticEntryRef<'_, usize>,
17950        window: &mut Window,
17951        cx: &mut Context<Self>,
17952    ) {
17953        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17954            return;
17955        }
17956        self.dismiss_diagnostics(cx);
17957        let snapshot = self.snapshot(window, cx);
17958        let buffer = self.buffer.read(cx).snapshot(cx);
17959        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17960            return;
17961        };
17962
17963        let diagnostic_group = buffer
17964            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17965            .collect::<Vec<_>>();
17966
17967        let language_registry = self
17968            .project()
17969            .map(|project| project.read(cx).languages().clone());
17970
17971        let blocks = renderer.render_group(
17972            diagnostic_group,
17973            buffer_id,
17974            snapshot,
17975            cx.weak_entity(),
17976            language_registry,
17977            cx,
17978        );
17979
17980        let blocks = self.display_map.update(cx, |display_map, cx| {
17981            display_map.insert_blocks(blocks, cx).into_iter().collect()
17982        });
17983        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17984            active_range: buffer.anchor_before(diagnostic.range.start)
17985                ..buffer.anchor_after(diagnostic.range.end),
17986            active_message: diagnostic.diagnostic.message.clone(),
17987            group_id: diagnostic.diagnostic.group_id,
17988            blocks,
17989        });
17990        cx.notify();
17991    }
17992
17993    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17994        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17995            return;
17996        };
17997
17998        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17999        if let ActiveDiagnostic::Group(group) = prev {
18000            self.display_map.update(cx, |display_map, cx| {
18001                display_map.remove_blocks(group.blocks, cx);
18002            });
18003            cx.notify();
18004        }
18005    }
18006
18007    /// Disable inline diagnostics rendering for this editor.
18008    pub fn disable_inline_diagnostics(&mut self) {
18009        self.inline_diagnostics_enabled = false;
18010        self.inline_diagnostics_update = Task::ready(());
18011        self.inline_diagnostics.clear();
18012    }
18013
18014    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18015        self.diagnostics_enabled = false;
18016        self.dismiss_diagnostics(cx);
18017        self.inline_diagnostics_update = Task::ready(());
18018        self.inline_diagnostics.clear();
18019    }
18020
18021    pub fn disable_word_completions(&mut self) {
18022        self.word_completions_enabled = false;
18023    }
18024
18025    pub fn diagnostics_enabled(&self) -> bool {
18026        self.diagnostics_enabled && self.mode.is_full()
18027    }
18028
18029    pub fn inline_diagnostics_enabled(&self) -> bool {
18030        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18031    }
18032
18033    pub fn show_inline_diagnostics(&self) -> bool {
18034        self.show_inline_diagnostics
18035    }
18036
18037    pub fn toggle_inline_diagnostics(
18038        &mut self,
18039        _: &ToggleInlineDiagnostics,
18040        window: &mut Window,
18041        cx: &mut Context<Editor>,
18042    ) {
18043        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18044        self.refresh_inline_diagnostics(false, window, cx);
18045    }
18046
18047    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18048        self.diagnostics_max_severity = severity;
18049        self.display_map.update(cx, |display_map, _| {
18050            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18051        });
18052    }
18053
18054    pub fn toggle_diagnostics(
18055        &mut self,
18056        _: &ToggleDiagnostics,
18057        window: &mut Window,
18058        cx: &mut Context<Editor>,
18059    ) {
18060        if !self.diagnostics_enabled() {
18061            return;
18062        }
18063
18064        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18065            EditorSettings::get_global(cx)
18066                .diagnostics_max_severity
18067                .filter(|severity| severity != &DiagnosticSeverity::Off)
18068                .unwrap_or(DiagnosticSeverity::Hint)
18069        } else {
18070            DiagnosticSeverity::Off
18071        };
18072        self.set_max_diagnostics_severity(new_severity, cx);
18073        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18074            self.active_diagnostics = ActiveDiagnostic::None;
18075            self.inline_diagnostics_update = Task::ready(());
18076            self.inline_diagnostics.clear();
18077        } else {
18078            self.refresh_inline_diagnostics(false, window, cx);
18079        }
18080
18081        cx.notify();
18082    }
18083
18084    pub fn toggle_minimap(
18085        &mut self,
18086        _: &ToggleMinimap,
18087        window: &mut Window,
18088        cx: &mut Context<Editor>,
18089    ) {
18090        if self.supports_minimap(cx) {
18091            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18092        }
18093    }
18094
18095    fn refresh_inline_diagnostics(
18096        &mut self,
18097        debounce: bool,
18098        window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        let max_severity = ProjectSettings::get_global(cx)
18102            .diagnostics
18103            .inline
18104            .max_severity
18105            .unwrap_or(self.diagnostics_max_severity);
18106
18107        if !self.inline_diagnostics_enabled()
18108            || !self.diagnostics_enabled()
18109            || !self.show_inline_diagnostics
18110            || max_severity == DiagnosticSeverity::Off
18111        {
18112            self.inline_diagnostics_update = Task::ready(());
18113            self.inline_diagnostics.clear();
18114            return;
18115        }
18116
18117        let debounce_ms = ProjectSettings::get_global(cx)
18118            .diagnostics
18119            .inline
18120            .update_debounce_ms;
18121        let debounce = if debounce && debounce_ms > 0 {
18122            Some(Duration::from_millis(debounce_ms))
18123        } else {
18124            None
18125        };
18126        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18127            if let Some(debounce) = debounce {
18128                cx.background_executor().timer(debounce).await;
18129            }
18130            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18131                editor
18132                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18133                    .ok()
18134            }) else {
18135                return;
18136            };
18137
18138            let new_inline_diagnostics = cx
18139                .background_spawn(async move {
18140                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18141                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18142                        let message = diagnostic_entry
18143                            .diagnostic
18144                            .message
18145                            .split_once('\n')
18146                            .map(|(line, _)| line)
18147                            .map(SharedString::new)
18148                            .unwrap_or_else(|| {
18149                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18150                            });
18151                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18152                        let (Ok(i) | Err(i)) = inline_diagnostics
18153                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18154                        inline_diagnostics.insert(
18155                            i,
18156                            (
18157                                start_anchor,
18158                                InlineDiagnostic {
18159                                    message,
18160                                    group_id: diagnostic_entry.diagnostic.group_id,
18161                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18162                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18163                                    severity: diagnostic_entry.diagnostic.severity,
18164                                },
18165                            ),
18166                        );
18167                    }
18168                    inline_diagnostics
18169                })
18170                .await;
18171
18172            editor
18173                .update(cx, |editor, cx| {
18174                    editor.inline_diagnostics = new_inline_diagnostics;
18175                    cx.notify();
18176                })
18177                .ok();
18178        });
18179    }
18180
18181    fn pull_diagnostics(
18182        &mut self,
18183        buffer_id: Option<BufferId>,
18184        window: &Window,
18185        cx: &mut Context<Self>,
18186    ) -> Option<()> {
18187        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18188            return None;
18189        }
18190        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18191            .diagnostics
18192            .lsp_pull_diagnostics;
18193        if !pull_diagnostics_settings.enabled {
18194            return None;
18195        }
18196        let project = self.project()?.downgrade();
18197        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18198        let mut buffers = self.buffer.read(cx).all_buffers();
18199        buffers.retain(|buffer| {
18200            let buffer_id_to_retain = buffer.read(cx).remote_id();
18201            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18202                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18203        });
18204        if buffers.is_empty() {
18205            self.pull_diagnostics_task = Task::ready(());
18206            return None;
18207        }
18208
18209        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18210            cx.background_executor().timer(debounce).await;
18211
18212            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18213                buffers
18214                    .into_iter()
18215                    .filter_map(|buffer| {
18216                        project
18217                            .update(cx, |project, cx| {
18218                                project.lsp_store().update(cx, |lsp_store, cx| {
18219                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18220                                })
18221                            })
18222                            .ok()
18223                    })
18224                    .collect::<FuturesUnordered<_>>()
18225            }) else {
18226                return;
18227            };
18228
18229            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18230                match pull_task {
18231                    Ok(()) => {
18232                        if editor
18233                            .update_in(cx, |editor, window, cx| {
18234                                editor.update_diagnostics_state(window, cx);
18235                            })
18236                            .is_err()
18237                        {
18238                            return;
18239                        }
18240                    }
18241                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18242                }
18243            }
18244        });
18245
18246        Some(())
18247    }
18248
18249    pub fn set_selections_from_remote(
18250        &mut self,
18251        selections: Vec<Selection<Anchor>>,
18252        pending_selection: Option<Selection<Anchor>>,
18253        window: &mut Window,
18254        cx: &mut Context<Self>,
18255    ) {
18256        let old_cursor_position = self.selections.newest_anchor().head();
18257        self.selections
18258            .change_with(&self.display_snapshot(cx), |s| {
18259                s.select_anchors(selections);
18260                if let Some(pending_selection) = pending_selection {
18261                    s.set_pending(pending_selection, SelectMode::Character);
18262                } else {
18263                    s.clear_pending();
18264                }
18265            });
18266        self.selections_did_change(
18267            false,
18268            &old_cursor_position,
18269            SelectionEffects::default(),
18270            window,
18271            cx,
18272        );
18273    }
18274
18275    pub fn transact(
18276        &mut self,
18277        window: &mut Window,
18278        cx: &mut Context<Self>,
18279        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18280    ) -> Option<TransactionId> {
18281        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18282            this.start_transaction_at(Instant::now(), window, cx);
18283            update(this, window, cx);
18284            this.end_transaction_at(Instant::now(), cx)
18285        })
18286    }
18287
18288    pub fn start_transaction_at(
18289        &mut self,
18290        now: Instant,
18291        window: &mut Window,
18292        cx: &mut Context<Self>,
18293    ) -> Option<TransactionId> {
18294        self.end_selection(window, cx);
18295        if let Some(tx_id) = self
18296            .buffer
18297            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18298        {
18299            self.selection_history
18300                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18301            cx.emit(EditorEvent::TransactionBegun {
18302                transaction_id: tx_id,
18303            });
18304            Some(tx_id)
18305        } else {
18306            None
18307        }
18308    }
18309
18310    pub fn end_transaction_at(
18311        &mut self,
18312        now: Instant,
18313        cx: &mut Context<Self>,
18314    ) -> Option<TransactionId> {
18315        if let Some(transaction_id) = self
18316            .buffer
18317            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18318        {
18319            if let Some((_, end_selections)) =
18320                self.selection_history.transaction_mut(transaction_id)
18321            {
18322                *end_selections = Some(self.selections.disjoint_anchors_arc());
18323            } else {
18324                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18325            }
18326
18327            cx.emit(EditorEvent::Edited { transaction_id });
18328            Some(transaction_id)
18329        } else {
18330            None
18331        }
18332    }
18333
18334    pub fn modify_transaction_selection_history(
18335        &mut self,
18336        transaction_id: TransactionId,
18337        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18338    ) -> bool {
18339        self.selection_history
18340            .transaction_mut(transaction_id)
18341            .map(modify)
18342            .is_some()
18343    }
18344
18345    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18346        if self.selection_mark_mode {
18347            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18348                s.move_with(|_, sel| {
18349                    sel.collapse_to(sel.head(), SelectionGoal::None);
18350                });
18351            })
18352        }
18353        self.selection_mark_mode = true;
18354        cx.notify();
18355    }
18356
18357    pub fn swap_selection_ends(
18358        &mut self,
18359        _: &actions::SwapSelectionEnds,
18360        window: &mut Window,
18361        cx: &mut Context<Self>,
18362    ) {
18363        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18364            s.move_with(|_, sel| {
18365                if sel.start != sel.end {
18366                    sel.reversed = !sel.reversed
18367                }
18368            });
18369        });
18370        self.request_autoscroll(Autoscroll::newest(), cx);
18371        cx.notify();
18372    }
18373
18374    pub fn toggle_focus(
18375        workspace: &mut Workspace,
18376        _: &actions::ToggleFocus,
18377        window: &mut Window,
18378        cx: &mut Context<Workspace>,
18379    ) {
18380        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18381            return;
18382        };
18383        workspace.activate_item(&item, true, true, window, cx);
18384    }
18385
18386    pub fn toggle_fold(
18387        &mut self,
18388        _: &actions::ToggleFold,
18389        window: &mut Window,
18390        cx: &mut Context<Self>,
18391    ) {
18392        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18393            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18394            let selection = self.selections.newest::<Point>(&display_map);
18395
18396            let range = if selection.is_empty() {
18397                let point = selection.head().to_display_point(&display_map);
18398                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18399                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18400                    .to_point(&display_map);
18401                start..end
18402            } else {
18403                selection.range()
18404            };
18405            if display_map.folds_in_range(range).next().is_some() {
18406                self.unfold_lines(&Default::default(), window, cx)
18407            } else {
18408                self.fold(&Default::default(), window, cx)
18409            }
18410        } else {
18411            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18412            let buffer_ids: HashSet<_> = self
18413                .selections
18414                .disjoint_anchor_ranges()
18415                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18416                .collect();
18417
18418            let should_unfold = buffer_ids
18419                .iter()
18420                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18421
18422            for buffer_id in buffer_ids {
18423                if should_unfold {
18424                    self.unfold_buffer(buffer_id, cx);
18425                } else {
18426                    self.fold_buffer(buffer_id, cx);
18427                }
18428            }
18429        }
18430    }
18431
18432    pub fn toggle_fold_recursive(
18433        &mut self,
18434        _: &actions::ToggleFoldRecursive,
18435        window: &mut Window,
18436        cx: &mut Context<Self>,
18437    ) {
18438        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18439
18440        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18441        let range = if selection.is_empty() {
18442            let point = selection.head().to_display_point(&display_map);
18443            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18444            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18445                .to_point(&display_map);
18446            start..end
18447        } else {
18448            selection.range()
18449        };
18450        if display_map.folds_in_range(range).next().is_some() {
18451            self.unfold_recursive(&Default::default(), window, cx)
18452        } else {
18453            self.fold_recursive(&Default::default(), window, cx)
18454        }
18455    }
18456
18457    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18458        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18459            let mut to_fold = Vec::new();
18460            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18461            let selections = self.selections.all_adjusted(&display_map);
18462
18463            for selection in selections {
18464                let range = selection.range().sorted();
18465                let buffer_start_row = range.start.row;
18466
18467                if range.start.row != range.end.row {
18468                    let mut found = false;
18469                    let mut row = range.start.row;
18470                    while row <= range.end.row {
18471                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18472                        {
18473                            found = true;
18474                            row = crease.range().end.row + 1;
18475                            to_fold.push(crease);
18476                        } else {
18477                            row += 1
18478                        }
18479                    }
18480                    if found {
18481                        continue;
18482                    }
18483                }
18484
18485                for row in (0..=range.start.row).rev() {
18486                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18487                        && crease.range().end.row >= buffer_start_row
18488                    {
18489                        to_fold.push(crease);
18490                        if row <= range.start.row {
18491                            break;
18492                        }
18493                    }
18494                }
18495            }
18496
18497            self.fold_creases(to_fold, true, window, cx);
18498        } else {
18499            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18500            let buffer_ids = self
18501                .selections
18502                .disjoint_anchor_ranges()
18503                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18504                .collect::<HashSet<_>>();
18505            for buffer_id in buffer_ids {
18506                self.fold_buffer(buffer_id, cx);
18507            }
18508        }
18509    }
18510
18511    pub fn toggle_fold_all(
18512        &mut self,
18513        _: &actions::ToggleFoldAll,
18514        window: &mut Window,
18515        cx: &mut Context<Self>,
18516    ) {
18517        if self.buffer.read(cx).is_singleton() {
18518            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18519            let has_folds = display_map
18520                .folds_in_range(0..display_map.buffer_snapshot().len())
18521                .next()
18522                .is_some();
18523
18524            if has_folds {
18525                self.unfold_all(&actions::UnfoldAll, window, cx);
18526            } else {
18527                self.fold_all(&actions::FoldAll, window, cx);
18528            }
18529        } else {
18530            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18531            let should_unfold = buffer_ids
18532                .iter()
18533                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18534
18535            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18536                editor
18537                    .update_in(cx, |editor, _, cx| {
18538                        for buffer_id in buffer_ids {
18539                            if should_unfold {
18540                                editor.unfold_buffer(buffer_id, cx);
18541                            } else {
18542                                editor.fold_buffer(buffer_id, cx);
18543                            }
18544                        }
18545                    })
18546                    .ok();
18547            });
18548        }
18549    }
18550
18551    fn fold_at_level(
18552        &mut self,
18553        fold_at: &FoldAtLevel,
18554        window: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) {
18557        if !self.buffer.read(cx).is_singleton() {
18558            return;
18559        }
18560
18561        let fold_at_level = fold_at.0;
18562        let snapshot = self.buffer.read(cx).snapshot(cx);
18563        let mut to_fold = Vec::new();
18564        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18565
18566        let row_ranges_to_keep: Vec<Range<u32>> = self
18567            .selections
18568            .all::<Point>(&self.display_snapshot(cx))
18569            .into_iter()
18570            .map(|sel| sel.start.row..sel.end.row)
18571            .collect();
18572
18573        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18574            while start_row < end_row {
18575                match self
18576                    .snapshot(window, cx)
18577                    .crease_for_buffer_row(MultiBufferRow(start_row))
18578                {
18579                    Some(crease) => {
18580                        let nested_start_row = crease.range().start.row + 1;
18581                        let nested_end_row = crease.range().end.row;
18582
18583                        if current_level < fold_at_level {
18584                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18585                        } else if current_level == fold_at_level {
18586                            // Fold iff there is no selection completely contained within the fold region
18587                            if !row_ranges_to_keep.iter().any(|selection| {
18588                                selection.end >= nested_start_row
18589                                    && selection.start <= nested_end_row
18590                            }) {
18591                                to_fold.push(crease);
18592                            }
18593                        }
18594
18595                        start_row = nested_end_row + 1;
18596                    }
18597                    None => start_row += 1,
18598                }
18599            }
18600        }
18601
18602        self.fold_creases(to_fold, true, window, cx);
18603    }
18604
18605    pub fn fold_at_level_1(
18606        &mut self,
18607        _: &actions::FoldAtLevel1,
18608        window: &mut Window,
18609        cx: &mut Context<Self>,
18610    ) {
18611        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18612    }
18613
18614    pub fn fold_at_level_2(
18615        &mut self,
18616        _: &actions::FoldAtLevel2,
18617        window: &mut Window,
18618        cx: &mut Context<Self>,
18619    ) {
18620        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18621    }
18622
18623    pub fn fold_at_level_3(
18624        &mut self,
18625        _: &actions::FoldAtLevel3,
18626        window: &mut Window,
18627        cx: &mut Context<Self>,
18628    ) {
18629        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18630    }
18631
18632    pub fn fold_at_level_4(
18633        &mut self,
18634        _: &actions::FoldAtLevel4,
18635        window: &mut Window,
18636        cx: &mut Context<Self>,
18637    ) {
18638        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18639    }
18640
18641    pub fn fold_at_level_5(
18642        &mut self,
18643        _: &actions::FoldAtLevel5,
18644        window: &mut Window,
18645        cx: &mut Context<Self>,
18646    ) {
18647        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18648    }
18649
18650    pub fn fold_at_level_6(
18651        &mut self,
18652        _: &actions::FoldAtLevel6,
18653        window: &mut Window,
18654        cx: &mut Context<Self>,
18655    ) {
18656        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18657    }
18658
18659    pub fn fold_at_level_7(
18660        &mut self,
18661        _: &actions::FoldAtLevel7,
18662        window: &mut Window,
18663        cx: &mut Context<Self>,
18664    ) {
18665        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18666    }
18667
18668    pub fn fold_at_level_8(
18669        &mut self,
18670        _: &actions::FoldAtLevel8,
18671        window: &mut Window,
18672        cx: &mut Context<Self>,
18673    ) {
18674        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18675    }
18676
18677    pub fn fold_at_level_9(
18678        &mut self,
18679        _: &actions::FoldAtLevel9,
18680        window: &mut Window,
18681        cx: &mut Context<Self>,
18682    ) {
18683        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18684    }
18685
18686    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18687        if self.buffer.read(cx).is_singleton() {
18688            let mut fold_ranges = Vec::new();
18689            let snapshot = self.buffer.read(cx).snapshot(cx);
18690
18691            for row in 0..snapshot.max_row().0 {
18692                if let Some(foldable_range) = self
18693                    .snapshot(window, cx)
18694                    .crease_for_buffer_row(MultiBufferRow(row))
18695                {
18696                    fold_ranges.push(foldable_range);
18697                }
18698            }
18699
18700            self.fold_creases(fold_ranges, true, window, cx);
18701        } else {
18702            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18703                editor
18704                    .update_in(cx, |editor, _, cx| {
18705                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18706                            editor.fold_buffer(buffer_id, cx);
18707                        }
18708                    })
18709                    .ok();
18710            });
18711        }
18712    }
18713
18714    pub fn fold_function_bodies(
18715        &mut self,
18716        _: &actions::FoldFunctionBodies,
18717        window: &mut Window,
18718        cx: &mut Context<Self>,
18719    ) {
18720        let snapshot = self.buffer.read(cx).snapshot(cx);
18721
18722        let ranges = snapshot
18723            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18724            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18725            .collect::<Vec<_>>();
18726
18727        let creases = ranges
18728            .into_iter()
18729            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18730            .collect();
18731
18732        self.fold_creases(creases, true, window, cx);
18733    }
18734
18735    pub fn fold_recursive(
18736        &mut self,
18737        _: &actions::FoldRecursive,
18738        window: &mut Window,
18739        cx: &mut Context<Self>,
18740    ) {
18741        let mut to_fold = Vec::new();
18742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18743        let selections = self.selections.all_adjusted(&display_map);
18744
18745        for selection in selections {
18746            let range = selection.range().sorted();
18747            let buffer_start_row = range.start.row;
18748
18749            if range.start.row != range.end.row {
18750                let mut found = false;
18751                for row in range.start.row..=range.end.row {
18752                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18753                        found = true;
18754                        to_fold.push(crease);
18755                    }
18756                }
18757                if found {
18758                    continue;
18759                }
18760            }
18761
18762            for row in (0..=range.start.row).rev() {
18763                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18764                    if crease.range().end.row >= buffer_start_row {
18765                        to_fold.push(crease);
18766                    } else {
18767                        break;
18768                    }
18769                }
18770            }
18771        }
18772
18773        self.fold_creases(to_fold, true, window, cx);
18774    }
18775
18776    pub fn fold_at(
18777        &mut self,
18778        buffer_row: MultiBufferRow,
18779        window: &mut Window,
18780        cx: &mut Context<Self>,
18781    ) {
18782        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18783
18784        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18785            let autoscroll = self
18786                .selections
18787                .all::<Point>(&display_map)
18788                .iter()
18789                .any(|selection| crease.range().overlaps(&selection.range()));
18790
18791            self.fold_creases(vec![crease], autoscroll, window, cx);
18792        }
18793    }
18794
18795    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18796        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18797            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18798            let buffer = display_map.buffer_snapshot();
18799            let selections = self.selections.all::<Point>(&display_map);
18800            let ranges = selections
18801                .iter()
18802                .map(|s| {
18803                    let range = s.display_range(&display_map).sorted();
18804                    let mut start = range.start.to_point(&display_map);
18805                    let mut end = range.end.to_point(&display_map);
18806                    start.column = 0;
18807                    end.column = buffer.line_len(MultiBufferRow(end.row));
18808                    start..end
18809                })
18810                .collect::<Vec<_>>();
18811
18812            self.unfold_ranges(&ranges, true, true, cx);
18813        } else {
18814            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18815            let buffer_ids = self
18816                .selections
18817                .disjoint_anchor_ranges()
18818                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18819                .collect::<HashSet<_>>();
18820            for buffer_id in buffer_ids {
18821                self.unfold_buffer(buffer_id, cx);
18822            }
18823        }
18824    }
18825
18826    pub fn unfold_recursive(
18827        &mut self,
18828        _: &UnfoldRecursive,
18829        _window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) {
18832        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18833        let selections = self.selections.all::<Point>(&display_map);
18834        let ranges = selections
18835            .iter()
18836            .map(|s| {
18837                let mut range = s.display_range(&display_map).sorted();
18838                *range.start.column_mut() = 0;
18839                *range.end.column_mut() = display_map.line_len(range.end.row());
18840                let start = range.start.to_point(&display_map);
18841                let end = range.end.to_point(&display_map);
18842                start..end
18843            })
18844            .collect::<Vec<_>>();
18845
18846        self.unfold_ranges(&ranges, true, true, cx);
18847    }
18848
18849    pub fn unfold_at(
18850        &mut self,
18851        buffer_row: MultiBufferRow,
18852        _window: &mut Window,
18853        cx: &mut Context<Self>,
18854    ) {
18855        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18856
18857        let intersection_range = Point::new(buffer_row.0, 0)
18858            ..Point::new(
18859                buffer_row.0,
18860                display_map.buffer_snapshot().line_len(buffer_row),
18861            );
18862
18863        let autoscroll = self
18864            .selections
18865            .all::<Point>(&display_map)
18866            .iter()
18867            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18868
18869        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18870    }
18871
18872    pub fn unfold_all(
18873        &mut self,
18874        _: &actions::UnfoldAll,
18875        _window: &mut Window,
18876        cx: &mut Context<Self>,
18877    ) {
18878        if self.buffer.read(cx).is_singleton() {
18879            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18880            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18881        } else {
18882            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18883                editor
18884                    .update(cx, |editor, cx| {
18885                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18886                            editor.unfold_buffer(buffer_id, cx);
18887                        }
18888                    })
18889                    .ok();
18890            });
18891        }
18892    }
18893
18894    pub fn fold_selected_ranges(
18895        &mut self,
18896        _: &FoldSelectedRanges,
18897        window: &mut Window,
18898        cx: &mut Context<Self>,
18899    ) {
18900        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18901        let selections = self.selections.all_adjusted(&display_map);
18902        let ranges = selections
18903            .into_iter()
18904            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18905            .collect::<Vec<_>>();
18906        self.fold_creases(ranges, true, window, cx);
18907    }
18908
18909    pub fn fold_ranges<T: ToOffset + Clone>(
18910        &mut self,
18911        ranges: Vec<Range<T>>,
18912        auto_scroll: bool,
18913        window: &mut Window,
18914        cx: &mut Context<Self>,
18915    ) {
18916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18917        let ranges = ranges
18918            .into_iter()
18919            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18920            .collect::<Vec<_>>();
18921        self.fold_creases(ranges, auto_scroll, window, cx);
18922    }
18923
18924    pub fn fold_creases<T: ToOffset + Clone>(
18925        &mut self,
18926        creases: Vec<Crease<T>>,
18927        auto_scroll: bool,
18928        _window: &mut Window,
18929        cx: &mut Context<Self>,
18930    ) {
18931        if creases.is_empty() {
18932            return;
18933        }
18934
18935        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18936
18937        if auto_scroll {
18938            self.request_autoscroll(Autoscroll::fit(), cx);
18939        }
18940
18941        cx.notify();
18942
18943        self.scrollbar_marker_state.dirty = true;
18944        self.folds_did_change(cx);
18945    }
18946
18947    /// Removes any folds whose ranges intersect any of the given ranges.
18948    pub fn unfold_ranges<T: ToOffset + Clone>(
18949        &mut self,
18950        ranges: &[Range<T>],
18951        inclusive: bool,
18952        auto_scroll: bool,
18953        cx: &mut Context<Self>,
18954    ) {
18955        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18956            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18957        });
18958        self.folds_did_change(cx);
18959    }
18960
18961    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18962        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18963            return;
18964        }
18965
18966        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18967        self.display_map.update(cx, |display_map, cx| {
18968            display_map.fold_buffers([buffer_id], cx)
18969        });
18970
18971        let snapshot = self.display_snapshot(cx);
18972        self.selections.change_with(&snapshot, |selections| {
18973            selections.remove_selections_from_buffer(buffer_id);
18974        });
18975
18976        cx.emit(EditorEvent::BufferFoldToggled {
18977            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18978            folded: true,
18979        });
18980        cx.notify();
18981    }
18982
18983    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18984        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18985            return;
18986        }
18987        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18988        self.display_map.update(cx, |display_map, cx| {
18989            display_map.unfold_buffers([buffer_id], cx);
18990        });
18991        cx.emit(EditorEvent::BufferFoldToggled {
18992            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18993            folded: false,
18994        });
18995        cx.notify();
18996    }
18997
18998    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18999        self.display_map.read(cx).is_buffer_folded(buffer)
19000    }
19001
19002    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19003        self.display_map.read(cx).folded_buffers()
19004    }
19005
19006    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19007        self.display_map.update(cx, |display_map, cx| {
19008            display_map.disable_header_for_buffer(buffer_id, cx);
19009        });
19010        cx.notify();
19011    }
19012
19013    /// Removes any folds with the given ranges.
19014    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19015        &mut self,
19016        ranges: &[Range<T>],
19017        type_id: TypeId,
19018        auto_scroll: bool,
19019        cx: &mut Context<Self>,
19020    ) {
19021        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19022            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19023        });
19024        self.folds_did_change(cx);
19025    }
19026
19027    fn remove_folds_with<T: ToOffset + Clone>(
19028        &mut self,
19029        ranges: &[Range<T>],
19030        auto_scroll: bool,
19031        cx: &mut Context<Self>,
19032        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19033    ) {
19034        if ranges.is_empty() {
19035            return;
19036        }
19037
19038        let mut buffers_affected = HashSet::default();
19039        let multi_buffer = self.buffer().read(cx);
19040        for range in ranges {
19041            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19042                buffers_affected.insert(buffer.read(cx).remote_id());
19043            };
19044        }
19045
19046        self.display_map.update(cx, update);
19047
19048        if auto_scroll {
19049            self.request_autoscroll(Autoscroll::fit(), cx);
19050        }
19051
19052        cx.notify();
19053        self.scrollbar_marker_state.dirty = true;
19054        self.active_indent_guides_state.dirty = true;
19055    }
19056
19057    pub fn update_renderer_widths(
19058        &mut self,
19059        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19060        cx: &mut Context<Self>,
19061    ) -> bool {
19062        self.display_map
19063            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19064    }
19065
19066    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19067        self.display_map.read(cx).fold_placeholder.clone()
19068    }
19069
19070    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19071        self.buffer.update(cx, |buffer, cx| {
19072            buffer.set_all_diff_hunks_expanded(cx);
19073        });
19074    }
19075
19076    pub fn expand_all_diff_hunks(
19077        &mut self,
19078        _: &ExpandAllDiffHunks,
19079        _window: &mut Window,
19080        cx: &mut Context<Self>,
19081    ) {
19082        self.buffer.update(cx, |buffer, cx| {
19083            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19084        });
19085    }
19086
19087    pub fn collapse_all_diff_hunks(
19088        &mut self,
19089        _: &CollapseAllDiffHunks,
19090        _window: &mut Window,
19091        cx: &mut Context<Self>,
19092    ) {
19093        self.buffer.update(cx, |buffer, cx| {
19094            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19095        });
19096    }
19097
19098    pub fn toggle_selected_diff_hunks(
19099        &mut self,
19100        _: &ToggleSelectedDiffHunks,
19101        _window: &mut Window,
19102        cx: &mut Context<Self>,
19103    ) {
19104        let ranges: Vec<_> = self
19105            .selections
19106            .disjoint_anchors()
19107            .iter()
19108            .map(|s| s.range())
19109            .collect();
19110        self.toggle_diff_hunks_in_ranges(ranges, cx);
19111    }
19112
19113    pub fn diff_hunks_in_ranges<'a>(
19114        &'a self,
19115        ranges: &'a [Range<Anchor>],
19116        buffer: &'a MultiBufferSnapshot,
19117    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19118        ranges.iter().flat_map(move |range| {
19119            let end_excerpt_id = range.end.excerpt_id;
19120            let range = range.to_point(buffer);
19121            let mut peek_end = range.end;
19122            if range.end.row < buffer.max_row().0 {
19123                peek_end = Point::new(range.end.row + 1, 0);
19124            }
19125            buffer
19126                .diff_hunks_in_range(range.start..peek_end)
19127                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19128        })
19129    }
19130
19131    pub fn has_stageable_diff_hunks_in_ranges(
19132        &self,
19133        ranges: &[Range<Anchor>],
19134        snapshot: &MultiBufferSnapshot,
19135    ) -> bool {
19136        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19137        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19138    }
19139
19140    pub fn toggle_staged_selected_diff_hunks(
19141        &mut self,
19142        _: &::git::ToggleStaged,
19143        _: &mut Window,
19144        cx: &mut Context<Self>,
19145    ) {
19146        let snapshot = self.buffer.read(cx).snapshot(cx);
19147        let ranges: Vec<_> = self
19148            .selections
19149            .disjoint_anchors()
19150            .iter()
19151            .map(|s| s.range())
19152            .collect();
19153        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19154        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19155    }
19156
19157    pub fn set_render_diff_hunk_controls(
19158        &mut self,
19159        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19160        cx: &mut Context<Self>,
19161    ) {
19162        self.render_diff_hunk_controls = render_diff_hunk_controls;
19163        cx.notify();
19164    }
19165
19166    pub fn stage_and_next(
19167        &mut self,
19168        _: &::git::StageAndNext,
19169        window: &mut Window,
19170        cx: &mut Context<Self>,
19171    ) {
19172        self.do_stage_or_unstage_and_next(true, window, cx);
19173    }
19174
19175    pub fn unstage_and_next(
19176        &mut self,
19177        _: &::git::UnstageAndNext,
19178        window: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) {
19181        self.do_stage_or_unstage_and_next(false, window, cx);
19182    }
19183
19184    pub fn stage_or_unstage_diff_hunks(
19185        &mut self,
19186        stage: bool,
19187        ranges: Vec<Range<Anchor>>,
19188        cx: &mut Context<Self>,
19189    ) {
19190        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19191        cx.spawn(async move |this, cx| {
19192            task.await?;
19193            this.update(cx, |this, cx| {
19194                let snapshot = this.buffer.read(cx).snapshot(cx);
19195                let chunk_by = this
19196                    .diff_hunks_in_ranges(&ranges, &snapshot)
19197                    .chunk_by(|hunk| hunk.buffer_id);
19198                for (buffer_id, hunks) in &chunk_by {
19199                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19200                }
19201            })
19202        })
19203        .detach_and_log_err(cx);
19204    }
19205
19206    fn save_buffers_for_ranges_if_needed(
19207        &mut self,
19208        ranges: &[Range<Anchor>],
19209        cx: &mut Context<Editor>,
19210    ) -> Task<Result<()>> {
19211        let multibuffer = self.buffer.read(cx);
19212        let snapshot = multibuffer.read(cx);
19213        let buffer_ids: HashSet<_> = ranges
19214            .iter()
19215            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19216            .collect();
19217        drop(snapshot);
19218
19219        let mut buffers = HashSet::default();
19220        for buffer_id in buffer_ids {
19221            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19222                let buffer = buffer_entity.read(cx);
19223                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19224                {
19225                    buffers.insert(buffer_entity);
19226                }
19227            }
19228        }
19229
19230        if let Some(project) = &self.project {
19231            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19232        } else {
19233            Task::ready(Ok(()))
19234        }
19235    }
19236
19237    fn do_stage_or_unstage_and_next(
19238        &mut self,
19239        stage: bool,
19240        window: &mut Window,
19241        cx: &mut Context<Self>,
19242    ) {
19243        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19244
19245        if ranges.iter().any(|range| range.start != range.end) {
19246            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19247            return;
19248        }
19249
19250        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19251        let snapshot = self.snapshot(window, cx);
19252        let position = self
19253            .selections
19254            .newest::<Point>(&snapshot.display_snapshot)
19255            .head();
19256        let mut row = snapshot
19257            .buffer_snapshot()
19258            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19259            .find(|hunk| hunk.row_range.start.0 > position.row)
19260            .map(|hunk| hunk.row_range.start);
19261
19262        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19263        // Outside of the project diff editor, wrap around to the beginning.
19264        if !all_diff_hunks_expanded {
19265            row = row.or_else(|| {
19266                snapshot
19267                    .buffer_snapshot()
19268                    .diff_hunks_in_range(Point::zero()..position)
19269                    .find(|hunk| hunk.row_range.end.0 < position.row)
19270                    .map(|hunk| hunk.row_range.start)
19271            });
19272        }
19273
19274        if let Some(row) = row {
19275            let destination = Point::new(row.0, 0);
19276            let autoscroll = Autoscroll::center();
19277
19278            self.unfold_ranges(&[destination..destination], false, false, cx);
19279            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19280                s.select_ranges([destination..destination]);
19281            });
19282        }
19283    }
19284
19285    fn do_stage_or_unstage(
19286        &self,
19287        stage: bool,
19288        buffer_id: BufferId,
19289        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19290        cx: &mut App,
19291    ) -> Option<()> {
19292        let project = self.project()?;
19293        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19294        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19295        let buffer_snapshot = buffer.read(cx).snapshot();
19296        let file_exists = buffer_snapshot
19297            .file()
19298            .is_some_and(|file| file.disk_state().exists());
19299        diff.update(cx, |diff, cx| {
19300            diff.stage_or_unstage_hunks(
19301                stage,
19302                &hunks
19303                    .map(|hunk| buffer_diff::DiffHunk {
19304                        buffer_range: hunk.buffer_range,
19305                        diff_base_byte_range: hunk.diff_base_byte_range,
19306                        secondary_status: hunk.secondary_status,
19307                        range: Point::zero()..Point::zero(), // unused
19308                    })
19309                    .collect::<Vec<_>>(),
19310                &buffer_snapshot,
19311                file_exists,
19312                cx,
19313            )
19314        });
19315        None
19316    }
19317
19318    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19319        let ranges: Vec<_> = self
19320            .selections
19321            .disjoint_anchors()
19322            .iter()
19323            .map(|s| s.range())
19324            .collect();
19325        self.buffer
19326            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19327    }
19328
19329    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19330        self.buffer.update(cx, |buffer, cx| {
19331            let ranges = vec![Anchor::min()..Anchor::max()];
19332            if !buffer.all_diff_hunks_expanded()
19333                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19334            {
19335                buffer.collapse_diff_hunks(ranges, cx);
19336                true
19337            } else {
19338                false
19339            }
19340        })
19341    }
19342
19343    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19344        if self.buffer.read(cx).all_diff_hunks_expanded() {
19345            return true;
19346        }
19347        let ranges = vec![Anchor::min()..Anchor::max()];
19348        self.buffer
19349            .read(cx)
19350            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19351    }
19352
19353    fn toggle_diff_hunks_in_ranges(
19354        &mut self,
19355        ranges: Vec<Range<Anchor>>,
19356        cx: &mut Context<Editor>,
19357    ) {
19358        self.buffer.update(cx, |buffer, cx| {
19359            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19360            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19361        })
19362    }
19363
19364    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19365        self.buffer.update(cx, |buffer, cx| {
19366            let snapshot = buffer.snapshot(cx);
19367            let excerpt_id = range.end.excerpt_id;
19368            let point_range = range.to_point(&snapshot);
19369            let expand = !buffer.single_hunk_is_expanded(range, cx);
19370            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19371        })
19372    }
19373
19374    pub(crate) fn apply_all_diff_hunks(
19375        &mut self,
19376        _: &ApplyAllDiffHunks,
19377        window: &mut Window,
19378        cx: &mut Context<Self>,
19379    ) {
19380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19381
19382        let buffers = self.buffer.read(cx).all_buffers();
19383        for branch_buffer in buffers {
19384            branch_buffer.update(cx, |branch_buffer, cx| {
19385                branch_buffer.merge_into_base(Vec::new(), cx);
19386            });
19387        }
19388
19389        if let Some(project) = self.project.clone() {
19390            self.save(
19391                SaveOptions {
19392                    format: true,
19393                    autosave: false,
19394                },
19395                project,
19396                window,
19397                cx,
19398            )
19399            .detach_and_log_err(cx);
19400        }
19401    }
19402
19403    pub(crate) fn apply_selected_diff_hunks(
19404        &mut self,
19405        _: &ApplyDiffHunk,
19406        window: &mut Window,
19407        cx: &mut Context<Self>,
19408    ) {
19409        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19410        let snapshot = self.snapshot(window, cx);
19411        let hunks = snapshot.hunks_for_ranges(
19412            self.selections
19413                .all(&snapshot.display_snapshot)
19414                .into_iter()
19415                .map(|selection| selection.range()),
19416        );
19417        let mut ranges_by_buffer = HashMap::default();
19418        self.transact(window, cx, |editor, _window, cx| {
19419            for hunk in hunks {
19420                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19421                    ranges_by_buffer
19422                        .entry(buffer.clone())
19423                        .or_insert_with(Vec::new)
19424                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19425                }
19426            }
19427
19428            for (buffer, ranges) in ranges_by_buffer {
19429                buffer.update(cx, |buffer, cx| {
19430                    buffer.merge_into_base(ranges, cx);
19431                });
19432            }
19433        });
19434
19435        if let Some(project) = self.project.clone() {
19436            self.save(
19437                SaveOptions {
19438                    format: true,
19439                    autosave: false,
19440                },
19441                project,
19442                window,
19443                cx,
19444            )
19445            .detach_and_log_err(cx);
19446        }
19447    }
19448
19449    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19450        if hovered != self.gutter_hovered {
19451            self.gutter_hovered = hovered;
19452            cx.notify();
19453        }
19454    }
19455
19456    pub fn insert_blocks(
19457        &mut self,
19458        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19459        autoscroll: Option<Autoscroll>,
19460        cx: &mut Context<Self>,
19461    ) -> Vec<CustomBlockId> {
19462        let blocks = self
19463            .display_map
19464            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19465        if let Some(autoscroll) = autoscroll {
19466            self.request_autoscroll(autoscroll, cx);
19467        }
19468        cx.notify();
19469        blocks
19470    }
19471
19472    pub fn resize_blocks(
19473        &mut self,
19474        heights: HashMap<CustomBlockId, u32>,
19475        autoscroll: Option<Autoscroll>,
19476        cx: &mut Context<Self>,
19477    ) {
19478        self.display_map
19479            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19480        if let Some(autoscroll) = autoscroll {
19481            self.request_autoscroll(autoscroll, cx);
19482        }
19483        cx.notify();
19484    }
19485
19486    pub fn replace_blocks(
19487        &mut self,
19488        renderers: HashMap<CustomBlockId, RenderBlock>,
19489        autoscroll: Option<Autoscroll>,
19490        cx: &mut Context<Self>,
19491    ) {
19492        self.display_map
19493            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19494        if let Some(autoscroll) = autoscroll {
19495            self.request_autoscroll(autoscroll, cx);
19496        }
19497        cx.notify();
19498    }
19499
19500    pub fn remove_blocks(
19501        &mut self,
19502        block_ids: HashSet<CustomBlockId>,
19503        autoscroll: Option<Autoscroll>,
19504        cx: &mut Context<Self>,
19505    ) {
19506        self.display_map.update(cx, |display_map, cx| {
19507            display_map.remove_blocks(block_ids, cx)
19508        });
19509        if let Some(autoscroll) = autoscroll {
19510            self.request_autoscroll(autoscroll, cx);
19511        }
19512        cx.notify();
19513    }
19514
19515    pub fn row_for_block(
19516        &self,
19517        block_id: CustomBlockId,
19518        cx: &mut Context<Self>,
19519    ) -> Option<DisplayRow> {
19520        self.display_map
19521            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19522    }
19523
19524    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19525        self.focused_block = Some(focused_block);
19526    }
19527
19528    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19529        self.focused_block.take()
19530    }
19531
19532    pub fn insert_creases(
19533        &mut self,
19534        creases: impl IntoIterator<Item = Crease<Anchor>>,
19535        cx: &mut Context<Self>,
19536    ) -> Vec<CreaseId> {
19537        self.display_map
19538            .update(cx, |map, cx| map.insert_creases(creases, cx))
19539    }
19540
19541    pub fn remove_creases(
19542        &mut self,
19543        ids: impl IntoIterator<Item = CreaseId>,
19544        cx: &mut Context<Self>,
19545    ) -> Vec<(CreaseId, Range<Anchor>)> {
19546        self.display_map
19547            .update(cx, |map, cx| map.remove_creases(ids, cx))
19548    }
19549
19550    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19551        self.display_map
19552            .update(cx, |map, cx| map.snapshot(cx))
19553            .longest_row()
19554    }
19555
19556    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19557        self.display_map
19558            .update(cx, |map, cx| map.snapshot(cx))
19559            .max_point()
19560    }
19561
19562    pub fn text(&self, cx: &App) -> String {
19563        self.buffer.read(cx).read(cx).text()
19564    }
19565
19566    pub fn is_empty(&self, cx: &App) -> bool {
19567        self.buffer.read(cx).read(cx).is_empty()
19568    }
19569
19570    pub fn text_option(&self, cx: &App) -> Option<String> {
19571        let text = self.text(cx);
19572        let text = text.trim();
19573
19574        if text.is_empty() {
19575            return None;
19576        }
19577
19578        Some(text.to_string())
19579    }
19580
19581    pub fn set_text(
19582        &mut self,
19583        text: impl Into<Arc<str>>,
19584        window: &mut Window,
19585        cx: &mut Context<Self>,
19586    ) {
19587        self.transact(window, cx, |this, _, cx| {
19588            this.buffer
19589                .read(cx)
19590                .as_singleton()
19591                .expect("you can only call set_text on editors for singleton buffers")
19592                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19593        });
19594    }
19595
19596    pub fn display_text(&self, cx: &mut App) -> String {
19597        self.display_map
19598            .update(cx, |map, cx| map.snapshot(cx))
19599            .text()
19600    }
19601
19602    fn create_minimap(
19603        &self,
19604        minimap_settings: MinimapSettings,
19605        window: &mut Window,
19606        cx: &mut Context<Self>,
19607    ) -> Option<Entity<Self>> {
19608        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19609            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19610    }
19611
19612    fn initialize_new_minimap(
19613        &self,
19614        minimap_settings: MinimapSettings,
19615        window: &mut Window,
19616        cx: &mut Context<Self>,
19617    ) -> Entity<Self> {
19618        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19619
19620        let mut minimap = Editor::new_internal(
19621            EditorMode::Minimap {
19622                parent: cx.weak_entity(),
19623            },
19624            self.buffer.clone(),
19625            None,
19626            Some(self.display_map.clone()),
19627            window,
19628            cx,
19629        );
19630        minimap.scroll_manager.clone_state(&self.scroll_manager);
19631        minimap.set_text_style_refinement(TextStyleRefinement {
19632            font_size: Some(MINIMAP_FONT_SIZE),
19633            font_weight: Some(MINIMAP_FONT_WEIGHT),
19634            ..Default::default()
19635        });
19636        minimap.update_minimap_configuration(minimap_settings, cx);
19637        cx.new(|_| minimap)
19638    }
19639
19640    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19641        let current_line_highlight = minimap_settings
19642            .current_line_highlight
19643            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19644        self.set_current_line_highlight(Some(current_line_highlight));
19645    }
19646
19647    pub fn minimap(&self) -> Option<&Entity<Self>> {
19648        self.minimap
19649            .as_ref()
19650            .filter(|_| self.minimap_visibility.visible())
19651    }
19652
19653    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19654        let mut wrap_guides = smallvec![];
19655
19656        if self.show_wrap_guides == Some(false) {
19657            return wrap_guides;
19658        }
19659
19660        let settings = self.buffer.read(cx).language_settings(cx);
19661        if settings.show_wrap_guides {
19662            match self.soft_wrap_mode(cx) {
19663                SoftWrap::Column(soft_wrap) => {
19664                    wrap_guides.push((soft_wrap as usize, true));
19665                }
19666                SoftWrap::Bounded(soft_wrap) => {
19667                    wrap_guides.push((soft_wrap as usize, true));
19668                }
19669                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19670            }
19671            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19672        }
19673
19674        wrap_guides
19675    }
19676
19677    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19678        let settings = self.buffer.read(cx).language_settings(cx);
19679        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19680        match mode {
19681            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19682                SoftWrap::None
19683            }
19684            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19685            language_settings::SoftWrap::PreferredLineLength => {
19686                SoftWrap::Column(settings.preferred_line_length)
19687            }
19688            language_settings::SoftWrap::Bounded => {
19689                SoftWrap::Bounded(settings.preferred_line_length)
19690            }
19691        }
19692    }
19693
19694    pub fn set_soft_wrap_mode(
19695        &mut self,
19696        mode: language_settings::SoftWrap,
19697
19698        cx: &mut Context<Self>,
19699    ) {
19700        self.soft_wrap_mode_override = Some(mode);
19701        cx.notify();
19702    }
19703
19704    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19705        self.hard_wrap = hard_wrap;
19706        cx.notify();
19707    }
19708
19709    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19710        self.text_style_refinement = Some(style);
19711    }
19712
19713    /// called by the Element so we know what style we were most recently rendered with.
19714    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19715        // We intentionally do not inform the display map about the minimap style
19716        // so that wrapping is not recalculated and stays consistent for the editor
19717        // and its linked minimap.
19718        if !self.mode.is_minimap() {
19719            let font = style.text.font();
19720            let font_size = style.text.font_size.to_pixels(window.rem_size());
19721            let display_map = self
19722                .placeholder_display_map
19723                .as_ref()
19724                .filter(|_| self.is_empty(cx))
19725                .unwrap_or(&self.display_map);
19726
19727            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19728        }
19729        self.style = Some(style);
19730    }
19731
19732    pub fn style(&self) -> Option<&EditorStyle> {
19733        self.style.as_ref()
19734    }
19735
19736    // Called by the element. This method is not designed to be called outside of the editor
19737    // element's layout code because it does not notify when rewrapping is computed synchronously.
19738    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19739        if self.is_empty(cx) {
19740            self.placeholder_display_map
19741                .as_ref()
19742                .map_or(false, |display_map| {
19743                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19744                })
19745        } else {
19746            self.display_map
19747                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19748        }
19749    }
19750
19751    pub fn set_soft_wrap(&mut self) {
19752        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19753    }
19754
19755    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19756        if self.soft_wrap_mode_override.is_some() {
19757            self.soft_wrap_mode_override.take();
19758        } else {
19759            let soft_wrap = match self.soft_wrap_mode(cx) {
19760                SoftWrap::GitDiff => return,
19761                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19762                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19763                    language_settings::SoftWrap::None
19764                }
19765            };
19766            self.soft_wrap_mode_override = Some(soft_wrap);
19767        }
19768        cx.notify();
19769    }
19770
19771    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19772        let Some(workspace) = self.workspace() else {
19773            return;
19774        };
19775        let fs = workspace.read(cx).app_state().fs.clone();
19776        let current_show = TabBarSettings::get_global(cx).show;
19777        update_settings_file(fs, cx, move |setting, _| {
19778            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19779        });
19780    }
19781
19782    pub fn toggle_indent_guides(
19783        &mut self,
19784        _: &ToggleIndentGuides,
19785        _: &mut Window,
19786        cx: &mut Context<Self>,
19787    ) {
19788        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19789            self.buffer
19790                .read(cx)
19791                .language_settings(cx)
19792                .indent_guides
19793                .enabled
19794        });
19795        self.show_indent_guides = Some(!currently_enabled);
19796        cx.notify();
19797    }
19798
19799    fn should_show_indent_guides(&self) -> Option<bool> {
19800        self.show_indent_guides
19801    }
19802
19803    pub fn toggle_line_numbers(
19804        &mut self,
19805        _: &ToggleLineNumbers,
19806        _: &mut Window,
19807        cx: &mut Context<Self>,
19808    ) {
19809        let mut editor_settings = EditorSettings::get_global(cx).clone();
19810        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19811        EditorSettings::override_global(editor_settings, cx);
19812    }
19813
19814    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19815        if let Some(show_line_numbers) = self.show_line_numbers {
19816            return show_line_numbers;
19817        }
19818        EditorSettings::get_global(cx).gutter.line_numbers
19819    }
19820
19821    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19822        match (
19823            self.use_relative_line_numbers,
19824            EditorSettings::get_global(cx).relative_line_numbers,
19825        ) {
19826            (None, setting) => setting,
19827            (Some(false), _) => RelativeLineNumbers::Disabled,
19828            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19829            (Some(true), _) => RelativeLineNumbers::Enabled,
19830        }
19831    }
19832
19833    pub fn toggle_relative_line_numbers(
19834        &mut self,
19835        _: &ToggleRelativeLineNumbers,
19836        _: &mut Window,
19837        cx: &mut Context<Self>,
19838    ) {
19839        let is_relative = self.relative_line_numbers(cx);
19840        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19841    }
19842
19843    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19844        self.use_relative_line_numbers = is_relative;
19845        cx.notify();
19846    }
19847
19848    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19849        self.show_gutter = show_gutter;
19850        cx.notify();
19851    }
19852
19853    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19854        self.show_scrollbars = ScrollbarAxes {
19855            horizontal: show,
19856            vertical: show,
19857        };
19858        cx.notify();
19859    }
19860
19861    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19862        self.show_scrollbars.vertical = show;
19863        cx.notify();
19864    }
19865
19866    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19867        self.show_scrollbars.horizontal = show;
19868        cx.notify();
19869    }
19870
19871    pub fn set_minimap_visibility(
19872        &mut self,
19873        minimap_visibility: MinimapVisibility,
19874        window: &mut Window,
19875        cx: &mut Context<Self>,
19876    ) {
19877        if self.minimap_visibility != minimap_visibility {
19878            if minimap_visibility.visible() && self.minimap.is_none() {
19879                let minimap_settings = EditorSettings::get_global(cx).minimap;
19880                self.minimap =
19881                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19882            }
19883            self.minimap_visibility = minimap_visibility;
19884            cx.notify();
19885        }
19886    }
19887
19888    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19889        self.set_show_scrollbars(false, cx);
19890        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19891    }
19892
19893    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19894        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19895    }
19896
19897    /// Normally the text in full mode and auto height editors is padded on the
19898    /// left side by roughly half a character width for improved hit testing.
19899    ///
19900    /// Use this method to disable this for cases where this is not wanted (e.g.
19901    /// if you want to align the editor text with some other text above or below)
19902    /// or if you want to add this padding to single-line editors.
19903    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19904        self.offset_content = offset_content;
19905        cx.notify();
19906    }
19907
19908    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19909        self.show_line_numbers = Some(show_line_numbers);
19910        cx.notify();
19911    }
19912
19913    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19914        self.disable_expand_excerpt_buttons = true;
19915        cx.notify();
19916    }
19917
19918    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19919        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19920        cx.notify();
19921    }
19922
19923    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19924        self.show_code_actions = Some(show_code_actions);
19925        cx.notify();
19926    }
19927
19928    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19929        self.show_runnables = Some(show_runnables);
19930        cx.notify();
19931    }
19932
19933    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19934        self.show_breakpoints = Some(show_breakpoints);
19935        cx.notify();
19936    }
19937
19938    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19939        if self.display_map.read(cx).masked != masked {
19940            self.display_map.update(cx, |map, _| map.masked = masked);
19941        }
19942        cx.notify()
19943    }
19944
19945    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19946        self.show_wrap_guides = Some(show_wrap_guides);
19947        cx.notify();
19948    }
19949
19950    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19951        self.show_indent_guides = Some(show_indent_guides);
19952        cx.notify();
19953    }
19954
19955    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19956        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19957            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19958                && let Some(dir) = file.abs_path(cx).parent()
19959            {
19960                return Some(dir.to_owned());
19961            }
19962        }
19963
19964        None
19965    }
19966
19967    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19968        self.active_excerpt(cx)?
19969            .1
19970            .read(cx)
19971            .file()
19972            .and_then(|f| f.as_local())
19973    }
19974
19975    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19976        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19977            let buffer = buffer.read(cx);
19978            if let Some(project_path) = buffer.project_path(cx) {
19979                let project = self.project()?.read(cx);
19980                project.absolute_path(&project_path, cx)
19981            } else {
19982                buffer
19983                    .file()
19984                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19985            }
19986        })
19987    }
19988
19989    pub fn reveal_in_finder(
19990        &mut self,
19991        _: &RevealInFileManager,
19992        _window: &mut Window,
19993        cx: &mut Context<Self>,
19994    ) {
19995        if let Some(target) = self.target_file(cx) {
19996            cx.reveal_path(&target.abs_path(cx));
19997        }
19998    }
19999
20000    pub fn copy_path(
20001        &mut self,
20002        _: &zed_actions::workspace::CopyPath,
20003        _window: &mut Window,
20004        cx: &mut Context<Self>,
20005    ) {
20006        if let Some(path) = self.target_file_abs_path(cx)
20007            && let Some(path) = path.to_str()
20008        {
20009            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20010        } else {
20011            cx.propagate();
20012        }
20013    }
20014
20015    pub fn copy_relative_path(
20016        &mut self,
20017        _: &zed_actions::workspace::CopyRelativePath,
20018        _window: &mut Window,
20019        cx: &mut Context<Self>,
20020    ) {
20021        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20022            let project = self.project()?.read(cx);
20023            let path = buffer.read(cx).file()?.path();
20024            let path = path.display(project.path_style(cx));
20025            Some(path)
20026        }) {
20027            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20028        } else {
20029            cx.propagate();
20030        }
20031    }
20032
20033    /// Returns the project path for the editor's buffer, if any buffer is
20034    /// opened in the editor.
20035    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20036        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20037            buffer.read(cx).project_path(cx)
20038        } else {
20039            None
20040        }
20041    }
20042
20043    // Returns true if the editor handled a go-to-line request
20044    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20045        maybe!({
20046            let breakpoint_store = self.breakpoint_store.as_ref()?;
20047
20048            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20049            else {
20050                self.clear_row_highlights::<ActiveDebugLine>();
20051                return None;
20052            };
20053
20054            let position = active_stack_frame.position;
20055            let buffer_id = position.buffer_id?;
20056            let snapshot = self
20057                .project
20058                .as_ref()?
20059                .read(cx)
20060                .buffer_for_id(buffer_id, cx)?
20061                .read(cx)
20062                .snapshot();
20063
20064            let mut handled = false;
20065            for (id, ExcerptRange { context, .. }) in
20066                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20067            {
20068                if context.start.cmp(&position, &snapshot).is_ge()
20069                    || context.end.cmp(&position, &snapshot).is_lt()
20070                {
20071                    continue;
20072                }
20073                let snapshot = self.buffer.read(cx).snapshot(cx);
20074                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20075
20076                handled = true;
20077                self.clear_row_highlights::<ActiveDebugLine>();
20078
20079                self.go_to_line::<ActiveDebugLine>(
20080                    multibuffer_anchor,
20081                    Some(cx.theme().colors().editor_debugger_active_line_background),
20082                    window,
20083                    cx,
20084                );
20085
20086                cx.notify();
20087            }
20088
20089            handled.then_some(())
20090        })
20091        .is_some()
20092    }
20093
20094    pub fn copy_file_name_without_extension(
20095        &mut self,
20096        _: &CopyFileNameWithoutExtension,
20097        _: &mut Window,
20098        cx: &mut Context<Self>,
20099    ) {
20100        if let Some(file) = self.target_file(cx)
20101            && let Some(file_stem) = file.path().file_stem()
20102        {
20103            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20104        }
20105    }
20106
20107    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20108        if let Some(file) = self.target_file(cx)
20109            && let Some(name) = file.path().file_name()
20110        {
20111            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20112        }
20113    }
20114
20115    pub fn toggle_git_blame(
20116        &mut self,
20117        _: &::git::Blame,
20118        window: &mut Window,
20119        cx: &mut Context<Self>,
20120    ) {
20121        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20122
20123        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20124            self.start_git_blame(true, window, cx);
20125        }
20126
20127        cx.notify();
20128    }
20129
20130    pub fn toggle_git_blame_inline(
20131        &mut self,
20132        _: &ToggleGitBlameInline,
20133        window: &mut Window,
20134        cx: &mut Context<Self>,
20135    ) {
20136        self.toggle_git_blame_inline_internal(true, window, cx);
20137        cx.notify();
20138    }
20139
20140    pub fn open_git_blame_commit(
20141        &mut self,
20142        _: &OpenGitBlameCommit,
20143        window: &mut Window,
20144        cx: &mut Context<Self>,
20145    ) {
20146        self.open_git_blame_commit_internal(window, cx);
20147    }
20148
20149    fn open_git_blame_commit_internal(
20150        &mut self,
20151        window: &mut Window,
20152        cx: &mut Context<Self>,
20153    ) -> Option<()> {
20154        let blame = self.blame.as_ref()?;
20155        let snapshot = self.snapshot(window, cx);
20156        let cursor = self
20157            .selections
20158            .newest::<Point>(&snapshot.display_snapshot)
20159            .head();
20160        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20161        let (_, blame_entry) = blame
20162            .update(cx, |blame, cx| {
20163                blame
20164                    .blame_for_rows(
20165                        &[RowInfo {
20166                            buffer_id: Some(buffer.remote_id()),
20167                            buffer_row: Some(point.row),
20168                            ..Default::default()
20169                        }],
20170                        cx,
20171                    )
20172                    .next()
20173            })
20174            .flatten()?;
20175        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20176        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20177        let workspace = self.workspace()?.downgrade();
20178        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20179        None
20180    }
20181
20182    pub fn git_blame_inline_enabled(&self) -> bool {
20183        self.git_blame_inline_enabled
20184    }
20185
20186    pub fn toggle_selection_menu(
20187        &mut self,
20188        _: &ToggleSelectionMenu,
20189        _: &mut Window,
20190        cx: &mut Context<Self>,
20191    ) {
20192        self.show_selection_menu = self
20193            .show_selection_menu
20194            .map(|show_selections_menu| !show_selections_menu)
20195            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20196
20197        cx.notify();
20198    }
20199
20200    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20201        self.show_selection_menu
20202            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20203    }
20204
20205    fn start_git_blame(
20206        &mut self,
20207        user_triggered: bool,
20208        window: &mut Window,
20209        cx: &mut Context<Self>,
20210    ) {
20211        if let Some(project) = self.project() {
20212            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20213                && buffer.read(cx).file().is_none()
20214            {
20215                return;
20216            }
20217
20218            let focused = self.focus_handle(cx).contains_focused(window, cx);
20219
20220            let project = project.clone();
20221            let blame = cx
20222                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20223            self.blame_subscription =
20224                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20225            self.blame = Some(blame);
20226        }
20227    }
20228
20229    fn toggle_git_blame_inline_internal(
20230        &mut self,
20231        user_triggered: bool,
20232        window: &mut Window,
20233        cx: &mut Context<Self>,
20234    ) {
20235        if self.git_blame_inline_enabled {
20236            self.git_blame_inline_enabled = false;
20237            self.show_git_blame_inline = false;
20238            self.show_git_blame_inline_delay_task.take();
20239        } else {
20240            self.git_blame_inline_enabled = true;
20241            self.start_git_blame_inline(user_triggered, window, cx);
20242        }
20243
20244        cx.notify();
20245    }
20246
20247    fn start_git_blame_inline(
20248        &mut self,
20249        user_triggered: bool,
20250        window: &mut Window,
20251        cx: &mut Context<Self>,
20252    ) {
20253        self.start_git_blame(user_triggered, window, cx);
20254
20255        if ProjectSettings::get_global(cx)
20256            .git
20257            .inline_blame_delay()
20258            .is_some()
20259        {
20260            self.start_inline_blame_timer(window, cx);
20261        } else {
20262            self.show_git_blame_inline = true
20263        }
20264    }
20265
20266    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20267        self.blame.as_ref()
20268    }
20269
20270    pub fn show_git_blame_gutter(&self) -> bool {
20271        self.show_git_blame_gutter
20272    }
20273
20274    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20275        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20276    }
20277
20278    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20279        self.show_git_blame_inline
20280            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20281            && !self.newest_selection_head_on_empty_line(cx)
20282            && self.has_blame_entries(cx)
20283    }
20284
20285    fn has_blame_entries(&self, cx: &App) -> bool {
20286        self.blame()
20287            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20288    }
20289
20290    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20291        let cursor_anchor = self.selections.newest_anchor().head();
20292
20293        let snapshot = self.buffer.read(cx).snapshot(cx);
20294        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20295
20296        snapshot.line_len(buffer_row) == 0
20297    }
20298
20299    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20300        let buffer_and_selection = maybe!({
20301            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20302            let selection_range = selection.range();
20303
20304            let multi_buffer = self.buffer().read(cx);
20305            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20306            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20307
20308            let (buffer, range, _) = if selection.reversed {
20309                buffer_ranges.first()
20310            } else {
20311                buffer_ranges.last()
20312            }?;
20313
20314            let selection = text::ToPoint::to_point(&range.start, buffer).row
20315                ..text::ToPoint::to_point(&range.end, buffer).row;
20316            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20317        });
20318
20319        let Some((buffer, selection)) = buffer_and_selection else {
20320            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20321        };
20322
20323        let Some(project) = self.project() else {
20324            return Task::ready(Err(anyhow!("editor does not have project")));
20325        };
20326
20327        project.update(cx, |project, cx| {
20328            project.get_permalink_to_line(&buffer, selection, cx)
20329        })
20330    }
20331
20332    pub fn copy_permalink_to_line(
20333        &mut self,
20334        _: &CopyPermalinkToLine,
20335        window: &mut Window,
20336        cx: &mut Context<Self>,
20337    ) {
20338        let permalink_task = self.get_permalink_to_line(cx);
20339        let workspace = self.workspace();
20340
20341        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20342            Ok(permalink) => {
20343                cx.update(|_, cx| {
20344                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20345                })
20346                .ok();
20347            }
20348            Err(err) => {
20349                let message = format!("Failed to copy permalink: {err}");
20350
20351                anyhow::Result::<()>::Err(err).log_err();
20352
20353                if let Some(workspace) = workspace {
20354                    workspace
20355                        .update_in(cx, |workspace, _, cx| {
20356                            struct CopyPermalinkToLine;
20357
20358                            workspace.show_toast(
20359                                Toast::new(
20360                                    NotificationId::unique::<CopyPermalinkToLine>(),
20361                                    message,
20362                                ),
20363                                cx,
20364                            )
20365                        })
20366                        .ok();
20367                }
20368            }
20369        })
20370        .detach();
20371    }
20372
20373    pub fn copy_file_location(
20374        &mut self,
20375        _: &CopyFileLocation,
20376        _: &mut Window,
20377        cx: &mut Context<Self>,
20378    ) {
20379        let selection = self
20380            .selections
20381            .newest::<Point>(&self.display_snapshot(cx))
20382            .start
20383            .row
20384            + 1;
20385        if let Some(file) = self.target_file(cx) {
20386            let path = file.path().display(file.path_style(cx));
20387            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20388        }
20389    }
20390
20391    pub fn open_permalink_to_line(
20392        &mut self,
20393        _: &OpenPermalinkToLine,
20394        window: &mut Window,
20395        cx: &mut Context<Self>,
20396    ) {
20397        let permalink_task = self.get_permalink_to_line(cx);
20398        let workspace = self.workspace();
20399
20400        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20401            Ok(permalink) => {
20402                cx.update(|_, cx| {
20403                    cx.open_url(permalink.as_ref());
20404                })
20405                .ok();
20406            }
20407            Err(err) => {
20408                let message = format!("Failed to open permalink: {err}");
20409
20410                anyhow::Result::<()>::Err(err).log_err();
20411
20412                if let Some(workspace) = workspace {
20413                    workspace
20414                        .update(cx, |workspace, cx| {
20415                            struct OpenPermalinkToLine;
20416
20417                            workspace.show_toast(
20418                                Toast::new(
20419                                    NotificationId::unique::<OpenPermalinkToLine>(),
20420                                    message,
20421                                ),
20422                                cx,
20423                            )
20424                        })
20425                        .ok();
20426                }
20427            }
20428        })
20429        .detach();
20430    }
20431
20432    pub fn insert_uuid_v4(
20433        &mut self,
20434        _: &InsertUuidV4,
20435        window: &mut Window,
20436        cx: &mut Context<Self>,
20437    ) {
20438        self.insert_uuid(UuidVersion::V4, window, cx);
20439    }
20440
20441    pub fn insert_uuid_v7(
20442        &mut self,
20443        _: &InsertUuidV7,
20444        window: &mut Window,
20445        cx: &mut Context<Self>,
20446    ) {
20447        self.insert_uuid(UuidVersion::V7, window, cx);
20448    }
20449
20450    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20451        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20452        self.transact(window, cx, |this, window, cx| {
20453            let edits = this
20454                .selections
20455                .all::<Point>(&this.display_snapshot(cx))
20456                .into_iter()
20457                .map(|selection| {
20458                    let uuid = match version {
20459                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20460                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20461                    };
20462
20463                    (selection.range(), uuid.to_string())
20464                });
20465            this.edit(edits, cx);
20466            this.refresh_edit_prediction(true, false, window, cx);
20467        });
20468    }
20469
20470    pub fn open_selections_in_multibuffer(
20471        &mut self,
20472        _: &OpenSelectionsInMultibuffer,
20473        window: &mut Window,
20474        cx: &mut Context<Self>,
20475    ) {
20476        let multibuffer = self.buffer.read(cx);
20477
20478        let Some(buffer) = multibuffer.as_singleton() else {
20479            return;
20480        };
20481
20482        let Some(workspace) = self.workspace() else {
20483            return;
20484        };
20485
20486        let title = multibuffer.title(cx).to_string();
20487
20488        let locations = self
20489            .selections
20490            .all_anchors(&self.display_snapshot(cx))
20491            .iter()
20492            .map(|selection| {
20493                (
20494                    buffer.clone(),
20495                    (selection.start.text_anchor..selection.end.text_anchor)
20496                        .to_point(buffer.read(cx)),
20497                )
20498            })
20499            .into_group_map();
20500
20501        cx.spawn_in(window, async move |_, cx| {
20502            workspace.update_in(cx, |workspace, window, cx| {
20503                Self::open_locations_in_multibuffer(
20504                    workspace,
20505                    locations,
20506                    format!("Selections for '{title}'"),
20507                    false,
20508                    MultibufferSelectionMode::All,
20509                    window,
20510                    cx,
20511                );
20512            })
20513        })
20514        .detach();
20515    }
20516
20517    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20518    /// last highlight added will be used.
20519    ///
20520    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20521    pub fn highlight_rows<T: 'static>(
20522        &mut self,
20523        range: Range<Anchor>,
20524        color: Hsla,
20525        options: RowHighlightOptions,
20526        cx: &mut Context<Self>,
20527    ) {
20528        let snapshot = self.buffer().read(cx).snapshot(cx);
20529        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20530        let ix = row_highlights.binary_search_by(|highlight| {
20531            Ordering::Equal
20532                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20533                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20534        });
20535
20536        if let Err(mut ix) = ix {
20537            let index = post_inc(&mut self.highlight_order);
20538
20539            // If this range intersects with the preceding highlight, then merge it with
20540            // the preceding highlight. Otherwise insert a new highlight.
20541            let mut merged = false;
20542            if ix > 0 {
20543                let prev_highlight = &mut row_highlights[ix - 1];
20544                if prev_highlight
20545                    .range
20546                    .end
20547                    .cmp(&range.start, &snapshot)
20548                    .is_ge()
20549                {
20550                    ix -= 1;
20551                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20552                        prev_highlight.range.end = range.end;
20553                    }
20554                    merged = true;
20555                    prev_highlight.index = index;
20556                    prev_highlight.color = color;
20557                    prev_highlight.options = options;
20558                }
20559            }
20560
20561            if !merged {
20562                row_highlights.insert(
20563                    ix,
20564                    RowHighlight {
20565                        range,
20566                        index,
20567                        color,
20568                        options,
20569                        type_id: TypeId::of::<T>(),
20570                    },
20571                );
20572            }
20573
20574            // If any of the following highlights intersect with this one, merge them.
20575            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20576                let highlight = &row_highlights[ix];
20577                if next_highlight
20578                    .range
20579                    .start
20580                    .cmp(&highlight.range.end, &snapshot)
20581                    .is_le()
20582                {
20583                    if next_highlight
20584                        .range
20585                        .end
20586                        .cmp(&highlight.range.end, &snapshot)
20587                        .is_gt()
20588                    {
20589                        row_highlights[ix].range.end = next_highlight.range.end;
20590                    }
20591                    row_highlights.remove(ix + 1);
20592                } else {
20593                    break;
20594                }
20595            }
20596        }
20597    }
20598
20599    /// Remove any highlighted row ranges of the given type that intersect the
20600    /// given ranges.
20601    pub fn remove_highlighted_rows<T: 'static>(
20602        &mut self,
20603        ranges_to_remove: Vec<Range<Anchor>>,
20604        cx: &mut Context<Self>,
20605    ) {
20606        let snapshot = self.buffer().read(cx).snapshot(cx);
20607        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20608        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20609        row_highlights.retain(|highlight| {
20610            while let Some(range_to_remove) = ranges_to_remove.peek() {
20611                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20612                    Ordering::Less | Ordering::Equal => {
20613                        ranges_to_remove.next();
20614                    }
20615                    Ordering::Greater => {
20616                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20617                            Ordering::Less | Ordering::Equal => {
20618                                return false;
20619                            }
20620                            Ordering::Greater => break,
20621                        }
20622                    }
20623                }
20624            }
20625
20626            true
20627        })
20628    }
20629
20630    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20631    pub fn clear_row_highlights<T: 'static>(&mut self) {
20632        self.highlighted_rows.remove(&TypeId::of::<T>());
20633    }
20634
20635    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20636    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20637        self.highlighted_rows
20638            .get(&TypeId::of::<T>())
20639            .map_or(&[] as &[_], |vec| vec.as_slice())
20640            .iter()
20641            .map(|highlight| (highlight.range.clone(), highlight.color))
20642    }
20643
20644    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20645    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20646    /// Allows to ignore certain kinds of highlights.
20647    pub fn highlighted_display_rows(
20648        &self,
20649        window: &mut Window,
20650        cx: &mut App,
20651    ) -> BTreeMap<DisplayRow, LineHighlight> {
20652        let snapshot = self.snapshot(window, cx);
20653        let mut used_highlight_orders = HashMap::default();
20654        self.highlighted_rows
20655            .iter()
20656            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20657            .fold(
20658                BTreeMap::<DisplayRow, LineHighlight>::new(),
20659                |mut unique_rows, highlight| {
20660                    let start = highlight.range.start.to_display_point(&snapshot);
20661                    let end = highlight.range.end.to_display_point(&snapshot);
20662                    let start_row = start.row().0;
20663                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20664                        && end.column() == 0
20665                    {
20666                        end.row().0.saturating_sub(1)
20667                    } else {
20668                        end.row().0
20669                    };
20670                    for row in start_row..=end_row {
20671                        let used_index =
20672                            used_highlight_orders.entry(row).or_insert(highlight.index);
20673                        if highlight.index >= *used_index {
20674                            *used_index = highlight.index;
20675                            unique_rows.insert(
20676                                DisplayRow(row),
20677                                LineHighlight {
20678                                    include_gutter: highlight.options.include_gutter,
20679                                    border: None,
20680                                    background: highlight.color.into(),
20681                                    type_id: Some(highlight.type_id),
20682                                },
20683                            );
20684                        }
20685                    }
20686                    unique_rows
20687                },
20688            )
20689    }
20690
20691    pub fn highlighted_display_row_for_autoscroll(
20692        &self,
20693        snapshot: &DisplaySnapshot,
20694    ) -> Option<DisplayRow> {
20695        self.highlighted_rows
20696            .values()
20697            .flat_map(|highlighted_rows| highlighted_rows.iter())
20698            .filter_map(|highlight| {
20699                if highlight.options.autoscroll {
20700                    Some(highlight.range.start.to_display_point(snapshot).row())
20701                } else {
20702                    None
20703                }
20704            })
20705            .min()
20706    }
20707
20708    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20709        self.highlight_background::<SearchWithinRange>(
20710            ranges,
20711            |colors| colors.colors().editor_document_highlight_read_background,
20712            cx,
20713        )
20714    }
20715
20716    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20717        self.breadcrumb_header = Some(new_header);
20718    }
20719
20720    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20721        self.clear_background_highlights::<SearchWithinRange>(cx);
20722    }
20723
20724    pub fn highlight_background<T: 'static>(
20725        &mut self,
20726        ranges: &[Range<Anchor>],
20727        color_fetcher: fn(&Theme) -> Hsla,
20728        cx: &mut Context<Self>,
20729    ) {
20730        self.background_highlights.insert(
20731            HighlightKey::Type(TypeId::of::<T>()),
20732            (color_fetcher, Arc::from(ranges)),
20733        );
20734        self.scrollbar_marker_state.dirty = true;
20735        cx.notify();
20736    }
20737
20738    pub fn highlight_background_key<T: 'static>(
20739        &mut self,
20740        key: usize,
20741        ranges: &[Range<Anchor>],
20742        color_fetcher: fn(&Theme) -> Hsla,
20743        cx: &mut Context<Self>,
20744    ) {
20745        self.background_highlights.insert(
20746            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20747            (color_fetcher, Arc::from(ranges)),
20748        );
20749        self.scrollbar_marker_state.dirty = true;
20750        cx.notify();
20751    }
20752
20753    pub fn clear_background_highlights<T: 'static>(
20754        &mut self,
20755        cx: &mut Context<Self>,
20756    ) -> Option<BackgroundHighlight> {
20757        let text_highlights = self
20758            .background_highlights
20759            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20760        if !text_highlights.1.is_empty() {
20761            self.scrollbar_marker_state.dirty = true;
20762            cx.notify();
20763        }
20764        Some(text_highlights)
20765    }
20766
20767    pub fn highlight_gutter<T: 'static>(
20768        &mut self,
20769        ranges: impl Into<Vec<Range<Anchor>>>,
20770        color_fetcher: fn(&App) -> Hsla,
20771        cx: &mut Context<Self>,
20772    ) {
20773        self.gutter_highlights
20774            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20775        cx.notify();
20776    }
20777
20778    pub fn clear_gutter_highlights<T: 'static>(
20779        &mut self,
20780        cx: &mut Context<Self>,
20781    ) -> Option<GutterHighlight> {
20782        cx.notify();
20783        self.gutter_highlights.remove(&TypeId::of::<T>())
20784    }
20785
20786    pub fn insert_gutter_highlight<T: 'static>(
20787        &mut self,
20788        range: Range<Anchor>,
20789        color_fetcher: fn(&App) -> Hsla,
20790        cx: &mut Context<Self>,
20791    ) {
20792        let snapshot = self.buffer().read(cx).snapshot(cx);
20793        let mut highlights = self
20794            .gutter_highlights
20795            .remove(&TypeId::of::<T>())
20796            .map(|(_, highlights)| highlights)
20797            .unwrap_or_default();
20798        let ix = highlights.binary_search_by(|highlight| {
20799            Ordering::Equal
20800                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20801                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20802        });
20803        if let Err(ix) = ix {
20804            highlights.insert(ix, range);
20805        }
20806        self.gutter_highlights
20807            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20808    }
20809
20810    pub fn remove_gutter_highlights<T: 'static>(
20811        &mut self,
20812        ranges_to_remove: Vec<Range<Anchor>>,
20813        cx: &mut Context<Self>,
20814    ) {
20815        let snapshot = self.buffer().read(cx).snapshot(cx);
20816        let Some((color_fetcher, mut gutter_highlights)) =
20817            self.gutter_highlights.remove(&TypeId::of::<T>())
20818        else {
20819            return;
20820        };
20821        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20822        gutter_highlights.retain(|highlight| {
20823            while let Some(range_to_remove) = ranges_to_remove.peek() {
20824                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20825                    Ordering::Less | Ordering::Equal => {
20826                        ranges_to_remove.next();
20827                    }
20828                    Ordering::Greater => {
20829                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20830                            Ordering::Less | Ordering::Equal => {
20831                                return false;
20832                            }
20833                            Ordering::Greater => break,
20834                        }
20835                    }
20836                }
20837            }
20838
20839            true
20840        });
20841        self.gutter_highlights
20842            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20843    }
20844
20845    #[cfg(feature = "test-support")]
20846    pub fn all_text_highlights(
20847        &self,
20848        window: &mut Window,
20849        cx: &mut Context<Self>,
20850    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20851        let snapshot = self.snapshot(window, cx);
20852        self.display_map.update(cx, |display_map, _| {
20853            display_map
20854                .all_text_highlights()
20855                .map(|highlight| {
20856                    let (style, ranges) = highlight.as_ref();
20857                    (
20858                        *style,
20859                        ranges
20860                            .iter()
20861                            .map(|range| range.clone().to_display_points(&snapshot))
20862                            .collect(),
20863                    )
20864                })
20865                .collect()
20866        })
20867    }
20868
20869    #[cfg(feature = "test-support")]
20870    pub fn all_text_background_highlights(
20871        &self,
20872        window: &mut Window,
20873        cx: &mut Context<Self>,
20874    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20875        let snapshot = self.snapshot(window, cx);
20876        let buffer = &snapshot.buffer_snapshot();
20877        let start = buffer.anchor_before(0);
20878        let end = buffer.anchor_after(buffer.len());
20879        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20880    }
20881
20882    #[cfg(any(test, feature = "test-support"))]
20883    pub fn sorted_background_highlights_in_range(
20884        &self,
20885        search_range: Range<Anchor>,
20886        display_snapshot: &DisplaySnapshot,
20887        theme: &Theme,
20888    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20889        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20890        res.sort_by(|a, b| {
20891            a.0.start
20892                .cmp(&b.0.start)
20893                .then_with(|| a.0.end.cmp(&b.0.end))
20894                .then_with(|| a.1.cmp(&b.1))
20895        });
20896        res
20897    }
20898
20899    #[cfg(feature = "test-support")]
20900    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20901        let snapshot = self.buffer().read(cx).snapshot(cx);
20902
20903        let highlights = self
20904            .background_highlights
20905            .get(&HighlightKey::Type(TypeId::of::<
20906                items::BufferSearchHighlights,
20907            >()));
20908
20909        if let Some((_color, ranges)) = highlights {
20910            ranges
20911                .iter()
20912                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20913                .collect_vec()
20914        } else {
20915            vec![]
20916        }
20917    }
20918
20919    fn document_highlights_for_position<'a>(
20920        &'a self,
20921        position: Anchor,
20922        buffer: &'a MultiBufferSnapshot,
20923    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20924        let read_highlights = self
20925            .background_highlights
20926            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20927            .map(|h| &h.1);
20928        let write_highlights = self
20929            .background_highlights
20930            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20931            .map(|h| &h.1);
20932        let left_position = position.bias_left(buffer);
20933        let right_position = position.bias_right(buffer);
20934        read_highlights
20935            .into_iter()
20936            .chain(write_highlights)
20937            .flat_map(move |ranges| {
20938                let start_ix = match ranges.binary_search_by(|probe| {
20939                    let cmp = probe.end.cmp(&left_position, buffer);
20940                    if cmp.is_ge() {
20941                        Ordering::Greater
20942                    } else {
20943                        Ordering::Less
20944                    }
20945                }) {
20946                    Ok(i) | Err(i) => i,
20947                };
20948
20949                ranges[start_ix..]
20950                    .iter()
20951                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20952            })
20953    }
20954
20955    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20956        self.background_highlights
20957            .get(&HighlightKey::Type(TypeId::of::<T>()))
20958            .is_some_and(|(_, highlights)| !highlights.is_empty())
20959    }
20960
20961    /// Returns all background highlights for a given range.
20962    ///
20963    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20964    pub fn background_highlights_in_range(
20965        &self,
20966        search_range: Range<Anchor>,
20967        display_snapshot: &DisplaySnapshot,
20968        theme: &Theme,
20969    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20970        let mut results = Vec::new();
20971        for (color_fetcher, ranges) in self.background_highlights.values() {
20972            let color = color_fetcher(theme);
20973            let start_ix = match ranges.binary_search_by(|probe| {
20974                let cmp = probe
20975                    .end
20976                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20977                if cmp.is_gt() {
20978                    Ordering::Greater
20979                } else {
20980                    Ordering::Less
20981                }
20982            }) {
20983                Ok(i) | Err(i) => i,
20984            };
20985            for range in &ranges[start_ix..] {
20986                if range
20987                    .start
20988                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20989                    .is_ge()
20990                {
20991                    break;
20992                }
20993
20994                let start = range.start.to_display_point(display_snapshot);
20995                let end = range.end.to_display_point(display_snapshot);
20996                results.push((start..end, color))
20997            }
20998        }
20999        results
21000    }
21001
21002    pub fn gutter_highlights_in_range(
21003        &self,
21004        search_range: Range<Anchor>,
21005        display_snapshot: &DisplaySnapshot,
21006        cx: &App,
21007    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21008        let mut results = Vec::new();
21009        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21010            let color = color_fetcher(cx);
21011            let start_ix = match ranges.binary_search_by(|probe| {
21012                let cmp = probe
21013                    .end
21014                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21015                if cmp.is_gt() {
21016                    Ordering::Greater
21017                } else {
21018                    Ordering::Less
21019                }
21020            }) {
21021                Ok(i) | Err(i) => i,
21022            };
21023            for range in &ranges[start_ix..] {
21024                if range
21025                    .start
21026                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21027                    .is_ge()
21028                {
21029                    break;
21030                }
21031
21032                let start = range.start.to_display_point(display_snapshot);
21033                let end = range.end.to_display_point(display_snapshot);
21034                results.push((start..end, color))
21035            }
21036        }
21037        results
21038    }
21039
21040    /// Get the text ranges corresponding to the redaction query
21041    pub fn redacted_ranges(
21042        &self,
21043        search_range: Range<Anchor>,
21044        display_snapshot: &DisplaySnapshot,
21045        cx: &App,
21046    ) -> Vec<Range<DisplayPoint>> {
21047        display_snapshot
21048            .buffer_snapshot()
21049            .redacted_ranges(search_range, |file| {
21050                if let Some(file) = file {
21051                    file.is_private()
21052                        && EditorSettings::get(
21053                            Some(SettingsLocation {
21054                                worktree_id: file.worktree_id(cx),
21055                                path: file.path().as_ref(),
21056                            }),
21057                            cx,
21058                        )
21059                        .redact_private_values
21060                } else {
21061                    false
21062                }
21063            })
21064            .map(|range| {
21065                range.start.to_display_point(display_snapshot)
21066                    ..range.end.to_display_point(display_snapshot)
21067            })
21068            .collect()
21069    }
21070
21071    pub fn highlight_text_key<T: 'static>(
21072        &mut self,
21073        key: usize,
21074        ranges: Vec<Range<Anchor>>,
21075        style: HighlightStyle,
21076        cx: &mut Context<Self>,
21077    ) {
21078        self.display_map.update(cx, |map, _| {
21079            map.highlight_text(
21080                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21081                ranges,
21082                style,
21083            );
21084        });
21085        cx.notify();
21086    }
21087
21088    pub fn highlight_text<T: 'static>(
21089        &mut self,
21090        ranges: Vec<Range<Anchor>>,
21091        style: HighlightStyle,
21092        cx: &mut Context<Self>,
21093    ) {
21094        self.display_map.update(cx, |map, _| {
21095            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
21096        });
21097        cx.notify();
21098    }
21099
21100    pub fn text_highlights<'a, T: 'static>(
21101        &'a self,
21102        cx: &'a App,
21103    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21104        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21105    }
21106
21107    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21108        let cleared = self
21109            .display_map
21110            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21111        if cleared {
21112            cx.notify();
21113        }
21114    }
21115
21116    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21117        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21118            && self.focus_handle.is_focused(window)
21119    }
21120
21121    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21122        self.show_cursor_when_unfocused = is_enabled;
21123        cx.notify();
21124    }
21125
21126    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21127        cx.notify();
21128    }
21129
21130    fn on_debug_session_event(
21131        &mut self,
21132        _session: Entity<Session>,
21133        event: &SessionEvent,
21134        cx: &mut Context<Self>,
21135    ) {
21136        if let SessionEvent::InvalidateInlineValue = event {
21137            self.refresh_inline_values(cx);
21138        }
21139    }
21140
21141    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21142        let Some(project) = self.project.clone() else {
21143            return;
21144        };
21145
21146        if !self.inline_value_cache.enabled {
21147            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21148            self.splice_inlays(&inlays, Vec::new(), cx);
21149            return;
21150        }
21151
21152        let current_execution_position = self
21153            .highlighted_rows
21154            .get(&TypeId::of::<ActiveDebugLine>())
21155            .and_then(|lines| lines.last().map(|line| line.range.end));
21156
21157        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21158            let inline_values = editor
21159                .update(cx, |editor, cx| {
21160                    let Some(current_execution_position) = current_execution_position else {
21161                        return Some(Task::ready(Ok(Vec::new())));
21162                    };
21163
21164                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21165                        let snapshot = buffer.snapshot(cx);
21166
21167                        let excerpt = snapshot.excerpt_containing(
21168                            current_execution_position..current_execution_position,
21169                        )?;
21170
21171                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21172                    })?;
21173
21174                    let range =
21175                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21176
21177                    project.inline_values(buffer, range, cx)
21178                })
21179                .ok()
21180                .flatten()?
21181                .await
21182                .context("refreshing debugger inlays")
21183                .log_err()?;
21184
21185            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21186
21187            for (buffer_id, inline_value) in inline_values
21188                .into_iter()
21189                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21190            {
21191                buffer_inline_values
21192                    .entry(buffer_id)
21193                    .or_default()
21194                    .push(inline_value);
21195            }
21196
21197            editor
21198                .update(cx, |editor, cx| {
21199                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21200                    let mut new_inlays = Vec::default();
21201
21202                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21203                        let buffer_id = buffer_snapshot.remote_id();
21204                        buffer_inline_values
21205                            .get(&buffer_id)
21206                            .into_iter()
21207                            .flatten()
21208                            .for_each(|hint| {
21209                                let inlay = Inlay::debugger(
21210                                    post_inc(&mut editor.next_inlay_id),
21211                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21212                                    hint.text(),
21213                                );
21214                                if !inlay.text().chars().contains(&'\n') {
21215                                    new_inlays.push(inlay);
21216                                }
21217                            });
21218                    }
21219
21220                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21221                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21222
21223                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21224                })
21225                .ok()?;
21226            Some(())
21227        });
21228    }
21229
21230    fn on_buffer_event(
21231        &mut self,
21232        multibuffer: &Entity<MultiBuffer>,
21233        event: &multi_buffer::Event,
21234        window: &mut Window,
21235        cx: &mut Context<Self>,
21236    ) {
21237        match event {
21238            multi_buffer::Event::Edited { edited_buffer } => {
21239                self.scrollbar_marker_state.dirty = true;
21240                self.active_indent_guides_state.dirty = true;
21241                self.refresh_active_diagnostics(cx);
21242                self.refresh_code_actions(window, cx);
21243                self.refresh_selected_text_highlights(true, window, cx);
21244                self.refresh_single_line_folds(window, cx);
21245                self.refresh_matching_bracket_highlights(window, cx);
21246                if self.has_active_edit_prediction() {
21247                    self.update_visible_edit_prediction(window, cx);
21248                }
21249
21250                if let Some(buffer) = edited_buffer {
21251                    if buffer.read(cx).file().is_none() {
21252                        cx.emit(EditorEvent::TitleChanged);
21253                    }
21254
21255                    if self.project.is_some() {
21256                        let buffer_id = buffer.read(cx).remote_id();
21257                        self.register_buffer(buffer_id, cx);
21258                        self.update_lsp_data(Some(buffer_id), window, cx);
21259                        self.refresh_inlay_hints(
21260                            InlayHintRefreshReason::BufferEdited(buffer_id),
21261                            cx,
21262                        );
21263                    }
21264                }
21265
21266                cx.emit(EditorEvent::BufferEdited);
21267                cx.emit(SearchEvent::MatchesInvalidated);
21268
21269                let Some(project) = &self.project else { return };
21270                let (telemetry, is_via_ssh) = {
21271                    let project = project.read(cx);
21272                    let telemetry = project.client().telemetry().clone();
21273                    let is_via_ssh = project.is_via_remote_server();
21274                    (telemetry, is_via_ssh)
21275                };
21276                telemetry.log_edit_event("editor", is_via_ssh);
21277            }
21278            multi_buffer::Event::ExcerptsAdded {
21279                buffer,
21280                predecessor,
21281                excerpts,
21282            } => {
21283                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21284                let buffer_id = buffer.read(cx).remote_id();
21285                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21286                    && let Some(project) = &self.project
21287                {
21288                    update_uncommitted_diff_for_buffer(
21289                        cx.entity(),
21290                        project,
21291                        [buffer.clone()],
21292                        self.buffer.clone(),
21293                        cx,
21294                    )
21295                    .detach();
21296                }
21297                self.update_lsp_data(Some(buffer_id), window, cx);
21298                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21299                cx.emit(EditorEvent::ExcerptsAdded {
21300                    buffer: buffer.clone(),
21301                    predecessor: *predecessor,
21302                    excerpts: excerpts.clone(),
21303                });
21304            }
21305            multi_buffer::Event::ExcerptsRemoved {
21306                ids,
21307                removed_buffer_ids,
21308            } => {
21309                if let Some(inlay_hints) = &mut self.inlay_hints {
21310                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21311                }
21312                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21313                for buffer_id in removed_buffer_ids {
21314                    self.registered_buffers.remove(buffer_id);
21315                }
21316                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21317                cx.emit(EditorEvent::ExcerptsRemoved {
21318                    ids: ids.clone(),
21319                    removed_buffer_ids: removed_buffer_ids.clone(),
21320                });
21321            }
21322            multi_buffer::Event::ExcerptsEdited {
21323                excerpt_ids,
21324                buffer_ids,
21325            } => {
21326                self.display_map.update(cx, |map, cx| {
21327                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21328                });
21329                cx.emit(EditorEvent::ExcerptsEdited {
21330                    ids: excerpt_ids.clone(),
21331                });
21332            }
21333            multi_buffer::Event::ExcerptsExpanded { ids } => {
21334                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21335                self.refresh_document_highlights(cx);
21336                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21337            }
21338            multi_buffer::Event::Reparsed(buffer_id) => {
21339                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21340                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21341
21342                cx.emit(EditorEvent::Reparsed(*buffer_id));
21343            }
21344            multi_buffer::Event::DiffHunksToggled => {
21345                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21346            }
21347            multi_buffer::Event::LanguageChanged(buffer_id) => {
21348                self.registered_buffers.remove(&buffer_id);
21349                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21350                cx.emit(EditorEvent::Reparsed(*buffer_id));
21351                cx.notify();
21352            }
21353            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21354            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21355            multi_buffer::Event::FileHandleChanged
21356            | multi_buffer::Event::Reloaded
21357            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21358            multi_buffer::Event::DiagnosticsUpdated => {
21359                self.update_diagnostics_state(window, cx);
21360            }
21361            _ => {}
21362        };
21363    }
21364
21365    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21366        if !self.diagnostics_enabled() {
21367            return;
21368        }
21369        self.refresh_active_diagnostics(cx);
21370        self.refresh_inline_diagnostics(true, window, cx);
21371        self.scrollbar_marker_state.dirty = true;
21372        cx.notify();
21373    }
21374
21375    pub fn start_temporary_diff_override(&mut self) {
21376        self.load_diff_task.take();
21377        self.temporary_diff_override = true;
21378    }
21379
21380    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21381        self.temporary_diff_override = false;
21382        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21383        self.buffer.update(cx, |buffer, cx| {
21384            buffer.set_all_diff_hunks_collapsed(cx);
21385        });
21386
21387        if let Some(project) = self.project.clone() {
21388            self.load_diff_task = Some(
21389                update_uncommitted_diff_for_buffer(
21390                    cx.entity(),
21391                    &project,
21392                    self.buffer.read(cx).all_buffers(),
21393                    self.buffer.clone(),
21394                    cx,
21395                )
21396                .shared(),
21397            );
21398        }
21399    }
21400
21401    fn on_display_map_changed(
21402        &mut self,
21403        _: Entity<DisplayMap>,
21404        _: &mut Window,
21405        cx: &mut Context<Self>,
21406    ) {
21407        cx.notify();
21408    }
21409
21410    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21411        if self.diagnostics_enabled() {
21412            let new_severity = EditorSettings::get_global(cx)
21413                .diagnostics_max_severity
21414                .unwrap_or(DiagnosticSeverity::Hint);
21415            self.set_max_diagnostics_severity(new_severity, cx);
21416        }
21417        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21418        self.update_edit_prediction_settings(cx);
21419        self.refresh_edit_prediction(true, false, window, cx);
21420        self.refresh_inline_values(cx);
21421        self.refresh_inlay_hints(
21422            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21423                self.selections.newest_anchor().head(),
21424                &self.buffer.read(cx).snapshot(cx),
21425                cx,
21426            )),
21427            cx,
21428        );
21429
21430        let old_cursor_shape = self.cursor_shape;
21431        let old_show_breadcrumbs = self.show_breadcrumbs;
21432
21433        {
21434            let editor_settings = EditorSettings::get_global(cx);
21435            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21436            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21437            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21438            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21439        }
21440
21441        if old_cursor_shape != self.cursor_shape {
21442            cx.emit(EditorEvent::CursorShapeChanged);
21443        }
21444
21445        if old_show_breadcrumbs != self.show_breadcrumbs {
21446            cx.emit(EditorEvent::BreadcrumbsChanged);
21447        }
21448
21449        let project_settings = ProjectSettings::get_global(cx);
21450        self.buffer_serialization = self
21451            .should_serialize_buffer()
21452            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21453
21454        if self.mode.is_full() {
21455            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21456            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21457            if self.show_inline_diagnostics != show_inline_diagnostics {
21458                self.show_inline_diagnostics = show_inline_diagnostics;
21459                self.refresh_inline_diagnostics(false, window, cx);
21460            }
21461
21462            if self.git_blame_inline_enabled != inline_blame_enabled {
21463                self.toggle_git_blame_inline_internal(false, window, cx);
21464            }
21465
21466            let minimap_settings = EditorSettings::get_global(cx).minimap;
21467            if self.minimap_visibility != MinimapVisibility::Disabled {
21468                if self.minimap_visibility.settings_visibility()
21469                    != minimap_settings.minimap_enabled()
21470                {
21471                    self.set_minimap_visibility(
21472                        MinimapVisibility::for_mode(self.mode(), cx),
21473                        window,
21474                        cx,
21475                    );
21476                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21477                    minimap_entity.update(cx, |minimap_editor, cx| {
21478                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21479                    })
21480                }
21481            }
21482        }
21483
21484        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21485            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21486        }) {
21487            if !inlay_splice.is_empty() {
21488                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21489            }
21490            self.refresh_colors_for_visible_range(None, window, cx);
21491        }
21492
21493        cx.notify();
21494    }
21495
21496    pub fn set_searchable(&mut self, searchable: bool) {
21497        self.searchable = searchable;
21498    }
21499
21500    pub fn searchable(&self) -> bool {
21501        self.searchable
21502    }
21503
21504    pub fn open_excerpts_in_split(
21505        &mut self,
21506        _: &OpenExcerptsSplit,
21507        window: &mut Window,
21508        cx: &mut Context<Self>,
21509    ) {
21510        self.open_excerpts_common(None, true, window, cx)
21511    }
21512
21513    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21514        self.open_excerpts_common(None, false, window, cx)
21515    }
21516
21517    fn open_excerpts_common(
21518        &mut self,
21519        jump_data: Option<JumpData>,
21520        split: bool,
21521        window: &mut Window,
21522        cx: &mut Context<Self>,
21523    ) {
21524        let Some(workspace) = self.workspace() else {
21525            cx.propagate();
21526            return;
21527        };
21528
21529        if self.buffer.read(cx).is_singleton() {
21530            cx.propagate();
21531            return;
21532        }
21533
21534        let mut new_selections_by_buffer = HashMap::default();
21535        match &jump_data {
21536            Some(JumpData::MultiBufferPoint {
21537                excerpt_id,
21538                position,
21539                anchor,
21540                line_offset_from_top,
21541            }) => {
21542                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21543                if let Some(buffer) = multi_buffer_snapshot
21544                    .buffer_id_for_excerpt(*excerpt_id)
21545                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21546                {
21547                    let buffer_snapshot = buffer.read(cx).snapshot();
21548                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21549                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21550                    } else {
21551                        buffer_snapshot.clip_point(*position, Bias::Left)
21552                    };
21553                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21554                    new_selections_by_buffer.insert(
21555                        buffer,
21556                        (
21557                            vec![jump_to_offset..jump_to_offset],
21558                            Some(*line_offset_from_top),
21559                        ),
21560                    );
21561                }
21562            }
21563            Some(JumpData::MultiBufferRow {
21564                row,
21565                line_offset_from_top,
21566            }) => {
21567                let point = MultiBufferPoint::new(row.0, 0);
21568                if let Some((buffer, buffer_point, _)) =
21569                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21570                {
21571                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21572                    new_selections_by_buffer
21573                        .entry(buffer)
21574                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21575                        .0
21576                        .push(buffer_offset..buffer_offset)
21577                }
21578            }
21579            None => {
21580                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21581                let multi_buffer = self.buffer.read(cx);
21582                for selection in selections {
21583                    for (snapshot, range, _, anchor) in multi_buffer
21584                        .snapshot(cx)
21585                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21586                    {
21587                        if let Some(anchor) = anchor {
21588                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21589                            else {
21590                                continue;
21591                            };
21592                            let offset = text::ToOffset::to_offset(
21593                                &anchor.text_anchor,
21594                                &buffer_handle.read(cx).snapshot(),
21595                            );
21596                            let range = offset..offset;
21597                            new_selections_by_buffer
21598                                .entry(buffer_handle)
21599                                .or_insert((Vec::new(), None))
21600                                .0
21601                                .push(range)
21602                        } else {
21603                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21604                            else {
21605                                continue;
21606                            };
21607                            new_selections_by_buffer
21608                                .entry(buffer_handle)
21609                                .or_insert((Vec::new(), None))
21610                                .0
21611                                .push(range)
21612                        }
21613                    }
21614                }
21615            }
21616        }
21617
21618        new_selections_by_buffer
21619            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21620
21621        if new_selections_by_buffer.is_empty() {
21622            return;
21623        }
21624
21625        // We defer the pane interaction because we ourselves are a workspace item
21626        // and activating a new item causes the pane to call a method on us reentrantly,
21627        // which panics if we're on the stack.
21628        window.defer(cx, move |window, cx| {
21629            workspace.update(cx, |workspace, cx| {
21630                let pane = if split {
21631                    workspace.adjacent_pane(window, cx)
21632                } else {
21633                    workspace.active_pane().clone()
21634                };
21635
21636                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21637                    let editor = buffer
21638                        .read(cx)
21639                        .file()
21640                        .is_none()
21641                        .then(|| {
21642                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21643                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21644                            // Instead, we try to activate the existing editor in the pane first.
21645                            let (editor, pane_item_index) =
21646                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21647                                    let editor = item.downcast::<Editor>()?;
21648                                    let singleton_buffer =
21649                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21650                                    if singleton_buffer == buffer {
21651                                        Some((editor, i))
21652                                    } else {
21653                                        None
21654                                    }
21655                                })?;
21656                            pane.update(cx, |pane, cx| {
21657                                pane.activate_item(pane_item_index, true, true, window, cx)
21658                            });
21659                            Some(editor)
21660                        })
21661                        .flatten()
21662                        .unwrap_or_else(|| {
21663                            workspace.open_project_item::<Self>(
21664                                pane.clone(),
21665                                buffer,
21666                                true,
21667                                true,
21668                                window,
21669                                cx,
21670                            )
21671                        });
21672
21673                    editor.update(cx, |editor, cx| {
21674                        let autoscroll = match scroll_offset {
21675                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21676                            None => Autoscroll::newest(),
21677                        };
21678                        let nav_history = editor.nav_history.take();
21679                        editor.change_selections(
21680                            SelectionEffects::scroll(autoscroll),
21681                            window,
21682                            cx,
21683                            |s| {
21684                                s.select_ranges(ranges);
21685                            },
21686                        );
21687                        editor.nav_history = nav_history;
21688                    });
21689                }
21690            })
21691        });
21692    }
21693
21694    // For now, don't allow opening excerpts in buffers that aren't backed by
21695    // regular project files.
21696    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21697        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21698    }
21699
21700    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21701        let snapshot = self.buffer.read(cx).read(cx);
21702        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21703        Some(
21704            ranges
21705                .iter()
21706                .map(move |range| {
21707                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21708                })
21709                .collect(),
21710        )
21711    }
21712
21713    fn selection_replacement_ranges(
21714        &self,
21715        range: Range<OffsetUtf16>,
21716        cx: &mut App,
21717    ) -> Vec<Range<OffsetUtf16>> {
21718        let selections = self
21719            .selections
21720            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21721        let newest_selection = selections
21722            .iter()
21723            .max_by_key(|selection| selection.id)
21724            .unwrap();
21725        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21726        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21727        let snapshot = self.buffer.read(cx).read(cx);
21728        selections
21729            .into_iter()
21730            .map(|mut selection| {
21731                selection.start.0 =
21732                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21733                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21734                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21735                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21736            })
21737            .collect()
21738    }
21739
21740    fn report_editor_event(
21741        &self,
21742        reported_event: ReportEditorEvent,
21743        file_extension: Option<String>,
21744        cx: &App,
21745    ) {
21746        if cfg!(any(test, feature = "test-support")) {
21747            return;
21748        }
21749
21750        let Some(project) = &self.project else { return };
21751
21752        // If None, we are in a file without an extension
21753        let file = self
21754            .buffer
21755            .read(cx)
21756            .as_singleton()
21757            .and_then(|b| b.read(cx).file());
21758        let file_extension = file_extension.or(file
21759            .as_ref()
21760            .and_then(|file| Path::new(file.file_name(cx)).extension())
21761            .and_then(|e| e.to_str())
21762            .map(|a| a.to_string()));
21763
21764        let vim_mode = vim_flavor(cx).is_some();
21765
21766        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21767        let copilot_enabled = edit_predictions_provider
21768            == language::language_settings::EditPredictionProvider::Copilot;
21769        let copilot_enabled_for_language = self
21770            .buffer
21771            .read(cx)
21772            .language_settings(cx)
21773            .show_edit_predictions;
21774
21775        let project = project.read(cx);
21776        let event_type = reported_event.event_type();
21777
21778        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21779            telemetry::event!(
21780                event_type,
21781                type = if auto_saved {"autosave"} else {"manual"},
21782                file_extension,
21783                vim_mode,
21784                copilot_enabled,
21785                copilot_enabled_for_language,
21786                edit_predictions_provider,
21787                is_via_ssh = project.is_via_remote_server(),
21788            );
21789        } else {
21790            telemetry::event!(
21791                event_type,
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        };
21800    }
21801
21802    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21803    /// with each line being an array of {text, highlight} objects.
21804    fn copy_highlight_json(
21805        &mut self,
21806        _: &CopyHighlightJson,
21807        window: &mut Window,
21808        cx: &mut Context<Self>,
21809    ) {
21810        #[derive(Serialize)]
21811        struct Chunk<'a> {
21812            text: String,
21813            highlight: Option<&'a str>,
21814        }
21815
21816        let snapshot = self.buffer.read(cx).snapshot(cx);
21817        let range = self
21818            .selected_text_range(false, window, cx)
21819            .and_then(|selection| {
21820                if selection.range.is_empty() {
21821                    None
21822                } else {
21823                    Some(
21824                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21825                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21826                    )
21827                }
21828            })
21829            .unwrap_or_else(|| 0..snapshot.len());
21830
21831        let chunks = snapshot.chunks(range, true);
21832        let mut lines = Vec::new();
21833        let mut line: VecDeque<Chunk> = VecDeque::new();
21834
21835        let Some(style) = self.style.as_ref() else {
21836            return;
21837        };
21838
21839        for chunk in chunks {
21840            let highlight = chunk
21841                .syntax_highlight_id
21842                .and_then(|id| id.name(&style.syntax));
21843            let mut chunk_lines = chunk.text.split('\n').peekable();
21844            while let Some(text) = chunk_lines.next() {
21845                let mut merged_with_last_token = false;
21846                if let Some(last_token) = line.back_mut()
21847                    && last_token.highlight == highlight
21848                {
21849                    last_token.text.push_str(text);
21850                    merged_with_last_token = true;
21851                }
21852
21853                if !merged_with_last_token {
21854                    line.push_back(Chunk {
21855                        text: text.into(),
21856                        highlight,
21857                    });
21858                }
21859
21860                if chunk_lines.peek().is_some() {
21861                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21862                        line.pop_front();
21863                    }
21864                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21865                        line.pop_back();
21866                    }
21867
21868                    lines.push(mem::take(&mut line));
21869                }
21870            }
21871        }
21872
21873        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21874            return;
21875        };
21876        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21877    }
21878
21879    pub fn open_context_menu(
21880        &mut self,
21881        _: &OpenContextMenu,
21882        window: &mut Window,
21883        cx: &mut Context<Self>,
21884    ) {
21885        self.request_autoscroll(Autoscroll::newest(), cx);
21886        let position = self
21887            .selections
21888            .newest_display(&self.display_snapshot(cx))
21889            .start;
21890        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21891    }
21892
21893    pub fn replay_insert_event(
21894        &mut self,
21895        text: &str,
21896        relative_utf16_range: Option<Range<isize>>,
21897        window: &mut Window,
21898        cx: &mut Context<Self>,
21899    ) {
21900        if !self.input_enabled {
21901            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21902            return;
21903        }
21904        if let Some(relative_utf16_range) = relative_utf16_range {
21905            let selections = self
21906                .selections
21907                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21908            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21909                let new_ranges = selections.into_iter().map(|range| {
21910                    let start = OffsetUtf16(
21911                        range
21912                            .head()
21913                            .0
21914                            .saturating_add_signed(relative_utf16_range.start),
21915                    );
21916                    let end = OffsetUtf16(
21917                        range
21918                            .head()
21919                            .0
21920                            .saturating_add_signed(relative_utf16_range.end),
21921                    );
21922                    start..end
21923                });
21924                s.select_ranges(new_ranges);
21925            });
21926        }
21927
21928        self.handle_input(text, window, cx);
21929    }
21930
21931    pub fn is_focused(&self, window: &Window) -> bool {
21932        self.focus_handle.is_focused(window)
21933    }
21934
21935    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21936        cx.emit(EditorEvent::Focused);
21937
21938        if let Some(descendant) = self
21939            .last_focused_descendant
21940            .take()
21941            .and_then(|descendant| descendant.upgrade())
21942        {
21943            window.focus(&descendant);
21944        } else {
21945            if let Some(blame) = self.blame.as_ref() {
21946                blame.update(cx, GitBlame::focus)
21947            }
21948
21949            self.blink_manager.update(cx, BlinkManager::enable);
21950            self.show_cursor_names(window, cx);
21951            self.buffer.update(cx, |buffer, cx| {
21952                buffer.finalize_last_transaction(cx);
21953                if self.leader_id.is_none() {
21954                    buffer.set_active_selections(
21955                        &self.selections.disjoint_anchors_arc(),
21956                        self.selections.line_mode(),
21957                        self.cursor_shape,
21958                        cx,
21959                    );
21960                }
21961            });
21962        }
21963    }
21964
21965    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21966        cx.emit(EditorEvent::FocusedIn)
21967    }
21968
21969    fn handle_focus_out(
21970        &mut self,
21971        event: FocusOutEvent,
21972        _window: &mut Window,
21973        cx: &mut Context<Self>,
21974    ) {
21975        if event.blurred != self.focus_handle {
21976            self.last_focused_descendant = Some(event.blurred);
21977        }
21978        self.selection_drag_state = SelectionDragState::None;
21979        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21980    }
21981
21982    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21983        self.blink_manager.update(cx, BlinkManager::disable);
21984        self.buffer
21985            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21986
21987        if let Some(blame) = self.blame.as_ref() {
21988            blame.update(cx, GitBlame::blur)
21989        }
21990        if !self.hover_state.focused(window, cx) {
21991            hide_hover(self, cx);
21992        }
21993        if !self
21994            .context_menu
21995            .borrow()
21996            .as_ref()
21997            .is_some_and(|context_menu| context_menu.focused(window, cx))
21998        {
21999            self.hide_context_menu(window, cx);
22000        }
22001        self.take_active_edit_prediction(cx);
22002        cx.emit(EditorEvent::Blurred);
22003        cx.notify();
22004    }
22005
22006    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22007        let mut pending: String = window
22008            .pending_input_keystrokes()
22009            .into_iter()
22010            .flatten()
22011            .filter_map(|keystroke| {
22012                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
22013                    keystroke.key_char.clone()
22014                } else {
22015                    None
22016                }
22017            })
22018            .collect();
22019
22020        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22021            pending = "".to_string();
22022        }
22023
22024        let existing_pending = self
22025            .text_highlights::<PendingInput>(cx)
22026            .map(|(_, ranges)| ranges.to_vec());
22027        if existing_pending.is_none() && pending.is_empty() {
22028            return;
22029        }
22030        let transaction =
22031            self.transact(window, cx, |this, window, cx| {
22032                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
22033                let edits = selections
22034                    .iter()
22035                    .map(|selection| (selection.end..selection.end, pending.clone()));
22036                this.edit(edits, cx);
22037                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22038                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22039                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22040                    }));
22041                });
22042                if let Some(existing_ranges) = existing_pending {
22043                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22044                    this.edit(edits, cx);
22045                }
22046            });
22047
22048        let snapshot = self.snapshot(window, cx);
22049        let ranges = self
22050            .selections
22051            .all::<usize>(&snapshot.display_snapshot)
22052            .into_iter()
22053            .map(|selection| {
22054                snapshot.buffer_snapshot().anchor_after(selection.end)
22055                    ..snapshot
22056                        .buffer_snapshot()
22057                        .anchor_before(selection.end + pending.len())
22058            })
22059            .collect();
22060
22061        if pending.is_empty() {
22062            self.clear_highlights::<PendingInput>(cx);
22063        } else {
22064            self.highlight_text::<PendingInput>(
22065                ranges,
22066                HighlightStyle {
22067                    underline: Some(UnderlineStyle {
22068                        thickness: px(1.),
22069                        color: None,
22070                        wavy: false,
22071                    }),
22072                    ..Default::default()
22073                },
22074                cx,
22075            );
22076        }
22077
22078        self.ime_transaction = self.ime_transaction.or(transaction);
22079        if let Some(transaction) = self.ime_transaction {
22080            self.buffer.update(cx, |buffer, cx| {
22081                buffer.group_until_transaction(transaction, cx);
22082            });
22083        }
22084
22085        if self.text_highlights::<PendingInput>(cx).is_none() {
22086            self.ime_transaction.take();
22087        }
22088    }
22089
22090    pub fn register_action_renderer(
22091        &mut self,
22092        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22093    ) -> Subscription {
22094        let id = self.next_editor_action_id.post_inc();
22095        self.editor_actions
22096            .borrow_mut()
22097            .insert(id, Box::new(listener));
22098
22099        let editor_actions = self.editor_actions.clone();
22100        Subscription::new(move || {
22101            editor_actions.borrow_mut().remove(&id);
22102        })
22103    }
22104
22105    pub fn register_action<A: Action>(
22106        &mut self,
22107        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22108    ) -> Subscription {
22109        let id = self.next_editor_action_id.post_inc();
22110        let listener = Arc::new(listener);
22111        self.editor_actions.borrow_mut().insert(
22112            id,
22113            Box::new(move |_, window, _| {
22114                let listener = listener.clone();
22115                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22116                    let action = action.downcast_ref().unwrap();
22117                    if phase == DispatchPhase::Bubble {
22118                        listener(action, window, cx)
22119                    }
22120                })
22121            }),
22122        );
22123
22124        let editor_actions = self.editor_actions.clone();
22125        Subscription::new(move || {
22126            editor_actions.borrow_mut().remove(&id);
22127        })
22128    }
22129
22130    pub fn file_header_size(&self) -> u32 {
22131        FILE_HEADER_HEIGHT
22132    }
22133
22134    pub fn restore(
22135        &mut self,
22136        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22137        window: &mut Window,
22138        cx: &mut Context<Self>,
22139    ) {
22140        let workspace = self.workspace();
22141        let project = self.project();
22142        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22143            let mut tasks = Vec::new();
22144            for (buffer_id, changes) in revert_changes {
22145                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22146                    buffer.update(cx, |buffer, cx| {
22147                        buffer.edit(
22148                            changes
22149                                .into_iter()
22150                                .map(|(range, text)| (range, text.to_string())),
22151                            None,
22152                            cx,
22153                        );
22154                    });
22155
22156                    if let Some(project) =
22157                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22158                    {
22159                        project.update(cx, |project, cx| {
22160                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22161                        })
22162                    }
22163                }
22164            }
22165            tasks
22166        });
22167        cx.spawn_in(window, async move |_, cx| {
22168            for (buffer, task) in save_tasks {
22169                let result = task.await;
22170                if result.is_err() {
22171                    let Some(path) = buffer
22172                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22173                        .ok()
22174                    else {
22175                        continue;
22176                    };
22177                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22178                        let Some(task) = cx
22179                            .update_window_entity(workspace, |workspace, window, cx| {
22180                                workspace
22181                                    .open_path_preview(path, None, false, false, false, window, cx)
22182                            })
22183                            .ok()
22184                        else {
22185                            continue;
22186                        };
22187                        task.await.log_err();
22188                    }
22189                }
22190            }
22191        })
22192        .detach();
22193        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22194            selections.refresh()
22195        });
22196    }
22197
22198    pub fn to_pixel_point(
22199        &self,
22200        source: multi_buffer::Anchor,
22201        editor_snapshot: &EditorSnapshot,
22202        window: &mut Window,
22203    ) -> Option<gpui::Point<Pixels>> {
22204        let source_point = source.to_display_point(editor_snapshot);
22205        self.display_to_pixel_point(source_point, editor_snapshot, window)
22206    }
22207
22208    pub fn display_to_pixel_point(
22209        &self,
22210        source: DisplayPoint,
22211        editor_snapshot: &EditorSnapshot,
22212        window: &mut Window,
22213    ) -> Option<gpui::Point<Pixels>> {
22214        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22215        let text_layout_details = self.text_layout_details(window);
22216        let scroll_top = text_layout_details
22217            .scroll_anchor
22218            .scroll_position(editor_snapshot)
22219            .y;
22220
22221        if source.row().as_f64() < scroll_top.floor() {
22222            return None;
22223        }
22224        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22225        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22226        Some(gpui::Point::new(source_x, source_y))
22227    }
22228
22229    pub fn has_visible_completions_menu(&self) -> bool {
22230        !self.edit_prediction_preview_is_active()
22231            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22232                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22233            })
22234    }
22235
22236    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22237        if self.mode.is_minimap() {
22238            return;
22239        }
22240        self.addons
22241            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22242    }
22243
22244    pub fn unregister_addon<T: Addon>(&mut self) {
22245        self.addons.remove(&std::any::TypeId::of::<T>());
22246    }
22247
22248    pub fn addon<T: Addon>(&self) -> Option<&T> {
22249        let type_id = std::any::TypeId::of::<T>();
22250        self.addons
22251            .get(&type_id)
22252            .and_then(|item| item.to_any().downcast_ref::<T>())
22253    }
22254
22255    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22256        let type_id = std::any::TypeId::of::<T>();
22257        self.addons
22258            .get_mut(&type_id)
22259            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22260    }
22261
22262    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22263        let text_layout_details = self.text_layout_details(window);
22264        let style = &text_layout_details.editor_style;
22265        let font_id = window.text_system().resolve_font(&style.text.font());
22266        let font_size = style.text.font_size.to_pixels(window.rem_size());
22267        let line_height = style.text.line_height_in_pixels(window.rem_size());
22268        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22269        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22270
22271        CharacterDimensions {
22272            em_width,
22273            em_advance,
22274            line_height,
22275        }
22276    }
22277
22278    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22279        self.load_diff_task.clone()
22280    }
22281
22282    fn read_metadata_from_db(
22283        &mut self,
22284        item_id: u64,
22285        workspace_id: WorkspaceId,
22286        window: &mut Window,
22287        cx: &mut Context<Editor>,
22288    ) {
22289        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22290            && !self.mode.is_minimap()
22291            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22292        {
22293            let buffer_snapshot = OnceCell::new();
22294
22295            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22296                && !folds.is_empty()
22297            {
22298                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22299                self.fold_ranges(
22300                    folds
22301                        .into_iter()
22302                        .map(|(start, end)| {
22303                            snapshot.clip_offset(start, Bias::Left)
22304                                ..snapshot.clip_offset(end, Bias::Right)
22305                        })
22306                        .collect(),
22307                    false,
22308                    window,
22309                    cx,
22310                );
22311            }
22312
22313            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22314                && !selections.is_empty()
22315            {
22316                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22317                // skip adding the initial selection to selection history
22318                self.selection_history.mode = SelectionHistoryMode::Skipping;
22319                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22320                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22321                        snapshot.clip_offset(start, Bias::Left)
22322                            ..snapshot.clip_offset(end, Bias::Right)
22323                    }));
22324                });
22325                self.selection_history.mode = SelectionHistoryMode::Normal;
22326            };
22327        }
22328
22329        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22330    }
22331
22332    fn update_lsp_data(
22333        &mut self,
22334        for_buffer: Option<BufferId>,
22335        window: &mut Window,
22336        cx: &mut Context<'_, Self>,
22337    ) {
22338        self.pull_diagnostics(for_buffer, window, cx);
22339        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22340    }
22341
22342    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22343        if self.ignore_lsp_data() {
22344            return;
22345        }
22346        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22347            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22348        }
22349    }
22350
22351    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22352        if self.ignore_lsp_data() {
22353            return;
22354        }
22355
22356        if !self.registered_buffers.contains_key(&buffer_id)
22357            && let Some(project) = self.project.as_ref()
22358        {
22359            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22360                project.update(cx, |project, cx| {
22361                    self.registered_buffers.insert(
22362                        buffer_id,
22363                        project.register_buffer_with_language_servers(&buffer, cx),
22364                    );
22365                });
22366            } else {
22367                self.registered_buffers.remove(&buffer_id);
22368            }
22369        }
22370    }
22371
22372    fn ignore_lsp_data(&self) -> bool {
22373        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22374        // skip any LSP updates for it.
22375        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22376    }
22377}
22378
22379fn edit_for_markdown_paste<'a>(
22380    buffer: &MultiBufferSnapshot,
22381    range: Range<usize>,
22382    to_insert: &'a str,
22383    url: Option<url::Url>,
22384) -> (Range<usize>, Cow<'a, str>) {
22385    if url.is_none() {
22386        return (range, Cow::Borrowed(to_insert));
22387    };
22388
22389    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22390
22391    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22392        Cow::Borrowed(to_insert)
22393    } else {
22394        Cow::Owned(format!("[{old_text}]({to_insert})"))
22395    };
22396    (range, new_text)
22397}
22398
22399#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22400pub enum VimFlavor {
22401    Vim,
22402    Helix,
22403}
22404
22405pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22406    if vim_mode_setting::HelixModeSetting::try_get(cx)
22407        .map(|helix_mode| helix_mode.0)
22408        .unwrap_or(false)
22409    {
22410        Some(VimFlavor::Helix)
22411    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22412        .map(|vim_mode| vim_mode.0)
22413        .unwrap_or(false)
22414    {
22415        Some(VimFlavor::Vim)
22416    } else {
22417        None // neither vim nor helix mode
22418    }
22419}
22420
22421fn process_completion_for_edit(
22422    completion: &Completion,
22423    intent: CompletionIntent,
22424    buffer: &Entity<Buffer>,
22425    cursor_position: &text::Anchor,
22426    cx: &mut Context<Editor>,
22427) -> CompletionEdit {
22428    let buffer = buffer.read(cx);
22429    let buffer_snapshot = buffer.snapshot();
22430    let (snippet, new_text) = if completion.is_snippet() {
22431        let mut snippet_source = completion.new_text.clone();
22432        // Workaround for typescript language server issues so that methods don't expand within
22433        // strings and functions with type expressions. The previous point is used because the query
22434        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22435        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22436        let previous_point = if previous_point.column > 0 {
22437            cursor_position.to_previous_offset(&buffer_snapshot)
22438        } else {
22439            cursor_position.to_offset(&buffer_snapshot)
22440        };
22441        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22442            && scope.prefers_label_for_snippet_in_completion()
22443            && let Some(label) = completion.label()
22444            && matches!(
22445                completion.kind(),
22446                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22447            )
22448        {
22449            snippet_source = label;
22450        }
22451        match Snippet::parse(&snippet_source).log_err() {
22452            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22453            None => (None, completion.new_text.clone()),
22454        }
22455    } else {
22456        (None, completion.new_text.clone())
22457    };
22458
22459    let mut range_to_replace = {
22460        let replace_range = &completion.replace_range;
22461        if let CompletionSource::Lsp {
22462            insert_range: Some(insert_range),
22463            ..
22464        } = &completion.source
22465        {
22466            debug_assert_eq!(
22467                insert_range.start, replace_range.start,
22468                "insert_range and replace_range should start at the same position"
22469            );
22470            debug_assert!(
22471                insert_range
22472                    .start
22473                    .cmp(cursor_position, &buffer_snapshot)
22474                    .is_le(),
22475                "insert_range should start before or at cursor position"
22476            );
22477            debug_assert!(
22478                replace_range
22479                    .start
22480                    .cmp(cursor_position, &buffer_snapshot)
22481                    .is_le(),
22482                "replace_range should start before or at cursor position"
22483            );
22484
22485            let should_replace = match intent {
22486                CompletionIntent::CompleteWithInsert => false,
22487                CompletionIntent::CompleteWithReplace => true,
22488                CompletionIntent::Complete | CompletionIntent::Compose => {
22489                    let insert_mode =
22490                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22491                            .completions
22492                            .lsp_insert_mode;
22493                    match insert_mode {
22494                        LspInsertMode::Insert => false,
22495                        LspInsertMode::Replace => true,
22496                        LspInsertMode::ReplaceSubsequence => {
22497                            let mut text_to_replace = buffer.chars_for_range(
22498                                buffer.anchor_before(replace_range.start)
22499                                    ..buffer.anchor_after(replace_range.end),
22500                            );
22501                            let mut current_needle = text_to_replace.next();
22502                            for haystack_ch in completion.label.text.chars() {
22503                                if let Some(needle_ch) = current_needle
22504                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22505                                {
22506                                    current_needle = text_to_replace.next();
22507                                }
22508                            }
22509                            current_needle.is_none()
22510                        }
22511                        LspInsertMode::ReplaceSuffix => {
22512                            if replace_range
22513                                .end
22514                                .cmp(cursor_position, &buffer_snapshot)
22515                                .is_gt()
22516                            {
22517                                let range_after_cursor = *cursor_position..replace_range.end;
22518                                let text_after_cursor = buffer
22519                                    .text_for_range(
22520                                        buffer.anchor_before(range_after_cursor.start)
22521                                            ..buffer.anchor_after(range_after_cursor.end),
22522                                    )
22523                                    .collect::<String>()
22524                                    .to_ascii_lowercase();
22525                                completion
22526                                    .label
22527                                    .text
22528                                    .to_ascii_lowercase()
22529                                    .ends_with(&text_after_cursor)
22530                            } else {
22531                                true
22532                            }
22533                        }
22534                    }
22535                }
22536            };
22537
22538            if should_replace {
22539                replace_range.clone()
22540            } else {
22541                insert_range.clone()
22542            }
22543        } else {
22544            replace_range.clone()
22545        }
22546    };
22547
22548    if range_to_replace
22549        .end
22550        .cmp(cursor_position, &buffer_snapshot)
22551        .is_lt()
22552    {
22553        range_to_replace.end = *cursor_position;
22554    }
22555
22556    CompletionEdit {
22557        new_text,
22558        replace_range: range_to_replace.to_offset(buffer),
22559        snippet,
22560    }
22561}
22562
22563struct CompletionEdit {
22564    new_text: String,
22565    replace_range: Range<usize>,
22566    snippet: Option<Snippet>,
22567}
22568
22569fn insert_extra_newline_brackets(
22570    buffer: &MultiBufferSnapshot,
22571    range: Range<usize>,
22572    language: &language::LanguageScope,
22573) -> bool {
22574    let leading_whitespace_len = buffer
22575        .reversed_chars_at(range.start)
22576        .take_while(|c| c.is_whitespace() && *c != '\n')
22577        .map(|c| c.len_utf8())
22578        .sum::<usize>();
22579    let trailing_whitespace_len = buffer
22580        .chars_at(range.end)
22581        .take_while(|c| c.is_whitespace() && *c != '\n')
22582        .map(|c| c.len_utf8())
22583        .sum::<usize>();
22584    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22585
22586    language.brackets().any(|(pair, enabled)| {
22587        let pair_start = pair.start.trim_end();
22588        let pair_end = pair.end.trim_start();
22589
22590        enabled
22591            && pair.newline
22592            && buffer.contains_str_at(range.end, pair_end)
22593            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22594    })
22595}
22596
22597fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22598    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22599        [(buffer, range, _)] => (*buffer, range.clone()),
22600        _ => return false,
22601    };
22602    let pair = {
22603        let mut result: Option<BracketMatch> = None;
22604
22605        for pair in buffer
22606            .all_bracket_ranges(range.clone())
22607            .filter(move |pair| {
22608                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22609            })
22610        {
22611            let len = pair.close_range.end - pair.open_range.start;
22612
22613            if let Some(existing) = &result {
22614                let existing_len = existing.close_range.end - existing.open_range.start;
22615                if len > existing_len {
22616                    continue;
22617                }
22618            }
22619
22620            result = Some(pair);
22621        }
22622
22623        result
22624    };
22625    let Some(pair) = pair else {
22626        return false;
22627    };
22628    pair.newline_only
22629        && buffer
22630            .chars_for_range(pair.open_range.end..range.start)
22631            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22632            .all(|c| c.is_whitespace() && c != '\n')
22633}
22634
22635fn update_uncommitted_diff_for_buffer(
22636    editor: Entity<Editor>,
22637    project: &Entity<Project>,
22638    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22639    buffer: Entity<MultiBuffer>,
22640    cx: &mut App,
22641) -> Task<()> {
22642    let mut tasks = Vec::new();
22643    project.update(cx, |project, cx| {
22644        for buffer in buffers {
22645            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22646                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22647            }
22648        }
22649    });
22650    cx.spawn(async move |cx| {
22651        let diffs = future::join_all(tasks).await;
22652        if editor
22653            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22654            .unwrap_or(false)
22655        {
22656            return;
22657        }
22658
22659        buffer
22660            .update(cx, |buffer, cx| {
22661                for diff in diffs.into_iter().flatten() {
22662                    buffer.add_diff(diff, cx);
22663                }
22664            })
22665            .ok();
22666    })
22667}
22668
22669fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22670    let tab_size = tab_size.get() as usize;
22671    let mut width = offset;
22672
22673    for ch in text.chars() {
22674        width += if ch == '\t' {
22675            tab_size - (width % tab_size)
22676        } else {
22677            1
22678        };
22679    }
22680
22681    width - offset
22682}
22683
22684#[cfg(test)]
22685mod tests {
22686    use super::*;
22687
22688    #[test]
22689    fn test_string_size_with_expanded_tabs() {
22690        let nz = |val| NonZeroU32::new(val).unwrap();
22691        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22692        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22693        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22694        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22695        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22696        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22697        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22698        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22699    }
22700}
22701
22702/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22703struct WordBreakingTokenizer<'a> {
22704    input: &'a str,
22705}
22706
22707impl<'a> WordBreakingTokenizer<'a> {
22708    fn new(input: &'a str) -> Self {
22709        Self { input }
22710    }
22711}
22712
22713fn is_char_ideographic(ch: char) -> bool {
22714    use unicode_script::Script::*;
22715    use unicode_script::UnicodeScript;
22716    matches!(ch.script(), Han | Tangut | Yi)
22717}
22718
22719fn is_grapheme_ideographic(text: &str) -> bool {
22720    text.chars().any(is_char_ideographic)
22721}
22722
22723fn is_grapheme_whitespace(text: &str) -> bool {
22724    text.chars().any(|x| x.is_whitespace())
22725}
22726
22727fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22728    text.chars()
22729        .next()
22730        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22731}
22732
22733#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22734enum WordBreakToken<'a> {
22735    Word { token: &'a str, grapheme_len: usize },
22736    InlineWhitespace { token: &'a str, grapheme_len: usize },
22737    Newline,
22738}
22739
22740impl<'a> Iterator for WordBreakingTokenizer<'a> {
22741    /// Yields a span, the count of graphemes in the token, and whether it was
22742    /// whitespace. Note that it also breaks at word boundaries.
22743    type Item = WordBreakToken<'a>;
22744
22745    fn next(&mut self) -> Option<Self::Item> {
22746        use unicode_segmentation::UnicodeSegmentation;
22747        if self.input.is_empty() {
22748            return None;
22749        }
22750
22751        let mut iter = self.input.graphemes(true).peekable();
22752        let mut offset = 0;
22753        let mut grapheme_len = 0;
22754        if let Some(first_grapheme) = iter.next() {
22755            let is_newline = first_grapheme == "\n";
22756            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22757            offset += first_grapheme.len();
22758            grapheme_len += 1;
22759            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22760                if let Some(grapheme) = iter.peek().copied()
22761                    && should_stay_with_preceding_ideograph(grapheme)
22762                {
22763                    offset += grapheme.len();
22764                    grapheme_len += 1;
22765                }
22766            } else {
22767                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22768                let mut next_word_bound = words.peek().copied();
22769                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22770                    next_word_bound = words.next();
22771                }
22772                while let Some(grapheme) = iter.peek().copied() {
22773                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22774                        break;
22775                    };
22776                    if is_grapheme_whitespace(grapheme) != is_whitespace
22777                        || (grapheme == "\n") != is_newline
22778                    {
22779                        break;
22780                    };
22781                    offset += grapheme.len();
22782                    grapheme_len += 1;
22783                    iter.next();
22784                }
22785            }
22786            let token = &self.input[..offset];
22787            self.input = &self.input[offset..];
22788            if token == "\n" {
22789                Some(WordBreakToken::Newline)
22790            } else if is_whitespace {
22791                Some(WordBreakToken::InlineWhitespace {
22792                    token,
22793                    grapheme_len,
22794                })
22795            } else {
22796                Some(WordBreakToken::Word {
22797                    token,
22798                    grapheme_len,
22799                })
22800            }
22801        } else {
22802            None
22803        }
22804    }
22805}
22806
22807#[test]
22808fn test_word_breaking_tokenizer() {
22809    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22810        ("", &[]),
22811        ("  ", &[whitespace("  ", 2)]),
22812        ("Ʒ", &[word("Ʒ", 1)]),
22813        ("Ǽ", &[word("Ǽ", 1)]),
22814        ("", &[word("", 1)]),
22815        ("⋑⋑", &[word("⋑⋑", 2)]),
22816        (
22817            "原理,进而",
22818            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22819        ),
22820        (
22821            "hello world",
22822            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22823        ),
22824        (
22825            "hello, world",
22826            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22827        ),
22828        (
22829            "  hello world",
22830            &[
22831                whitespace("  ", 2),
22832                word("hello", 5),
22833                whitespace(" ", 1),
22834                word("world", 5),
22835            ],
22836        ),
22837        (
22838            "这是什么 \n 钢笔",
22839            &[
22840                word("", 1),
22841                word("", 1),
22842                word("", 1),
22843                word("", 1),
22844                whitespace(" ", 1),
22845                newline(),
22846                whitespace(" ", 1),
22847                word("", 1),
22848                word("", 1),
22849            ],
22850        ),
22851        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22852    ];
22853
22854    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22855        WordBreakToken::Word {
22856            token,
22857            grapheme_len,
22858        }
22859    }
22860
22861    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22862        WordBreakToken::InlineWhitespace {
22863            token,
22864            grapheme_len,
22865        }
22866    }
22867
22868    fn newline() -> WordBreakToken<'static> {
22869        WordBreakToken::Newline
22870    }
22871
22872    for (input, result) in tests {
22873        assert_eq!(
22874            WordBreakingTokenizer::new(input)
22875                .collect::<Vec<_>>()
22876                .as_slice(),
22877            *result,
22878        );
22879    }
22880}
22881
22882fn wrap_with_prefix(
22883    first_line_prefix: String,
22884    subsequent_lines_prefix: String,
22885    unwrapped_text: String,
22886    wrap_column: usize,
22887    tab_size: NonZeroU32,
22888    preserve_existing_whitespace: bool,
22889) -> String {
22890    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22891    let subsequent_lines_prefix_len =
22892        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22893    let mut wrapped_text = String::new();
22894    let mut current_line = first_line_prefix;
22895    let mut is_first_line = true;
22896
22897    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22898    let mut current_line_len = first_line_prefix_len;
22899    let mut in_whitespace = false;
22900    for token in tokenizer {
22901        let have_preceding_whitespace = in_whitespace;
22902        match token {
22903            WordBreakToken::Word {
22904                token,
22905                grapheme_len,
22906            } => {
22907                in_whitespace = false;
22908                let current_prefix_len = if is_first_line {
22909                    first_line_prefix_len
22910                } else {
22911                    subsequent_lines_prefix_len
22912                };
22913                if current_line_len + grapheme_len > wrap_column
22914                    && current_line_len != current_prefix_len
22915                {
22916                    wrapped_text.push_str(current_line.trim_end());
22917                    wrapped_text.push('\n');
22918                    is_first_line = false;
22919                    current_line = subsequent_lines_prefix.clone();
22920                    current_line_len = subsequent_lines_prefix_len;
22921                }
22922                current_line.push_str(token);
22923                current_line_len += grapheme_len;
22924            }
22925            WordBreakToken::InlineWhitespace {
22926                mut token,
22927                mut grapheme_len,
22928            } => {
22929                in_whitespace = true;
22930                if have_preceding_whitespace && !preserve_existing_whitespace {
22931                    continue;
22932                }
22933                if !preserve_existing_whitespace {
22934                    // Keep a single whitespace grapheme as-is
22935                    if let Some(first) =
22936                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22937                    {
22938                        token = first;
22939                    } else {
22940                        token = " ";
22941                    }
22942                    grapheme_len = 1;
22943                }
22944                let current_prefix_len = if is_first_line {
22945                    first_line_prefix_len
22946                } else {
22947                    subsequent_lines_prefix_len
22948                };
22949                if current_line_len + grapheme_len > wrap_column {
22950                    wrapped_text.push_str(current_line.trim_end());
22951                    wrapped_text.push('\n');
22952                    is_first_line = false;
22953                    current_line = subsequent_lines_prefix.clone();
22954                    current_line_len = subsequent_lines_prefix_len;
22955                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22956                    current_line.push_str(token);
22957                    current_line_len += grapheme_len;
22958                }
22959            }
22960            WordBreakToken::Newline => {
22961                in_whitespace = true;
22962                let current_prefix_len = if is_first_line {
22963                    first_line_prefix_len
22964                } else {
22965                    subsequent_lines_prefix_len
22966                };
22967                if preserve_existing_whitespace {
22968                    wrapped_text.push_str(current_line.trim_end());
22969                    wrapped_text.push('\n');
22970                    is_first_line = false;
22971                    current_line = subsequent_lines_prefix.clone();
22972                    current_line_len = subsequent_lines_prefix_len;
22973                } else if have_preceding_whitespace {
22974                    continue;
22975                } else if current_line_len + 1 > wrap_column
22976                    && current_line_len != current_prefix_len
22977                {
22978                    wrapped_text.push_str(current_line.trim_end());
22979                    wrapped_text.push('\n');
22980                    is_first_line = false;
22981                    current_line = subsequent_lines_prefix.clone();
22982                    current_line_len = subsequent_lines_prefix_len;
22983                } else if current_line_len != current_prefix_len {
22984                    current_line.push(' ');
22985                    current_line_len += 1;
22986                }
22987            }
22988        }
22989    }
22990
22991    if !current_line.is_empty() {
22992        wrapped_text.push_str(&current_line);
22993    }
22994    wrapped_text
22995}
22996
22997#[test]
22998fn test_wrap_with_prefix() {
22999    assert_eq!(
23000        wrap_with_prefix(
23001            "# ".to_string(),
23002            "# ".to_string(),
23003            "abcdefg".to_string(),
23004            4,
23005            NonZeroU32::new(4).unwrap(),
23006            false,
23007        ),
23008        "# abcdefg"
23009    );
23010    assert_eq!(
23011        wrap_with_prefix(
23012            "".to_string(),
23013            "".to_string(),
23014            "\thello world".to_string(),
23015            8,
23016            NonZeroU32::new(4).unwrap(),
23017            false,
23018        ),
23019        "hello\nworld"
23020    );
23021    assert_eq!(
23022        wrap_with_prefix(
23023            "// ".to_string(),
23024            "// ".to_string(),
23025            "xx \nyy zz aa bb cc".to_string(),
23026            12,
23027            NonZeroU32::new(4).unwrap(),
23028            false,
23029        ),
23030        "// xx yy zz\n// aa bb cc"
23031    );
23032    assert_eq!(
23033        wrap_with_prefix(
23034            String::new(),
23035            String::new(),
23036            "这是什么 \n 钢笔".to_string(),
23037            3,
23038            NonZeroU32::new(4).unwrap(),
23039            false,
23040        ),
23041        "这是什\n么 钢\n"
23042    );
23043    assert_eq!(
23044        wrap_with_prefix(
23045            String::new(),
23046            String::new(),
23047            format!("foo{}bar", '\u{2009}'), // thin space
23048            80,
23049            NonZeroU32::new(4).unwrap(),
23050            false,
23051        ),
23052        format!("foo{}bar", '\u{2009}')
23053    );
23054}
23055
23056pub trait CollaborationHub {
23057    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23058    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23059    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23060}
23061
23062impl CollaborationHub for Entity<Project> {
23063    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23064        self.read(cx).collaborators()
23065    }
23066
23067    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23068        self.read(cx).user_store().read(cx).participant_indices()
23069    }
23070
23071    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23072        let this = self.read(cx);
23073        let user_ids = this.collaborators().values().map(|c| c.user_id);
23074        this.user_store().read(cx).participant_names(user_ids, cx)
23075    }
23076}
23077
23078pub trait SemanticsProvider {
23079    fn hover(
23080        &self,
23081        buffer: &Entity<Buffer>,
23082        position: text::Anchor,
23083        cx: &mut App,
23084    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23085
23086    fn inline_values(
23087        &self,
23088        buffer_handle: Entity<Buffer>,
23089        range: Range<text::Anchor>,
23090        cx: &mut App,
23091    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23092
23093    fn applicable_inlay_chunks(
23094        &self,
23095        buffer: &Entity<Buffer>,
23096        ranges: &[Range<text::Anchor>],
23097        cx: &mut App,
23098    ) -> Vec<Range<BufferRow>>;
23099
23100    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23101
23102    fn inlay_hints(
23103        &self,
23104        invalidate: InvalidationStrategy,
23105        buffer: Entity<Buffer>,
23106        ranges: Vec<Range<text::Anchor>>,
23107        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23108        cx: &mut App,
23109    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23110
23111    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23112
23113    fn document_highlights(
23114        &self,
23115        buffer: &Entity<Buffer>,
23116        position: text::Anchor,
23117        cx: &mut App,
23118    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23119
23120    fn definitions(
23121        &self,
23122        buffer: &Entity<Buffer>,
23123        position: text::Anchor,
23124        kind: GotoDefinitionKind,
23125        cx: &mut App,
23126    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23127
23128    fn range_for_rename(
23129        &self,
23130        buffer: &Entity<Buffer>,
23131        position: text::Anchor,
23132        cx: &mut App,
23133    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23134
23135    fn perform_rename(
23136        &self,
23137        buffer: &Entity<Buffer>,
23138        position: text::Anchor,
23139        new_name: String,
23140        cx: &mut App,
23141    ) -> Option<Task<Result<ProjectTransaction>>>;
23142}
23143
23144pub trait CompletionProvider {
23145    fn completions(
23146        &self,
23147        excerpt_id: ExcerptId,
23148        buffer: &Entity<Buffer>,
23149        buffer_position: text::Anchor,
23150        trigger: CompletionContext,
23151        window: &mut Window,
23152        cx: &mut Context<Editor>,
23153    ) -> Task<Result<Vec<CompletionResponse>>>;
23154
23155    fn resolve_completions(
23156        &self,
23157        _buffer: Entity<Buffer>,
23158        _completion_indices: Vec<usize>,
23159        _completions: Rc<RefCell<Box<[Completion]>>>,
23160        _cx: &mut Context<Editor>,
23161    ) -> Task<Result<bool>> {
23162        Task::ready(Ok(false))
23163    }
23164
23165    fn apply_additional_edits_for_completion(
23166        &self,
23167        _buffer: Entity<Buffer>,
23168        _completions: Rc<RefCell<Box<[Completion]>>>,
23169        _completion_index: usize,
23170        _push_to_history: bool,
23171        _cx: &mut Context<Editor>,
23172    ) -> Task<Result<Option<language::Transaction>>> {
23173        Task::ready(Ok(None))
23174    }
23175
23176    fn is_completion_trigger(
23177        &self,
23178        buffer: &Entity<Buffer>,
23179        position: language::Anchor,
23180        text: &str,
23181        trigger_in_words: bool,
23182        menu_is_open: bool,
23183        cx: &mut Context<Editor>,
23184    ) -> bool;
23185
23186    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23187
23188    fn sort_completions(&self) -> bool {
23189        true
23190    }
23191
23192    fn filter_completions(&self) -> bool {
23193        true
23194    }
23195
23196    fn show_snippets(&self) -> bool {
23197        false
23198    }
23199}
23200
23201pub trait CodeActionProvider {
23202    fn id(&self) -> Arc<str>;
23203
23204    fn code_actions(
23205        &self,
23206        buffer: &Entity<Buffer>,
23207        range: Range<text::Anchor>,
23208        window: &mut Window,
23209        cx: &mut App,
23210    ) -> Task<Result<Vec<CodeAction>>>;
23211
23212    fn apply_code_action(
23213        &self,
23214        buffer_handle: Entity<Buffer>,
23215        action: CodeAction,
23216        excerpt_id: ExcerptId,
23217        push_to_history: bool,
23218        window: &mut Window,
23219        cx: &mut App,
23220    ) -> Task<Result<ProjectTransaction>>;
23221}
23222
23223impl CodeActionProvider for Entity<Project> {
23224    fn id(&self) -> Arc<str> {
23225        "project".into()
23226    }
23227
23228    fn code_actions(
23229        &self,
23230        buffer: &Entity<Buffer>,
23231        range: Range<text::Anchor>,
23232        _window: &mut Window,
23233        cx: &mut App,
23234    ) -> Task<Result<Vec<CodeAction>>> {
23235        self.update(cx, |project, cx| {
23236            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23237            let code_actions = project.code_actions(buffer, range, None, cx);
23238            cx.background_spawn(async move {
23239                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23240                Ok(code_lens_actions
23241                    .context("code lens fetch")?
23242                    .into_iter()
23243                    .flatten()
23244                    .chain(
23245                        code_actions
23246                            .context("code action fetch")?
23247                            .into_iter()
23248                            .flatten(),
23249                    )
23250                    .collect())
23251            })
23252        })
23253    }
23254
23255    fn apply_code_action(
23256        &self,
23257        buffer_handle: Entity<Buffer>,
23258        action: CodeAction,
23259        _excerpt_id: ExcerptId,
23260        push_to_history: bool,
23261        _window: &mut Window,
23262        cx: &mut App,
23263    ) -> Task<Result<ProjectTransaction>> {
23264        self.update(cx, |project, cx| {
23265            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23266        })
23267    }
23268}
23269
23270fn snippet_completions(
23271    project: &Project,
23272    buffer: &Entity<Buffer>,
23273    buffer_anchor: text::Anchor,
23274    classifier: CharClassifier,
23275    cx: &mut App,
23276) -> Task<Result<CompletionResponse>> {
23277    let languages = buffer.read(cx).languages_at(buffer_anchor);
23278    let snippet_store = project.snippets().read(cx);
23279
23280    let scopes: Vec<_> = languages
23281        .iter()
23282        .filter_map(|language| {
23283            let language_name = language.lsp_id();
23284            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23285
23286            if snippets.is_empty() {
23287                None
23288            } else {
23289                Some((language.default_scope(), snippets))
23290            }
23291        })
23292        .collect();
23293
23294    if scopes.is_empty() {
23295        return Task::ready(Ok(CompletionResponse {
23296            completions: vec![],
23297            display_options: CompletionDisplayOptions::default(),
23298            is_incomplete: false,
23299        }));
23300    }
23301
23302    let snapshot = buffer.read(cx).text_snapshot();
23303    let executor = cx.background_executor().clone();
23304
23305    cx.background_spawn(async move {
23306        let is_word_char = |c| classifier.is_word(c);
23307
23308        let mut is_incomplete = false;
23309        let mut completions: Vec<Completion> = Vec::new();
23310
23311        const MAX_PREFIX_LEN: usize = 128;
23312        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23313        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23314        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23315
23316        let max_buffer_window: String = snapshot
23317            .text_for_range(window_start..buffer_offset)
23318            .collect();
23319
23320        if max_buffer_window.is_empty() {
23321            return Ok(CompletionResponse {
23322                completions: vec![],
23323                display_options: CompletionDisplayOptions::default(),
23324                is_incomplete: true,
23325            });
23326        }
23327
23328        for (_scope, snippets) in scopes.into_iter() {
23329            // Sort snippets by word count to match longer snippet prefixes first.
23330            let mut sorted_snippet_candidates = snippets
23331                .iter()
23332                .enumerate()
23333                .flat_map(|(snippet_ix, snippet)| {
23334                    snippet
23335                        .prefix
23336                        .iter()
23337                        .enumerate()
23338                        .map(move |(prefix_ix, prefix)| {
23339                            let word_count =
23340                                snippet_candidate_suffixes(prefix, is_word_char).count();
23341                            ((snippet_ix, prefix_ix), prefix, word_count)
23342                        })
23343                })
23344                .collect_vec();
23345            sorted_snippet_candidates
23346                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23347
23348            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23349
23350            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23351                .take(
23352                    sorted_snippet_candidates
23353                        .first()
23354                        .map(|(_, _, word_count)| *word_count)
23355                        .unwrap_or_default(),
23356                )
23357                .collect_vec();
23358
23359            const MAX_RESULTS: usize = 100;
23360            // Each match also remembers how many characters from the buffer it consumed
23361            let mut matches: Vec<(StringMatch, usize)> = vec![];
23362
23363            let mut snippet_list_cutoff_index = 0;
23364            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23365                let word_count = buffer_index + 1;
23366                // Increase `snippet_list_cutoff_index` until we have all of the
23367                // snippets with sufficiently many words.
23368                while sorted_snippet_candidates
23369                    .get(snippet_list_cutoff_index)
23370                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23371                        *snippet_word_count >= word_count
23372                    })
23373                {
23374                    snippet_list_cutoff_index += 1;
23375                }
23376
23377                // Take only the candidates with at least `word_count` many words
23378                let snippet_candidates_at_word_len =
23379                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23380
23381                let candidates = snippet_candidates_at_word_len
23382                    .iter()
23383                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23384                    .enumerate() // index in `sorted_snippet_candidates`
23385                    // First char must match
23386                    .filter(|(_ix, prefix)| {
23387                        itertools::equal(
23388                            prefix
23389                                .chars()
23390                                .next()
23391                                .into_iter()
23392                                .flat_map(|c| c.to_lowercase()),
23393                            buffer_window
23394                                .chars()
23395                                .next()
23396                                .into_iter()
23397                                .flat_map(|c| c.to_lowercase()),
23398                        )
23399                    })
23400                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23401                    .collect::<Vec<StringMatchCandidate>>();
23402
23403                matches.extend(
23404                    fuzzy::match_strings(
23405                        &candidates,
23406                        &buffer_window,
23407                        buffer_window.chars().any(|c| c.is_uppercase()),
23408                        true,
23409                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23410                        &Default::default(),
23411                        executor.clone(),
23412                    )
23413                    .await
23414                    .into_iter()
23415                    .map(|string_match| (string_match, buffer_window.len())),
23416                );
23417
23418                if matches.len() >= MAX_RESULTS {
23419                    break;
23420                }
23421            }
23422
23423            let to_lsp = |point: &text::Anchor| {
23424                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23425                point_to_lsp(end)
23426            };
23427            let lsp_end = to_lsp(&buffer_anchor);
23428
23429            if matches.len() >= MAX_RESULTS {
23430                is_incomplete = true;
23431            }
23432
23433            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23434                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23435                    sorted_snippet_candidates[string_match.candidate_id];
23436                let snippet = &snippets[snippet_index];
23437                let start = buffer_offset - buffer_window_len;
23438                let start = snapshot.anchor_before(start);
23439                let range = start..buffer_anchor;
23440                let lsp_start = to_lsp(&start);
23441                let lsp_range = lsp::Range {
23442                    start: lsp_start,
23443                    end: lsp_end,
23444                };
23445                Completion {
23446                    replace_range: range,
23447                    new_text: snippet.body.clone(),
23448                    source: CompletionSource::Lsp {
23449                        insert_range: None,
23450                        server_id: LanguageServerId(usize::MAX),
23451                        resolved: true,
23452                        lsp_completion: Box::new(lsp::CompletionItem {
23453                            label: snippet.prefix.first().unwrap().clone(),
23454                            kind: Some(CompletionItemKind::SNIPPET),
23455                            label_details: snippet.description.as_ref().map(|description| {
23456                                lsp::CompletionItemLabelDetails {
23457                                    detail: Some(description.clone()),
23458                                    description: None,
23459                                }
23460                            }),
23461                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23462                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23463                                lsp::InsertReplaceEdit {
23464                                    new_text: snippet.body.clone(),
23465                                    insert: lsp_range,
23466                                    replace: lsp_range,
23467                                },
23468                            )),
23469                            filter_text: Some(snippet.body.clone()),
23470                            sort_text: Some(char::MAX.to_string()),
23471                            ..lsp::CompletionItem::default()
23472                        }),
23473                        lsp_defaults: None,
23474                    },
23475                    label: CodeLabel {
23476                        text: matching_prefix.clone(),
23477                        runs: Vec::new(),
23478                        filter_range: 0..matching_prefix.len(),
23479                    },
23480                    icon_path: None,
23481                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23482                        single_line: snippet.name.clone().into(),
23483                        plain_text: snippet
23484                            .description
23485                            .clone()
23486                            .map(|description| description.into()),
23487                    }),
23488                    insert_text_mode: None,
23489                    confirm: None,
23490                    match_start: Some(start),
23491                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23492                }
23493            }));
23494        }
23495
23496        Ok(CompletionResponse {
23497            completions,
23498            display_options: CompletionDisplayOptions::default(),
23499            is_incomplete,
23500        })
23501    })
23502}
23503
23504impl CompletionProvider for Entity<Project> {
23505    fn completions(
23506        &self,
23507        _excerpt_id: ExcerptId,
23508        buffer: &Entity<Buffer>,
23509        buffer_position: text::Anchor,
23510        options: CompletionContext,
23511        _window: &mut Window,
23512        cx: &mut Context<Editor>,
23513    ) -> Task<Result<Vec<CompletionResponse>>> {
23514        self.update(cx, |project, cx| {
23515            let task = project.completions(buffer, buffer_position, options, cx);
23516            cx.background_spawn(task)
23517        })
23518    }
23519
23520    fn resolve_completions(
23521        &self,
23522        buffer: Entity<Buffer>,
23523        completion_indices: Vec<usize>,
23524        completions: Rc<RefCell<Box<[Completion]>>>,
23525        cx: &mut Context<Editor>,
23526    ) -> Task<Result<bool>> {
23527        self.update(cx, |project, cx| {
23528            project.lsp_store().update(cx, |lsp_store, cx| {
23529                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23530            })
23531        })
23532    }
23533
23534    fn apply_additional_edits_for_completion(
23535        &self,
23536        buffer: Entity<Buffer>,
23537        completions: Rc<RefCell<Box<[Completion]>>>,
23538        completion_index: usize,
23539        push_to_history: bool,
23540        cx: &mut Context<Editor>,
23541    ) -> Task<Result<Option<language::Transaction>>> {
23542        self.update(cx, |project, cx| {
23543            project.lsp_store().update(cx, |lsp_store, cx| {
23544                lsp_store.apply_additional_edits_for_completion(
23545                    buffer,
23546                    completions,
23547                    completion_index,
23548                    push_to_history,
23549                    cx,
23550                )
23551            })
23552        })
23553    }
23554
23555    fn is_completion_trigger(
23556        &self,
23557        buffer: &Entity<Buffer>,
23558        position: language::Anchor,
23559        text: &str,
23560        trigger_in_words: bool,
23561        menu_is_open: bool,
23562        cx: &mut Context<Editor>,
23563    ) -> bool {
23564        let mut chars = text.chars();
23565        let char = if let Some(char) = chars.next() {
23566            char
23567        } else {
23568            return false;
23569        };
23570        if chars.next().is_some() {
23571            return false;
23572        }
23573
23574        let buffer = buffer.read(cx);
23575        let snapshot = buffer.snapshot();
23576        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23577            return false;
23578        }
23579        let classifier = snapshot
23580            .char_classifier_at(position)
23581            .scope_context(Some(CharScopeContext::Completion));
23582        if trigger_in_words && classifier.is_word(char) {
23583            return true;
23584        }
23585
23586        buffer.completion_triggers().contains(text)
23587    }
23588
23589    fn show_snippets(&self) -> bool {
23590        true
23591    }
23592}
23593
23594impl SemanticsProvider for Entity<Project> {
23595    fn hover(
23596        &self,
23597        buffer: &Entity<Buffer>,
23598        position: text::Anchor,
23599        cx: &mut App,
23600    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23601        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23602    }
23603
23604    fn document_highlights(
23605        &self,
23606        buffer: &Entity<Buffer>,
23607        position: text::Anchor,
23608        cx: &mut App,
23609    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23610        Some(self.update(cx, |project, cx| {
23611            project.document_highlights(buffer, position, cx)
23612        }))
23613    }
23614
23615    fn definitions(
23616        &self,
23617        buffer: &Entity<Buffer>,
23618        position: text::Anchor,
23619        kind: GotoDefinitionKind,
23620        cx: &mut App,
23621    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23622        Some(self.update(cx, |project, cx| match kind {
23623            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23624            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23625            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23626            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23627        }))
23628    }
23629
23630    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23631        self.update(cx, |project, cx| {
23632            if project
23633                .active_debug_session(cx)
23634                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23635            {
23636                return true;
23637            }
23638
23639            buffer.update(cx, |buffer, cx| {
23640                project.any_language_server_supports_inlay_hints(buffer, cx)
23641            })
23642        })
23643    }
23644
23645    fn inline_values(
23646        &self,
23647        buffer_handle: Entity<Buffer>,
23648        range: Range<text::Anchor>,
23649        cx: &mut App,
23650    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23651        self.update(cx, |project, cx| {
23652            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23653
23654            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23655        })
23656    }
23657
23658    fn applicable_inlay_chunks(
23659        &self,
23660        buffer: &Entity<Buffer>,
23661        ranges: &[Range<text::Anchor>],
23662        cx: &mut App,
23663    ) -> Vec<Range<BufferRow>> {
23664        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23665            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23666        })
23667    }
23668
23669    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23670        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23671            lsp_store.invalidate_inlay_hints(for_buffers)
23672        });
23673    }
23674
23675    fn inlay_hints(
23676        &self,
23677        invalidate: InvalidationStrategy,
23678        buffer: Entity<Buffer>,
23679        ranges: Vec<Range<text::Anchor>>,
23680        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23681        cx: &mut App,
23682    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23683        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23684            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23685        }))
23686    }
23687
23688    fn range_for_rename(
23689        &self,
23690        buffer: &Entity<Buffer>,
23691        position: text::Anchor,
23692        cx: &mut App,
23693    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23694        Some(self.update(cx, |project, cx| {
23695            let buffer = buffer.clone();
23696            let task = project.prepare_rename(buffer.clone(), position, cx);
23697            cx.spawn(async move |_, cx| {
23698                Ok(match task.await? {
23699                    PrepareRenameResponse::Success(range) => Some(range),
23700                    PrepareRenameResponse::InvalidPosition => None,
23701                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23702                        // Fallback on using TreeSitter info to determine identifier range
23703                        buffer.read_with(cx, |buffer, _| {
23704                            let snapshot = buffer.snapshot();
23705                            let (range, kind) = snapshot.surrounding_word(position, None);
23706                            if kind != Some(CharKind::Word) {
23707                                return None;
23708                            }
23709                            Some(
23710                                snapshot.anchor_before(range.start)
23711                                    ..snapshot.anchor_after(range.end),
23712                            )
23713                        })?
23714                    }
23715                })
23716            })
23717        }))
23718    }
23719
23720    fn perform_rename(
23721        &self,
23722        buffer: &Entity<Buffer>,
23723        position: text::Anchor,
23724        new_name: String,
23725        cx: &mut App,
23726    ) -> Option<Task<Result<ProjectTransaction>>> {
23727        Some(self.update(cx, |project, cx| {
23728            project.perform_rename(buffer.clone(), position, new_name, cx)
23729        }))
23730    }
23731}
23732
23733fn consume_contiguous_rows(
23734    contiguous_row_selections: &mut Vec<Selection<Point>>,
23735    selection: &Selection<Point>,
23736    display_map: &DisplaySnapshot,
23737    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23738) -> (MultiBufferRow, MultiBufferRow) {
23739    contiguous_row_selections.push(selection.clone());
23740    let start_row = starting_row(selection, display_map);
23741    let mut end_row = ending_row(selection, display_map);
23742
23743    while let Some(next_selection) = selections.peek() {
23744        if next_selection.start.row <= end_row.0 {
23745            end_row = ending_row(next_selection, display_map);
23746            contiguous_row_selections.push(selections.next().unwrap().clone());
23747        } else {
23748            break;
23749        }
23750    }
23751    (start_row, end_row)
23752}
23753
23754fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23755    if selection.start.column > 0 {
23756        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23757    } else {
23758        MultiBufferRow(selection.start.row)
23759    }
23760}
23761
23762fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23763    if next_selection.end.column > 0 || next_selection.is_empty() {
23764        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23765    } else {
23766        MultiBufferRow(next_selection.end.row)
23767    }
23768}
23769
23770impl EditorSnapshot {
23771    pub fn remote_selections_in_range<'a>(
23772        &'a self,
23773        range: &'a Range<Anchor>,
23774        collaboration_hub: &dyn CollaborationHub,
23775        cx: &'a App,
23776    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23777        let participant_names = collaboration_hub.user_names(cx);
23778        let participant_indices = collaboration_hub.user_participant_indices(cx);
23779        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23780        let collaborators_by_replica_id = collaborators_by_peer_id
23781            .values()
23782            .map(|collaborator| (collaborator.replica_id, collaborator))
23783            .collect::<HashMap<_, _>>();
23784        self.buffer_snapshot()
23785            .selections_in_range(range, false)
23786            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23787                if replica_id == ReplicaId::AGENT {
23788                    Some(RemoteSelection {
23789                        replica_id,
23790                        selection,
23791                        cursor_shape,
23792                        line_mode,
23793                        collaborator_id: CollaboratorId::Agent,
23794                        user_name: Some("Agent".into()),
23795                        color: cx.theme().players().agent(),
23796                    })
23797                } else {
23798                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23799                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23800                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23801                    Some(RemoteSelection {
23802                        replica_id,
23803                        selection,
23804                        cursor_shape,
23805                        line_mode,
23806                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23807                        user_name,
23808                        color: if let Some(index) = participant_index {
23809                            cx.theme().players().color_for_participant(index.0)
23810                        } else {
23811                            cx.theme().players().absent()
23812                        },
23813                    })
23814                }
23815            })
23816    }
23817
23818    pub fn hunks_for_ranges(
23819        &self,
23820        ranges: impl IntoIterator<Item = Range<Point>>,
23821    ) -> Vec<MultiBufferDiffHunk> {
23822        let mut hunks = Vec::new();
23823        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23824            HashMap::default();
23825        for query_range in ranges {
23826            let query_rows =
23827                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23828            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23829                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23830            ) {
23831                // Include deleted hunks that are adjacent to the query range, because
23832                // otherwise they would be missed.
23833                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23834                if hunk.status().is_deleted() {
23835                    intersects_range |= hunk.row_range.start == query_rows.end;
23836                    intersects_range |= hunk.row_range.end == query_rows.start;
23837                }
23838                if intersects_range {
23839                    if !processed_buffer_rows
23840                        .entry(hunk.buffer_id)
23841                        .or_default()
23842                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23843                    {
23844                        continue;
23845                    }
23846                    hunks.push(hunk);
23847                }
23848            }
23849        }
23850
23851        hunks
23852    }
23853
23854    fn display_diff_hunks_for_rows<'a>(
23855        &'a self,
23856        display_rows: Range<DisplayRow>,
23857        folded_buffers: &'a HashSet<BufferId>,
23858    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23859        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23860        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23861
23862        self.buffer_snapshot()
23863            .diff_hunks_in_range(buffer_start..buffer_end)
23864            .filter_map(|hunk| {
23865                if folded_buffers.contains(&hunk.buffer_id) {
23866                    return None;
23867                }
23868
23869                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23870                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23871
23872                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23873                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23874
23875                let display_hunk = if hunk_display_start.column() != 0 {
23876                    DisplayDiffHunk::Folded {
23877                        display_row: hunk_display_start.row(),
23878                    }
23879                } else {
23880                    let mut end_row = hunk_display_end.row();
23881                    if hunk_display_end.column() > 0 {
23882                        end_row.0 += 1;
23883                    }
23884                    let is_created_file = hunk.is_created_file();
23885                    DisplayDiffHunk::Unfolded {
23886                        status: hunk.status(),
23887                        diff_base_byte_range: hunk.diff_base_byte_range,
23888                        display_row_range: hunk_display_start.row()..end_row,
23889                        multi_buffer_range: Anchor::range_in_buffer(
23890                            hunk.excerpt_id,
23891                            hunk.buffer_id,
23892                            hunk.buffer_range,
23893                        ),
23894                        is_created_file,
23895                    }
23896                };
23897
23898                Some(display_hunk)
23899            })
23900    }
23901
23902    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23903        self.display_snapshot
23904            .buffer_snapshot()
23905            .language_at(position)
23906    }
23907
23908    pub fn is_focused(&self) -> bool {
23909        self.is_focused
23910    }
23911
23912    pub fn placeholder_text(&self) -> Option<String> {
23913        self.placeholder_display_snapshot
23914            .as_ref()
23915            .map(|display_map| display_map.text())
23916    }
23917
23918    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23919        self.scroll_anchor.scroll_position(&self.display_snapshot)
23920    }
23921
23922    fn gutter_dimensions(
23923        &self,
23924        font_id: FontId,
23925        font_size: Pixels,
23926        max_line_number_width: Pixels,
23927        cx: &App,
23928    ) -> Option<GutterDimensions> {
23929        if !self.show_gutter {
23930            return None;
23931        }
23932
23933        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23934        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23935
23936        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23937            matches!(
23938                ProjectSettings::get_global(cx).git.git_gutter,
23939                GitGutterSetting::TrackedFiles
23940            )
23941        });
23942        let gutter_settings = EditorSettings::get_global(cx).gutter;
23943        let show_line_numbers = self
23944            .show_line_numbers
23945            .unwrap_or(gutter_settings.line_numbers);
23946        let line_gutter_width = if show_line_numbers {
23947            // Avoid flicker-like gutter resizes when the line number gains another digit by
23948            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23949            let min_width_for_number_on_gutter =
23950                ch_advance * gutter_settings.min_line_number_digits as f32;
23951            max_line_number_width.max(min_width_for_number_on_gutter)
23952        } else {
23953            0.0.into()
23954        };
23955
23956        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23957        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23958
23959        let git_blame_entries_width =
23960            self.git_blame_gutter_max_author_length
23961                .map(|max_author_length| {
23962                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23963                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23964
23965                    /// The number of characters to dedicate to gaps and margins.
23966                    const SPACING_WIDTH: usize = 4;
23967
23968                    let max_char_count = max_author_length.min(renderer.max_author_length())
23969                        + ::git::SHORT_SHA_LENGTH
23970                        + MAX_RELATIVE_TIMESTAMP.len()
23971                        + SPACING_WIDTH;
23972
23973                    ch_advance * max_char_count
23974                });
23975
23976        let is_singleton = self.buffer_snapshot().is_singleton();
23977
23978        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23979        left_padding += if !is_singleton {
23980            ch_width * 4.0
23981        } else if show_runnables || show_breakpoints {
23982            ch_width * 3.0
23983        } else if show_git_gutter && show_line_numbers {
23984            ch_width * 2.0
23985        } else if show_git_gutter || show_line_numbers {
23986            ch_width
23987        } else {
23988            px(0.)
23989        };
23990
23991        let shows_folds = is_singleton && gutter_settings.folds;
23992
23993        let right_padding = if shows_folds && show_line_numbers {
23994            ch_width * 4.0
23995        } else if shows_folds || (!is_singleton && show_line_numbers) {
23996            ch_width * 3.0
23997        } else if show_line_numbers {
23998            ch_width
23999        } else {
24000            px(0.)
24001        };
24002
24003        Some(GutterDimensions {
24004            left_padding,
24005            right_padding,
24006            width: line_gutter_width + left_padding + right_padding,
24007            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24008            git_blame_entries_width,
24009        })
24010    }
24011
24012    pub fn render_crease_toggle(
24013        &self,
24014        buffer_row: MultiBufferRow,
24015        row_contains_cursor: bool,
24016        editor: Entity<Editor>,
24017        window: &mut Window,
24018        cx: &mut App,
24019    ) -> Option<AnyElement> {
24020        let folded = self.is_line_folded(buffer_row);
24021        let mut is_foldable = false;
24022
24023        if let Some(crease) = self
24024            .crease_snapshot
24025            .query_row(buffer_row, self.buffer_snapshot())
24026        {
24027            is_foldable = true;
24028            match crease {
24029                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24030                    if let Some(render_toggle) = render_toggle {
24031                        let toggle_callback =
24032                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24033                                if folded {
24034                                    editor.update(cx, |editor, cx| {
24035                                        editor.fold_at(buffer_row, window, cx)
24036                                    });
24037                                } else {
24038                                    editor.update(cx, |editor, cx| {
24039                                        editor.unfold_at(buffer_row, window, cx)
24040                                    });
24041                                }
24042                            });
24043                        return Some((render_toggle)(
24044                            buffer_row,
24045                            folded,
24046                            toggle_callback,
24047                            window,
24048                            cx,
24049                        ));
24050                    }
24051                }
24052            }
24053        }
24054
24055        is_foldable |= self.starts_indent(buffer_row);
24056
24057        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24058            Some(
24059                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24060                    .toggle_state(folded)
24061                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24062                        if folded {
24063                            this.unfold_at(buffer_row, window, cx);
24064                        } else {
24065                            this.fold_at(buffer_row, window, cx);
24066                        }
24067                    }))
24068                    .into_any_element(),
24069            )
24070        } else {
24071            None
24072        }
24073    }
24074
24075    pub fn render_crease_trailer(
24076        &self,
24077        buffer_row: MultiBufferRow,
24078        window: &mut Window,
24079        cx: &mut App,
24080    ) -> Option<AnyElement> {
24081        let folded = self.is_line_folded(buffer_row);
24082        if let Crease::Inline { render_trailer, .. } = self
24083            .crease_snapshot
24084            .query_row(buffer_row, self.buffer_snapshot())?
24085        {
24086            let render_trailer = render_trailer.as_ref()?;
24087            Some(render_trailer(buffer_row, folded, window, cx))
24088        } else {
24089            None
24090        }
24091    }
24092}
24093
24094impl Deref for EditorSnapshot {
24095    type Target = DisplaySnapshot;
24096
24097    fn deref(&self) -> &Self::Target {
24098        &self.display_snapshot
24099    }
24100}
24101
24102#[derive(Clone, Debug, PartialEq, Eq)]
24103pub enum EditorEvent {
24104    InputIgnored {
24105        text: Arc<str>,
24106    },
24107    InputHandled {
24108        utf16_range_to_replace: Option<Range<isize>>,
24109        text: Arc<str>,
24110    },
24111    ExcerptsAdded {
24112        buffer: Entity<Buffer>,
24113        predecessor: ExcerptId,
24114        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24115    },
24116    ExcerptsRemoved {
24117        ids: Vec<ExcerptId>,
24118        removed_buffer_ids: Vec<BufferId>,
24119    },
24120    BufferFoldToggled {
24121        ids: Vec<ExcerptId>,
24122        folded: bool,
24123    },
24124    ExcerptsEdited {
24125        ids: Vec<ExcerptId>,
24126    },
24127    ExcerptsExpanded {
24128        ids: Vec<ExcerptId>,
24129    },
24130    BufferEdited,
24131    Edited {
24132        transaction_id: clock::Lamport,
24133    },
24134    Reparsed(BufferId),
24135    Focused,
24136    FocusedIn,
24137    Blurred,
24138    DirtyChanged,
24139    Saved,
24140    TitleChanged,
24141    SelectionsChanged {
24142        local: bool,
24143    },
24144    ScrollPositionChanged {
24145        local: bool,
24146        autoscroll: bool,
24147    },
24148    TransactionUndone {
24149        transaction_id: clock::Lamport,
24150    },
24151    TransactionBegun {
24152        transaction_id: clock::Lamport,
24153    },
24154    CursorShapeChanged,
24155    BreadcrumbsChanged,
24156    PushedToNavHistory {
24157        anchor: Anchor,
24158        is_deactivate: bool,
24159    },
24160}
24161
24162impl EventEmitter<EditorEvent> for Editor {}
24163
24164impl Focusable for Editor {
24165    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24166        self.focus_handle.clone()
24167    }
24168}
24169
24170impl Render for Editor {
24171    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24172        let settings = ThemeSettings::get_global(cx);
24173
24174        let mut text_style = match self.mode {
24175            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24176                color: cx.theme().colors().editor_foreground,
24177                font_family: settings.ui_font.family.clone(),
24178                font_features: settings.ui_font.features.clone(),
24179                font_fallbacks: settings.ui_font.fallbacks.clone(),
24180                font_size: rems(0.875).into(),
24181                font_weight: settings.ui_font.weight,
24182                line_height: relative(settings.buffer_line_height.value()),
24183                ..Default::default()
24184            },
24185            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24186                color: cx.theme().colors().editor_foreground,
24187                font_family: settings.buffer_font.family.clone(),
24188                font_features: settings.buffer_font.features.clone(),
24189                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24190                font_size: settings.buffer_font_size(cx).into(),
24191                font_weight: settings.buffer_font.weight,
24192                line_height: relative(settings.buffer_line_height.value()),
24193                ..Default::default()
24194            },
24195        };
24196        if let Some(text_style_refinement) = &self.text_style_refinement {
24197            text_style.refine(text_style_refinement)
24198        }
24199
24200        let background = match self.mode {
24201            EditorMode::SingleLine => cx.theme().system().transparent,
24202            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24203            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24204            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24205        };
24206
24207        EditorElement::new(
24208            &cx.entity(),
24209            EditorStyle {
24210                background,
24211                border: cx.theme().colors().border,
24212                local_player: cx.theme().players().local(),
24213                text: text_style,
24214                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24215                syntax: cx.theme().syntax().clone(),
24216                status: cx.theme().status().clone(),
24217                inlay_hints_style: make_inlay_hints_style(cx),
24218                edit_prediction_styles: make_suggestion_styles(cx),
24219                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24220                show_underlines: self.diagnostics_enabled(),
24221            },
24222        )
24223    }
24224}
24225
24226impl EntityInputHandler for Editor {
24227    fn text_for_range(
24228        &mut self,
24229        range_utf16: Range<usize>,
24230        adjusted_range: &mut Option<Range<usize>>,
24231        _: &mut Window,
24232        cx: &mut Context<Self>,
24233    ) -> Option<String> {
24234        let snapshot = self.buffer.read(cx).read(cx);
24235        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24236        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24237        if (start.0..end.0) != range_utf16 {
24238            adjusted_range.replace(start.0..end.0);
24239        }
24240        Some(snapshot.text_for_range(start..end).collect())
24241    }
24242
24243    fn selected_text_range(
24244        &mut self,
24245        ignore_disabled_input: bool,
24246        _: &mut Window,
24247        cx: &mut Context<Self>,
24248    ) -> Option<UTF16Selection> {
24249        // Prevent the IME menu from appearing when holding down an alphabetic key
24250        // while input is disabled.
24251        if !ignore_disabled_input && !self.input_enabled {
24252            return None;
24253        }
24254
24255        let selection = self
24256            .selections
24257            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24258        let range = selection.range();
24259
24260        Some(UTF16Selection {
24261            range: range.start.0..range.end.0,
24262            reversed: selection.reversed,
24263        })
24264    }
24265
24266    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24267        let snapshot = self.buffer.read(cx).read(cx);
24268        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24269        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24270    }
24271
24272    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24273        self.clear_highlights::<InputComposition>(cx);
24274        self.ime_transaction.take();
24275    }
24276
24277    fn replace_text_in_range(
24278        &mut self,
24279        range_utf16: Option<Range<usize>>,
24280        text: &str,
24281        window: &mut Window,
24282        cx: &mut Context<Self>,
24283    ) {
24284        if !self.input_enabled {
24285            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24286            return;
24287        }
24288
24289        self.transact(window, cx, |this, window, cx| {
24290            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24291                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24292                Some(this.selection_replacement_ranges(range_utf16, cx))
24293            } else {
24294                this.marked_text_ranges(cx)
24295            };
24296
24297            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24298                let newest_selection_id = this.selections.newest_anchor().id;
24299                this.selections
24300                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24301                    .iter()
24302                    .zip(ranges_to_replace.iter())
24303                    .find_map(|(selection, range)| {
24304                        if selection.id == newest_selection_id {
24305                            Some(
24306                                (range.start.0 as isize - selection.head().0 as isize)
24307                                    ..(range.end.0 as isize - selection.head().0 as isize),
24308                            )
24309                        } else {
24310                            None
24311                        }
24312                    })
24313            });
24314
24315            cx.emit(EditorEvent::InputHandled {
24316                utf16_range_to_replace: range_to_replace,
24317                text: text.into(),
24318            });
24319
24320            if let Some(new_selected_ranges) = new_selected_ranges {
24321                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24322                    selections.select_ranges(new_selected_ranges)
24323                });
24324                this.backspace(&Default::default(), window, cx);
24325            }
24326
24327            this.handle_input(text, window, cx);
24328        });
24329
24330        if let Some(transaction) = self.ime_transaction {
24331            self.buffer.update(cx, |buffer, cx| {
24332                buffer.group_until_transaction(transaction, cx);
24333            });
24334        }
24335
24336        self.unmark_text(window, cx);
24337    }
24338
24339    fn replace_and_mark_text_in_range(
24340        &mut self,
24341        range_utf16: Option<Range<usize>>,
24342        text: &str,
24343        new_selected_range_utf16: Option<Range<usize>>,
24344        window: &mut Window,
24345        cx: &mut Context<Self>,
24346    ) {
24347        if !self.input_enabled {
24348            return;
24349        }
24350
24351        let transaction = self.transact(window, cx, |this, window, cx| {
24352            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24353                let snapshot = this.buffer.read(cx).read(cx);
24354                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24355                    for marked_range in &mut marked_ranges {
24356                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24357                        marked_range.start.0 += relative_range_utf16.start;
24358                        marked_range.start =
24359                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24360                        marked_range.end =
24361                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24362                    }
24363                }
24364                Some(marked_ranges)
24365            } else if let Some(range_utf16) = range_utf16 {
24366                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24367                Some(this.selection_replacement_ranges(range_utf16, cx))
24368            } else {
24369                None
24370            };
24371
24372            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24373                let newest_selection_id = this.selections.newest_anchor().id;
24374                this.selections
24375                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24376                    .iter()
24377                    .zip(ranges_to_replace.iter())
24378                    .find_map(|(selection, range)| {
24379                        if selection.id == newest_selection_id {
24380                            Some(
24381                                (range.start.0 as isize - selection.head().0 as isize)
24382                                    ..(range.end.0 as isize - selection.head().0 as isize),
24383                            )
24384                        } else {
24385                            None
24386                        }
24387                    })
24388            });
24389
24390            cx.emit(EditorEvent::InputHandled {
24391                utf16_range_to_replace: range_to_replace,
24392                text: text.into(),
24393            });
24394
24395            if let Some(ranges) = ranges_to_replace {
24396                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24397                    s.select_ranges(ranges)
24398                });
24399            }
24400
24401            let marked_ranges = {
24402                let snapshot = this.buffer.read(cx).read(cx);
24403                this.selections
24404                    .disjoint_anchors_arc()
24405                    .iter()
24406                    .map(|selection| {
24407                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24408                    })
24409                    .collect::<Vec<_>>()
24410            };
24411
24412            if text.is_empty() {
24413                this.unmark_text(window, cx);
24414            } else {
24415                this.highlight_text::<InputComposition>(
24416                    marked_ranges.clone(),
24417                    HighlightStyle {
24418                        underline: Some(UnderlineStyle {
24419                            thickness: px(1.),
24420                            color: None,
24421                            wavy: false,
24422                        }),
24423                        ..Default::default()
24424                    },
24425                    cx,
24426                );
24427            }
24428
24429            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24430            let use_autoclose = this.use_autoclose;
24431            let use_auto_surround = this.use_auto_surround;
24432            this.set_use_autoclose(false);
24433            this.set_use_auto_surround(false);
24434            this.handle_input(text, window, cx);
24435            this.set_use_autoclose(use_autoclose);
24436            this.set_use_auto_surround(use_auto_surround);
24437
24438            if let Some(new_selected_range) = new_selected_range_utf16 {
24439                let snapshot = this.buffer.read(cx).read(cx);
24440                let new_selected_ranges = marked_ranges
24441                    .into_iter()
24442                    .map(|marked_range| {
24443                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24444                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24445                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24446                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24447                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24448                    })
24449                    .collect::<Vec<_>>();
24450
24451                drop(snapshot);
24452                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24453                    selections.select_ranges(new_selected_ranges)
24454                });
24455            }
24456        });
24457
24458        self.ime_transaction = self.ime_transaction.or(transaction);
24459        if let Some(transaction) = self.ime_transaction {
24460            self.buffer.update(cx, |buffer, cx| {
24461                buffer.group_until_transaction(transaction, cx);
24462            });
24463        }
24464
24465        if self.text_highlights::<InputComposition>(cx).is_none() {
24466            self.ime_transaction.take();
24467        }
24468    }
24469
24470    fn bounds_for_range(
24471        &mut self,
24472        range_utf16: Range<usize>,
24473        element_bounds: gpui::Bounds<Pixels>,
24474        window: &mut Window,
24475        cx: &mut Context<Self>,
24476    ) -> Option<gpui::Bounds<Pixels>> {
24477        let text_layout_details = self.text_layout_details(window);
24478        let CharacterDimensions {
24479            em_width,
24480            em_advance,
24481            line_height,
24482        } = self.character_dimensions(window);
24483
24484        let snapshot = self.snapshot(window, cx);
24485        let scroll_position = snapshot.scroll_position();
24486        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24487
24488        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24489        let x = Pixels::from(
24490            ScrollOffset::from(
24491                snapshot.x_for_display_point(start, &text_layout_details)
24492                    + self.gutter_dimensions.full_width(),
24493            ) - scroll_left,
24494        );
24495        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24496
24497        Some(Bounds {
24498            origin: element_bounds.origin + point(x, y),
24499            size: size(em_width, line_height),
24500        })
24501    }
24502
24503    fn character_index_for_point(
24504        &mut self,
24505        point: gpui::Point<Pixels>,
24506        _window: &mut Window,
24507        _cx: &mut Context<Self>,
24508    ) -> Option<usize> {
24509        let position_map = self.last_position_map.as_ref()?;
24510        if !position_map.text_hitbox.contains(&point) {
24511            return None;
24512        }
24513        let display_point = position_map.point_for_position(point).previous_valid;
24514        let anchor = position_map
24515            .snapshot
24516            .display_point_to_anchor(display_point, Bias::Left);
24517        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24518        Some(utf16_offset.0)
24519    }
24520
24521    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24522        self.input_enabled
24523    }
24524}
24525
24526trait SelectionExt {
24527    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24528    fn spanned_rows(
24529        &self,
24530        include_end_if_at_line_start: bool,
24531        map: &DisplaySnapshot,
24532    ) -> Range<MultiBufferRow>;
24533}
24534
24535impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24536    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24537        let start = self
24538            .start
24539            .to_point(map.buffer_snapshot())
24540            .to_display_point(map);
24541        let end = self
24542            .end
24543            .to_point(map.buffer_snapshot())
24544            .to_display_point(map);
24545        if self.reversed {
24546            end..start
24547        } else {
24548            start..end
24549        }
24550    }
24551
24552    fn spanned_rows(
24553        &self,
24554        include_end_if_at_line_start: bool,
24555        map: &DisplaySnapshot,
24556    ) -> Range<MultiBufferRow> {
24557        let start = self.start.to_point(map.buffer_snapshot());
24558        let mut end = self.end.to_point(map.buffer_snapshot());
24559        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24560            end.row -= 1;
24561        }
24562
24563        let buffer_start = map.prev_line_boundary(start).0;
24564        let buffer_end = map.next_line_boundary(end).0;
24565        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24566    }
24567}
24568
24569impl<T: InvalidationRegion> InvalidationStack<T> {
24570    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24571    where
24572        S: Clone + ToOffset,
24573    {
24574        while let Some(region) = self.last() {
24575            let all_selections_inside_invalidation_ranges =
24576                if selections.len() == region.ranges().len() {
24577                    selections
24578                        .iter()
24579                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24580                        .all(|(selection, invalidation_range)| {
24581                            let head = selection.head().to_offset(buffer);
24582                            invalidation_range.start <= head && invalidation_range.end >= head
24583                        })
24584                } else {
24585                    false
24586                };
24587
24588            if all_selections_inside_invalidation_ranges {
24589                break;
24590            } else {
24591                self.pop();
24592            }
24593        }
24594    }
24595}
24596
24597impl<T> Default for InvalidationStack<T> {
24598    fn default() -> Self {
24599        Self(Default::default())
24600    }
24601}
24602
24603impl<T> Deref for InvalidationStack<T> {
24604    type Target = Vec<T>;
24605
24606    fn deref(&self) -> &Self::Target {
24607        &self.0
24608    }
24609}
24610
24611impl<T> DerefMut for InvalidationStack<T> {
24612    fn deref_mut(&mut self) -> &mut Self::Target {
24613        &mut self.0
24614    }
24615}
24616
24617impl InvalidationRegion for SnippetState {
24618    fn ranges(&self) -> &[Range<Anchor>] {
24619        &self.ranges[self.active_index]
24620    }
24621}
24622
24623fn edit_prediction_edit_text(
24624    current_snapshot: &BufferSnapshot,
24625    edits: &[(Range<Anchor>, impl AsRef<str>)],
24626    edit_preview: &EditPreview,
24627    include_deletions: bool,
24628    cx: &App,
24629) -> HighlightedText {
24630    let edits = edits
24631        .iter()
24632        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24633        .collect::<Vec<_>>();
24634
24635    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24636}
24637
24638fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24639    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24640    // Just show the raw edit text with basic styling
24641    let mut text = String::new();
24642    let mut highlights = Vec::new();
24643
24644    let insertion_highlight_style = HighlightStyle {
24645        color: Some(cx.theme().colors().text),
24646        ..Default::default()
24647    };
24648
24649    for (_, edit_text) in edits {
24650        let start_offset = text.len();
24651        text.push_str(edit_text);
24652        let end_offset = text.len();
24653
24654        if start_offset < end_offset {
24655            highlights.push((start_offset..end_offset, insertion_highlight_style));
24656        }
24657    }
24658
24659    HighlightedText {
24660        text: text.into(),
24661        highlights,
24662    }
24663}
24664
24665pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24666    match severity {
24667        lsp::DiagnosticSeverity::ERROR => colors.error,
24668        lsp::DiagnosticSeverity::WARNING => colors.warning,
24669        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24670        lsp::DiagnosticSeverity::HINT => colors.info,
24671        _ => colors.ignored,
24672    }
24673}
24674
24675pub fn styled_runs_for_code_label<'a>(
24676    label: &'a CodeLabel,
24677    syntax_theme: &'a theme::SyntaxTheme,
24678) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24679    let fade_out = HighlightStyle {
24680        fade_out: Some(0.35),
24681        ..Default::default()
24682    };
24683
24684    let mut prev_end = label.filter_range.end;
24685    label
24686        .runs
24687        .iter()
24688        .enumerate()
24689        .flat_map(move |(ix, (range, highlight_id))| {
24690            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24691                style
24692            } else {
24693                return Default::default();
24694            };
24695            let muted_style = style.highlight(fade_out);
24696
24697            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24698            if range.start >= label.filter_range.end {
24699                if range.start > prev_end {
24700                    runs.push((prev_end..range.start, fade_out));
24701                }
24702                runs.push((range.clone(), muted_style));
24703            } else if range.end <= label.filter_range.end {
24704                runs.push((range.clone(), style));
24705            } else {
24706                runs.push((range.start..label.filter_range.end, style));
24707                runs.push((label.filter_range.end..range.end, muted_style));
24708            }
24709            prev_end = cmp::max(prev_end, range.end);
24710
24711            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24712                runs.push((prev_end..label.text.len(), fade_out));
24713            }
24714
24715            runs
24716        })
24717}
24718
24719pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24720    let mut prev_index = 0;
24721    let mut prev_codepoint: Option<char> = None;
24722    text.char_indices()
24723        .chain([(text.len(), '\0')])
24724        .filter_map(move |(index, codepoint)| {
24725            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24726            let is_boundary = index == text.len()
24727                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24728                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24729            if is_boundary {
24730                let chunk = &text[prev_index..index];
24731                prev_index = index;
24732                Some(chunk)
24733            } else {
24734                None
24735            }
24736        })
24737}
24738
24739/// Given a string of text immediately before the cursor, iterates over possible
24740/// strings a snippet could match to. More precisely: returns an iterator over
24741/// suffixes of `text` created by splitting at word boundaries (before & after
24742/// every non-word character).
24743///
24744/// Shorter suffixes are returned first.
24745pub(crate) fn snippet_candidate_suffixes(
24746    text: &str,
24747    is_word_char: impl Fn(char) -> bool,
24748) -> impl std::iter::Iterator<Item = &str> {
24749    let mut prev_index = text.len();
24750    let mut prev_codepoint = None;
24751    text.char_indices()
24752        .rev()
24753        .chain([(0, '\0')])
24754        .filter_map(move |(index, codepoint)| {
24755            let prev_index = std::mem::replace(&mut prev_index, index);
24756            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24757            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24758                None
24759            } else {
24760                let chunk = &text[prev_index..]; // go to end of string
24761                Some(chunk)
24762            }
24763        })
24764}
24765
24766pub trait RangeToAnchorExt: Sized {
24767    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24768
24769    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24770        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24771        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24772    }
24773}
24774
24775impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24776    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24777        let start_offset = self.start.to_offset(snapshot);
24778        let end_offset = self.end.to_offset(snapshot);
24779        if start_offset == end_offset {
24780            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24781        } else {
24782            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24783        }
24784    }
24785}
24786
24787pub trait RowExt {
24788    fn as_f64(&self) -> f64;
24789
24790    fn next_row(&self) -> Self;
24791
24792    fn previous_row(&self) -> Self;
24793
24794    fn minus(&self, other: Self) -> u32;
24795}
24796
24797impl RowExt for DisplayRow {
24798    fn as_f64(&self) -> f64 {
24799        self.0 as _
24800    }
24801
24802    fn next_row(&self) -> Self {
24803        Self(self.0 + 1)
24804    }
24805
24806    fn previous_row(&self) -> Self {
24807        Self(self.0.saturating_sub(1))
24808    }
24809
24810    fn minus(&self, other: Self) -> u32 {
24811        self.0 - other.0
24812    }
24813}
24814
24815impl RowExt for MultiBufferRow {
24816    fn as_f64(&self) -> f64 {
24817        self.0 as _
24818    }
24819
24820    fn next_row(&self) -> Self {
24821        Self(self.0 + 1)
24822    }
24823
24824    fn previous_row(&self) -> Self {
24825        Self(self.0.saturating_sub(1))
24826    }
24827
24828    fn minus(&self, other: Self) -> u32 {
24829        self.0 - other.0
24830    }
24831}
24832
24833trait RowRangeExt {
24834    type Row;
24835
24836    fn len(&self) -> usize;
24837
24838    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24839}
24840
24841impl RowRangeExt for Range<MultiBufferRow> {
24842    type Row = MultiBufferRow;
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 = MultiBufferRow> {
24849        (self.start.0..self.end.0).map(MultiBufferRow)
24850    }
24851}
24852
24853impl RowRangeExt for Range<DisplayRow> {
24854    type Row = DisplayRow;
24855
24856    fn len(&self) -> usize {
24857        (self.end.0 - self.start.0) as usize
24858    }
24859
24860    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24861        (self.start.0..self.end.0).map(DisplayRow)
24862    }
24863}
24864
24865/// If select range has more than one line, we
24866/// just point the cursor to range.start.
24867fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24868    if range.start.row == range.end.row {
24869        range
24870    } else {
24871        range.start..range.start
24872    }
24873}
24874pub struct KillRing(ClipboardItem);
24875impl Global for KillRing {}
24876
24877const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24878
24879enum BreakpointPromptEditAction {
24880    Log,
24881    Condition,
24882    HitCondition,
24883}
24884
24885struct BreakpointPromptEditor {
24886    pub(crate) prompt: Entity<Editor>,
24887    editor: WeakEntity<Editor>,
24888    breakpoint_anchor: Anchor,
24889    breakpoint: Breakpoint,
24890    edit_action: BreakpointPromptEditAction,
24891    block_ids: HashSet<CustomBlockId>,
24892    editor_margins: Arc<Mutex<EditorMargins>>,
24893    _subscriptions: Vec<Subscription>,
24894}
24895
24896impl BreakpointPromptEditor {
24897    const MAX_LINES: u8 = 4;
24898
24899    fn new(
24900        editor: WeakEntity<Editor>,
24901        breakpoint_anchor: Anchor,
24902        breakpoint: Breakpoint,
24903        edit_action: BreakpointPromptEditAction,
24904        window: &mut Window,
24905        cx: &mut Context<Self>,
24906    ) -> Self {
24907        let base_text = match edit_action {
24908            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24909            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24910            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24911        }
24912        .map(|msg| msg.to_string())
24913        .unwrap_or_default();
24914
24915        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24916        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24917
24918        let prompt = cx.new(|cx| {
24919            let mut prompt = Editor::new(
24920                EditorMode::AutoHeight {
24921                    min_lines: 1,
24922                    max_lines: Some(Self::MAX_LINES as usize),
24923                },
24924                buffer,
24925                None,
24926                window,
24927                cx,
24928            );
24929            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24930            prompt.set_show_cursor_when_unfocused(false, cx);
24931            prompt.set_placeholder_text(
24932                match edit_action {
24933                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24934                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24935                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24936                },
24937                window,
24938                cx,
24939            );
24940
24941            prompt
24942        });
24943
24944        Self {
24945            prompt,
24946            editor,
24947            breakpoint_anchor,
24948            breakpoint,
24949            edit_action,
24950            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24951            block_ids: Default::default(),
24952            _subscriptions: vec![],
24953        }
24954    }
24955
24956    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24957        self.block_ids.extend(block_ids)
24958    }
24959
24960    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24961        if let Some(editor) = self.editor.upgrade() {
24962            let message = self
24963                .prompt
24964                .read(cx)
24965                .buffer
24966                .read(cx)
24967                .as_singleton()
24968                .expect("A multi buffer in breakpoint prompt isn't possible")
24969                .read(cx)
24970                .as_rope()
24971                .to_string();
24972
24973            editor.update(cx, |editor, cx| {
24974                editor.edit_breakpoint_at_anchor(
24975                    self.breakpoint_anchor,
24976                    self.breakpoint.clone(),
24977                    match self.edit_action {
24978                        BreakpointPromptEditAction::Log => {
24979                            BreakpointEditAction::EditLogMessage(message.into())
24980                        }
24981                        BreakpointPromptEditAction::Condition => {
24982                            BreakpointEditAction::EditCondition(message.into())
24983                        }
24984                        BreakpointPromptEditAction::HitCondition => {
24985                            BreakpointEditAction::EditHitCondition(message.into())
24986                        }
24987                    },
24988                    cx,
24989                );
24990
24991                editor.remove_blocks(self.block_ids.clone(), None, cx);
24992                cx.focus_self(window);
24993            });
24994        }
24995    }
24996
24997    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24998        self.editor
24999            .update(cx, |editor, cx| {
25000                editor.remove_blocks(self.block_ids.clone(), None, cx);
25001                window.focus(&editor.focus_handle);
25002            })
25003            .log_err();
25004    }
25005
25006    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25007        let settings = ThemeSettings::get_global(cx);
25008        let text_style = TextStyle {
25009            color: if self.prompt.read(cx).read_only(cx) {
25010                cx.theme().colors().text_disabled
25011            } else {
25012                cx.theme().colors().text
25013            },
25014            font_family: settings.buffer_font.family.clone(),
25015            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25016            font_size: settings.buffer_font_size(cx).into(),
25017            font_weight: settings.buffer_font.weight,
25018            line_height: relative(settings.buffer_line_height.value()),
25019            ..Default::default()
25020        };
25021        EditorElement::new(
25022            &self.prompt,
25023            EditorStyle {
25024                background: cx.theme().colors().editor_background,
25025                local_player: cx.theme().players().local(),
25026                text: text_style,
25027                ..Default::default()
25028            },
25029        )
25030    }
25031}
25032
25033impl Render for BreakpointPromptEditor {
25034    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25035        let editor_margins = *self.editor_margins.lock();
25036        let gutter_dimensions = editor_margins.gutter;
25037        h_flex()
25038            .key_context("Editor")
25039            .bg(cx.theme().colors().editor_background)
25040            .border_y_1()
25041            .border_color(cx.theme().status().info_border)
25042            .size_full()
25043            .py(window.line_height() / 2.5)
25044            .on_action(cx.listener(Self::confirm))
25045            .on_action(cx.listener(Self::cancel))
25046            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25047            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25048    }
25049}
25050
25051impl Focusable for BreakpointPromptEditor {
25052    fn focus_handle(&self, cx: &App) -> FocusHandle {
25053        self.prompt.focus_handle(cx)
25054    }
25055}
25056
25057fn all_edits_insertions_or_deletions(
25058    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25059    snapshot: &MultiBufferSnapshot,
25060) -> bool {
25061    let mut all_insertions = true;
25062    let mut all_deletions = true;
25063
25064    for (range, new_text) in edits.iter() {
25065        let range_is_empty = range.to_offset(snapshot).is_empty();
25066        let text_is_empty = new_text.is_empty();
25067
25068        if range_is_empty != text_is_empty {
25069            if range_is_empty {
25070                all_deletions = false;
25071            } else {
25072                all_insertions = false;
25073            }
25074        } else {
25075            return false;
25076        }
25077
25078        if !all_insertions && !all_deletions {
25079            return false;
25080        }
25081    }
25082    all_insertions || all_deletions
25083}
25084
25085struct MissingEditPredictionKeybindingTooltip;
25086
25087impl Render for MissingEditPredictionKeybindingTooltip {
25088    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25089        ui::tooltip_container(cx, |container, cx| {
25090            container
25091                .flex_shrink_0()
25092                .max_w_80()
25093                .min_h(rems_from_px(124.))
25094                .justify_between()
25095                .child(
25096                    v_flex()
25097                        .flex_1()
25098                        .text_ui_sm(cx)
25099                        .child(Label::new("Conflict with Accept Keybinding"))
25100                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25101                )
25102                .child(
25103                    h_flex()
25104                        .pb_1()
25105                        .gap_1()
25106                        .items_end()
25107                        .w_full()
25108                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25109                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25110                        }))
25111                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25112                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25113                        })),
25114                )
25115        })
25116    }
25117}
25118
25119#[derive(Debug, Clone, Copy, PartialEq)]
25120pub struct LineHighlight {
25121    pub background: Background,
25122    pub border: Option<gpui::Hsla>,
25123    pub include_gutter: bool,
25124    pub type_id: Option<TypeId>,
25125}
25126
25127struct LineManipulationResult {
25128    pub new_text: String,
25129    pub line_count_before: usize,
25130    pub line_count_after: usize,
25131}
25132
25133fn render_diff_hunk_controls(
25134    row: u32,
25135    status: &DiffHunkStatus,
25136    hunk_range: Range<Anchor>,
25137    is_created_file: bool,
25138    line_height: Pixels,
25139    editor: &Entity<Editor>,
25140    _window: &mut Window,
25141    cx: &mut App,
25142) -> AnyElement {
25143    h_flex()
25144        .h(line_height)
25145        .mr_1()
25146        .gap_1()
25147        .px_0p5()
25148        .pb_1()
25149        .border_x_1()
25150        .border_b_1()
25151        .border_color(cx.theme().colors().border_variant)
25152        .rounded_b_lg()
25153        .bg(cx.theme().colors().editor_background)
25154        .gap_1()
25155        .block_mouse_except_scroll()
25156        .shadow_md()
25157        .child(if status.has_secondary_hunk() {
25158            Button::new(("stage", row as u64), "Stage")
25159                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25160                .tooltip({
25161                    let focus_handle = editor.focus_handle(cx);
25162                    move |_window, cx| {
25163                        Tooltip::for_action_in(
25164                            "Stage Hunk",
25165                            &::git::ToggleStaged,
25166                            &focus_handle,
25167                            cx,
25168                        )
25169                    }
25170                })
25171                .on_click({
25172                    let editor = editor.clone();
25173                    move |_event, _window, cx| {
25174                        editor.update(cx, |editor, cx| {
25175                            editor.stage_or_unstage_diff_hunks(
25176                                true,
25177                                vec![hunk_range.start..hunk_range.start],
25178                                cx,
25179                            );
25180                        });
25181                    }
25182                })
25183        } else {
25184            Button::new(("unstage", row as u64), "Unstage")
25185                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25186                .tooltip({
25187                    let focus_handle = editor.focus_handle(cx);
25188                    move |_window, cx| {
25189                        Tooltip::for_action_in(
25190                            "Unstage Hunk",
25191                            &::git::ToggleStaged,
25192                            &focus_handle,
25193                            cx,
25194                        )
25195                    }
25196                })
25197                .on_click({
25198                    let editor = editor.clone();
25199                    move |_event, _window, cx| {
25200                        editor.update(cx, |editor, cx| {
25201                            editor.stage_or_unstage_diff_hunks(
25202                                false,
25203                                vec![hunk_range.start..hunk_range.start],
25204                                cx,
25205                            );
25206                        });
25207                    }
25208                })
25209        })
25210        .child(
25211            Button::new(("restore", row as u64), "Restore")
25212                .tooltip({
25213                    let focus_handle = editor.focus_handle(cx);
25214                    move |_window, cx| {
25215                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25216                    }
25217                })
25218                .on_click({
25219                    let editor = editor.clone();
25220                    move |_event, window, cx| {
25221                        editor.update(cx, |editor, cx| {
25222                            let snapshot = editor.snapshot(window, cx);
25223                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25224                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25225                        });
25226                    }
25227                })
25228                .disabled(is_created_file),
25229        )
25230        .when(
25231            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25232            |el| {
25233                el.child(
25234                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25235                        .shape(IconButtonShape::Square)
25236                        .icon_size(IconSize::Small)
25237                        // .disabled(!has_multiple_hunks)
25238                        .tooltip({
25239                            let focus_handle = editor.focus_handle(cx);
25240                            move |_window, cx| {
25241                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25242                            }
25243                        })
25244                        .on_click({
25245                            let editor = editor.clone();
25246                            move |_event, window, cx| {
25247                                editor.update(cx, |editor, cx| {
25248                                    let snapshot = editor.snapshot(window, cx);
25249                                    let position =
25250                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25251                                    editor.go_to_hunk_before_or_after_position(
25252                                        &snapshot,
25253                                        position,
25254                                        Direction::Next,
25255                                        window,
25256                                        cx,
25257                                    );
25258                                    editor.expand_selected_diff_hunks(cx);
25259                                });
25260                            }
25261                        }),
25262                )
25263                .child(
25264                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25265                        .shape(IconButtonShape::Square)
25266                        .icon_size(IconSize::Small)
25267                        // .disabled(!has_multiple_hunks)
25268                        .tooltip({
25269                            let focus_handle = editor.focus_handle(cx);
25270                            move |_window, cx| {
25271                                Tooltip::for_action_in(
25272                                    "Previous Hunk",
25273                                    &GoToPreviousHunk,
25274                                    &focus_handle,
25275                                    cx,
25276                                )
25277                            }
25278                        })
25279                        .on_click({
25280                            let editor = editor.clone();
25281                            move |_event, window, cx| {
25282                                editor.update(cx, |editor, cx| {
25283                                    let snapshot = editor.snapshot(window, cx);
25284                                    let point =
25285                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25286                                    editor.go_to_hunk_before_or_after_position(
25287                                        &snapshot,
25288                                        point,
25289                                        Direction::Prev,
25290                                        window,
25291                                        cx,
25292                                    );
25293                                    editor.expand_selected_diff_hunks(cx);
25294                                });
25295                            }
25296                        }),
25297                )
25298            },
25299        )
25300        .into_any_element()
25301}
25302
25303pub fn multibuffer_context_lines(cx: &App) -> u32 {
25304    EditorSettings::try_get(cx)
25305        .map(|settings| settings.excerpt_context_lines)
25306        .unwrap_or(2)
25307        .min(32)
25308}