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;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction_types::Direction;
   55pub use editor_settings::{
   56    CompletionDetailAlignment, CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings,
   57    HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61    render_breadcrumb_text,
   62};
   63pub use git::blame::BlameRenderer;
   64pub use hover_popover::hover_markdown_style;
   65pub use inlays::Inlay;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   71    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   72    ToPoint,
   73};
   74pub use split::SplittableEditor;
   75pub use text::Bias;
   76
   77use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   78use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   79use anyhow::{Context as _, Result, anyhow, bail};
   80use blink_manager::BlinkManager;
   81use buffer_diff::DiffHunkStatus;
   82use client::{Collaborator, ParticipantIndex, parse_zed_link};
   83use clock::ReplicaId;
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   89use convert_case::{Case, Casing};
   90use dap::TelemetrySpawnLocation;
   91use display_map::*;
   92use edit_prediction_types::{
   93    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   94    SuggestionDisplayType,
   95};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  111    Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled, Subscription, Task,
  112    TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
  113    UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*,
  114    pulsating_between, px, relative, size,
  115};
  116use hover_links::{HoverLink, HoveredLinkState, find_file};
  117use hover_popover::{HoverState, hide_hover};
  118use indent_guides::ActiveIndentGuidesState;
  119use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  120use itertools::{Either, Itertools};
  121use language::{
  122    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  123    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  124    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  125    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  126    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  127    TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145};
  146use parking_lot::Mutex;
  147use persistence::DB;
  148use project::{
  149    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  150    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  151    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  152    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::{
  154        breakpoint_store::{
  155            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  156            BreakpointStore, BreakpointStoreEvent,
  157        },
  158        session::{Session, SessionEvent},
  159    },
  160    git_store::GitStoreEvent,
  161    lsp_store::{
  162        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  163        OpenLspBufferHandle,
  164    },
  165    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  166};
  167use rand::seq::SliceRandom;
  168use regex::Regex;
  169use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  170use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  171use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  172use serde::{Deserialize, Serialize};
  173use settings::{
  174    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  175    update_settings_file,
  176};
  177use smallvec::{SmallVec, smallvec};
  178use snippet::Snippet;
  179use std::{
  180    any::{Any, TypeId},
  181    borrow::Cow,
  182    cell::{OnceCell, RefCell},
  183    cmp::{self, Ordering, Reverse},
  184    collections::hash_map,
  185    iter::{self, Peekable},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    sync::Arc,
  192    time::{Duration, Instant},
  193};
  194use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  196use theme::{
  197    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  202    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  207    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  208    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::{CollapseDirection, SearchEvent},
  212};
  213
  214use crate::{
  215    code_context_menus::CompletionsMenuSource,
  216    editor_settings::MultiCursorModifier,
  217    hover_links::{find_url, find_url_from_range},
  218    inlays::{
  219        InlineValueCache,
  220        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  221    },
  222    scroll::{ScrollOffset, ScrollPixelOffset},
  223    selections_collection::resolve_selections_wrapping_blocks,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260enum ReportEditorEvent {
  261    Saved { auto_saved: bool },
  262    EditorOpened,
  263    Closed,
  264}
  265
  266impl ReportEditorEvent {
  267    pub fn event_type(&self) -> &'static str {
  268        match self {
  269            Self::Saved { .. } => "Editor Saved",
  270            Self::EditorOpened => "Editor Opened",
  271            Self::Closed => "Editor Closed",
  272        }
  273    }
  274}
  275
  276pub enum ActiveDebugLine {}
  277pub enum DebugStackFrameLine {}
  278enum DocumentHighlightRead {}
  279enum DocumentHighlightWrite {}
  280enum InputComposition {}
  281pub enum PendingInput {}
  282enum SelectedTextHighlight {}
  283
  284pub enum ConflictsOuter {}
  285pub enum ConflictsOurs {}
  286pub enum ConflictsTheirs {}
  287pub enum ConflictsOursMarker {}
  288pub enum ConflictsTheirsMarker {}
  289
  290pub struct HunkAddedColor;
  291pub struct HunkRemovedColor;
  292
  293#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  294pub enum Navigated {
  295    Yes,
  296    No,
  297}
  298
  299impl Navigated {
  300    pub fn from_bool(yes: bool) -> Navigated {
  301        if yes { Navigated::Yes } else { Navigated::No }
  302    }
  303}
  304
  305#[derive(Debug, Clone, PartialEq, Eq)]
  306enum DisplayDiffHunk {
  307    Folded {
  308        display_row: DisplayRow,
  309    },
  310    Unfolded {
  311        is_created_file: bool,
  312        diff_base_byte_range: Range<usize>,
  313        display_row_range: Range<DisplayRow>,
  314        multi_buffer_range: Range<Anchor>,
  315        status: DiffHunkStatus,
  316        word_diffs: Vec<Range<MultiBufferOffset>>,
  317    },
  318}
  319
  320pub enum HideMouseCursorOrigin {
  321    TypingAction,
  322    MovementAction,
  323}
  324
  325pub fn init(cx: &mut App) {
  326    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  327
  328    workspace::register_project_item::<Editor>(cx);
  329    workspace::FollowableViewRegistry::register::<Editor>(cx);
  330    workspace::register_serializable_item::<Editor>(cx);
  331
  332    cx.observe_new(
  333        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  334            workspace.register_action(Editor::new_file);
  335            workspace.register_action(Editor::new_file_split);
  336            workspace.register_action(Editor::new_file_vertical);
  337            workspace.register_action(Editor::new_file_horizontal);
  338            workspace.register_action(Editor::cancel_language_server_work);
  339            workspace.register_action(Editor::toggle_focus);
  340        },
  341    )
  342    .detach();
  343
  344    cx.on_action(move |_: &workspace::NewFile, cx| {
  345        let app_state = workspace::AppState::global(cx);
  346        if let Some(app_state) = app_state.upgrade() {
  347            workspace::open_new(
  348                Default::default(),
  349                app_state,
  350                cx,
  351                |workspace, window, cx| {
  352                    Editor::new_file(workspace, &Default::default(), window, cx)
  353                },
  354            )
  355            .detach();
  356        }
  357    })
  358    .on_action(move |_: &workspace::NewWindow, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    cx.activate(true);
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373}
  374
  375pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  376    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  377}
  378
  379pub trait DiagnosticRenderer {
  380    fn render_group(
  381        &self,
  382        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  383        buffer_id: BufferId,
  384        snapshot: EditorSnapshot,
  385        editor: WeakEntity<Editor>,
  386        language_registry: Option<Arc<LanguageRegistry>>,
  387        cx: &mut App,
  388    ) -> Vec<BlockProperties<Anchor>>;
  389
  390    fn render_hover(
  391        &self,
  392        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  393        range: Range<Point>,
  394        buffer_id: BufferId,
  395        language_registry: Option<Arc<LanguageRegistry>>,
  396        cx: &mut App,
  397    ) -> Option<Entity<markdown::Markdown>>;
  398
  399    fn open_link(
  400        &self,
  401        editor: &mut Editor,
  402        link: SharedString,
  403        window: &mut Window,
  404        cx: &mut Context<Editor>,
  405    );
  406}
  407
  408pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  409
  410impl GlobalDiagnosticRenderer {
  411    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  412        cx.try_global::<Self>().map(|g| g.0.clone())
  413    }
  414}
  415
  416impl gpui::Global for GlobalDiagnosticRenderer {}
  417pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  418    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  419}
  420
  421pub struct SearchWithinRange;
  422
  423trait InvalidationRegion {
  424    fn ranges(&self) -> &[Range<Anchor>];
  425}
  426
  427#[derive(Clone, Debug, PartialEq)]
  428pub enum SelectPhase {
  429    Begin {
  430        position: DisplayPoint,
  431        add: bool,
  432        click_count: usize,
  433    },
  434    BeginColumnar {
  435        position: DisplayPoint,
  436        reset: bool,
  437        mode: ColumnarMode,
  438        goal_column: u32,
  439    },
  440    Extend {
  441        position: DisplayPoint,
  442        click_count: usize,
  443    },
  444    Update {
  445        position: DisplayPoint,
  446        goal_column: u32,
  447        scroll_delta: gpui::Point<f32>,
  448    },
  449    End,
  450}
  451
  452#[derive(Clone, Debug, PartialEq)]
  453pub enum ColumnarMode {
  454    FromMouse,
  455    FromSelection,
  456}
  457
  458#[derive(Clone, Debug)]
  459pub enum SelectMode {
  460    Character,
  461    Word(Range<Anchor>),
  462    Line(Range<Anchor>),
  463    All,
  464}
  465
  466#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  467pub enum SizingBehavior {
  468    /// The editor will layout itself using `size_full` and will include the vertical
  469    /// scroll margin as requested by user settings.
  470    #[default]
  471    Default,
  472    /// The editor will layout itself using `size_full`, but will not have any
  473    /// vertical overscroll.
  474    ExcludeOverscrollMargin,
  475    /// The editor will request a vertical size according to its content and will be
  476    /// layouted without a vertical scroll margin.
  477    SizeByContent,
  478}
  479
  480#[derive(Clone, PartialEq, Eq, Debug)]
  481pub enum EditorMode {
  482    SingleLine,
  483    AutoHeight {
  484        min_lines: usize,
  485        max_lines: Option<usize>,
  486    },
  487    Full {
  488        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  489        scale_ui_elements_with_buffer_font_size: bool,
  490        /// When set to `true`, the editor will render a background for the active line.
  491        show_active_line_background: bool,
  492        /// Determines the sizing behavior for this editor
  493        sizing_behavior: SizingBehavior,
  494    },
  495    Minimap {
  496        parent: WeakEntity<Editor>,
  497    },
  498}
  499
  500impl EditorMode {
  501    pub fn full() -> Self {
  502        Self::Full {
  503            scale_ui_elements_with_buffer_font_size: true,
  504            show_active_line_background: true,
  505            sizing_behavior: SizingBehavior::Default,
  506        }
  507    }
  508
  509    #[inline]
  510    pub fn is_full(&self) -> bool {
  511        matches!(self, Self::Full { .. })
  512    }
  513
  514    #[inline]
  515    pub fn is_single_line(&self) -> bool {
  516        matches!(self, Self::SingleLine { .. })
  517    }
  518
  519    #[inline]
  520    fn is_minimap(&self) -> bool {
  521        matches!(self, Self::Minimap { .. })
  522    }
  523}
  524
  525#[derive(Copy, Clone, Debug)]
  526pub enum SoftWrap {
  527    /// Prefer not to wrap at all.
  528    ///
  529    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  530    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  531    GitDiff,
  532    /// Prefer a single line generally, unless an overly long line is encountered.
  533    None,
  534    /// Soft wrap lines that exceed the editor width.
  535    EditorWidth,
  536    /// Soft wrap lines at the preferred line length.
  537    Column(u32),
  538    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  539    Bounded(u32),
  540}
  541
  542#[derive(Clone)]
  543pub struct EditorStyle {
  544    pub background: Hsla,
  545    pub border: Hsla,
  546    pub local_player: PlayerColor,
  547    pub text: TextStyle,
  548    pub scrollbar_width: Pixels,
  549    pub syntax: Arc<SyntaxTheme>,
  550    pub status: StatusColors,
  551    pub inlay_hints_style: HighlightStyle,
  552    pub edit_prediction_styles: EditPredictionStyles,
  553    pub unnecessary_code_fade: f32,
  554    pub show_underlines: bool,
  555}
  556
  557impl Default for EditorStyle {
  558    fn default() -> Self {
  559        Self {
  560            background: Hsla::default(),
  561            border: Hsla::default(),
  562            local_player: PlayerColor::default(),
  563            text: TextStyle::default(),
  564            scrollbar_width: Pixels::default(),
  565            syntax: Default::default(),
  566            // HACK: Status colors don't have a real default.
  567            // We should look into removing the status colors from the editor
  568            // style and retrieve them directly from the theme.
  569            status: StatusColors::dark(),
  570            inlay_hints_style: HighlightStyle::default(),
  571            edit_prediction_styles: EditPredictionStyles {
  572                insertion: HighlightStyle::default(),
  573                whitespace: HighlightStyle::default(),
  574            },
  575            unnecessary_code_fade: Default::default(),
  576            show_underlines: true,
  577        }
  578    }
  579}
  580
  581pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  582    let show_background = language_settings::language_settings(None, None, cx)
  583        .inlay_hints
  584        .show_background;
  585
  586    let mut style = cx.theme().syntax().get("hint");
  587
  588    if style.color.is_none() {
  589        style.color = Some(cx.theme().status().hint);
  590    }
  591
  592    if !show_background {
  593        style.background_color = None;
  594        return style;
  595    }
  596
  597    if style.background_color.is_none() {
  598        style.background_color = Some(cx.theme().status().hint_background);
  599    }
  600
  601    style
  602}
  603
  604pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  605    EditPredictionStyles {
  606        insertion: HighlightStyle {
  607            color: Some(cx.theme().status().predictive),
  608            ..HighlightStyle::default()
  609        },
  610        whitespace: HighlightStyle {
  611            background_color: Some(cx.theme().status().created_background),
  612            ..HighlightStyle::default()
  613        },
  614    }
  615}
  616
  617type CompletionId = usize;
  618
  619pub(crate) enum EditDisplayMode {
  620    TabAccept,
  621    DiffPopover,
  622    Inline,
  623}
  624
  625enum EditPrediction {
  626    Edit {
  627        edits: Vec<(Range<Anchor>, Arc<str>)>,
  628        edit_preview: Option<EditPreview>,
  629        display_mode: EditDisplayMode,
  630        snapshot: BufferSnapshot,
  631    },
  632    /// Move to a specific location in the active editor
  633    MoveWithin {
  634        target: Anchor,
  635        snapshot: BufferSnapshot,
  636    },
  637    /// Move to a specific location in a different editor (not the active one)
  638    MoveOutside {
  639        target: language::Anchor,
  640        snapshot: BufferSnapshot,
  641    },
  642}
  643
  644struct EditPredictionState {
  645    inlay_ids: Vec<InlayId>,
  646    completion: EditPrediction,
  647    completion_id: Option<SharedString>,
  648    invalidation_range: Option<Range<Anchor>>,
  649}
  650
  651enum EditPredictionSettings {
  652    Disabled,
  653    Enabled {
  654        show_in_menu: bool,
  655        preview_requires_modifier: bool,
  656    },
  657}
  658
  659enum EditPredictionHighlight {}
  660
  661#[derive(Debug, Clone)]
  662struct InlineDiagnostic {
  663    message: SharedString,
  664    group_id: usize,
  665    is_primary: bool,
  666    start: Point,
  667    severity: lsp::DiagnosticSeverity,
  668}
  669
  670pub enum MenuEditPredictionsPolicy {
  671    Never,
  672    ByProvider,
  673}
  674
  675pub enum EditPredictionPreview {
  676    /// Modifier is not pressed
  677    Inactive { released_too_fast: bool },
  678    /// Modifier pressed
  679    Active {
  680        since: Instant,
  681        previous_scroll_position: Option<ScrollAnchor>,
  682    },
  683}
  684
  685impl EditPredictionPreview {
  686    pub fn released_too_fast(&self) -> bool {
  687        match self {
  688            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  689            EditPredictionPreview::Active { .. } => false,
  690        }
  691    }
  692
  693    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  694        if let EditPredictionPreview::Active {
  695            previous_scroll_position,
  696            ..
  697        } = self
  698        {
  699            *previous_scroll_position = scroll_position;
  700        }
  701    }
  702}
  703
  704pub struct ContextMenuOptions {
  705    pub min_entries_visible: usize,
  706    pub max_entries_visible: usize,
  707    pub placement: Option<ContextMenuPlacement>,
  708}
  709
  710#[derive(Debug, Clone, PartialEq, Eq)]
  711pub enum ContextMenuPlacement {
  712    Above,
  713    Below,
  714}
  715
  716#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  717struct EditorActionId(usize);
  718
  719impl EditorActionId {
  720    pub fn post_inc(&mut self) -> Self {
  721        let answer = self.0;
  722
  723        *self = Self(answer + 1);
  724
  725        Self(answer)
  726    }
  727}
  728
  729// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  730// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  731
  732type BackgroundHighlight = (
  733    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  734    Arc<[Range<Anchor>]>,
  735);
  736type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  737
  738#[derive(Default)]
  739struct ScrollbarMarkerState {
  740    scrollbar_size: Size<Pixels>,
  741    dirty: bool,
  742    markers: Arc<[PaintQuad]>,
  743    pending_refresh: Option<Task<Result<()>>>,
  744}
  745
  746impl ScrollbarMarkerState {
  747    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  748        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  749    }
  750}
  751
  752#[derive(Clone, Copy, PartialEq, Eq)]
  753pub enum MinimapVisibility {
  754    Disabled,
  755    Enabled {
  756        /// The configuration currently present in the users settings.
  757        setting_configuration: bool,
  758        /// Whether to override the currently set visibility from the users setting.
  759        toggle_override: bool,
  760    },
  761}
  762
  763impl MinimapVisibility {
  764    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  765        if mode.is_full() {
  766            Self::Enabled {
  767                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  768                toggle_override: false,
  769            }
  770        } else {
  771            Self::Disabled
  772        }
  773    }
  774
  775    fn hidden(&self) -> Self {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => Self::Enabled {
  781                setting_configuration,
  782                toggle_override: setting_configuration,
  783            },
  784            Self::Disabled => Self::Disabled,
  785        }
  786    }
  787
  788    fn disabled(&self) -> bool {
  789        matches!(*self, Self::Disabled)
  790    }
  791
  792    fn settings_visibility(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                ..
  797            } => setting_configuration,
  798            _ => false,
  799        }
  800    }
  801
  802    fn visible(&self) -> bool {
  803        match *self {
  804            Self::Enabled {
  805                setting_configuration,
  806                toggle_override,
  807            } => setting_configuration ^ toggle_override,
  808            _ => false,
  809        }
  810    }
  811
  812    fn toggle_visibility(&self) -> Self {
  813        match *self {
  814            Self::Enabled {
  815                toggle_override,
  816                setting_configuration,
  817            } => Self::Enabled {
  818                setting_configuration,
  819                toggle_override: !toggle_override,
  820            },
  821            Self::Disabled => Self::Disabled,
  822        }
  823    }
  824}
  825
  826#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  827pub enum BufferSerialization {
  828    All,
  829    NonDirtyBuffers,
  830}
  831
  832impl BufferSerialization {
  833    fn new(restore_unsaved_buffers: bool) -> Self {
  834        if restore_unsaved_buffers {
  835            Self::All
  836        } else {
  837            Self::NonDirtyBuffers
  838        }
  839    }
  840}
  841
  842#[derive(Clone, Debug)]
  843struct RunnableTasks {
  844    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  845    offset: multi_buffer::Anchor,
  846    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  847    column: u32,
  848    // Values of all named captures, including those starting with '_'
  849    extra_variables: HashMap<String, String>,
  850    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  851    context_range: Range<BufferOffset>,
  852}
  853
  854impl RunnableTasks {
  855    fn resolve<'a>(
  856        &'a self,
  857        cx: &'a task::TaskContext,
  858    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  859        self.templates.iter().filter_map(|(kind, template)| {
  860            template
  861                .resolve_task(&kind.to_id_base(), cx)
  862                .map(|task| (kind.clone(), task))
  863        })
  864    }
  865}
  866
  867#[derive(Clone)]
  868pub struct ResolvedTasks {
  869    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  870    position: Anchor,
  871}
  872
  873/// Addons allow storing per-editor state in other crates (e.g. Vim)
  874pub trait Addon: 'static {
  875    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  876
  877    fn render_buffer_header_controls(
  878        &self,
  879        _: &ExcerptInfo,
  880        _: &Window,
  881        _: &App,
  882    ) -> Option<AnyElement> {
  883        None
  884    }
  885
  886    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  887        None
  888    }
  889
  890    fn to_any(&self) -> &dyn std::any::Any;
  891
  892    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  893        None
  894    }
  895}
  896
  897struct ChangeLocation {
  898    current: Option<Vec<Anchor>>,
  899    original: Vec<Anchor>,
  900}
  901impl ChangeLocation {
  902    fn locations(&self) -> &[Anchor] {
  903        self.current.as_ref().unwrap_or(&self.original)
  904    }
  905}
  906
  907/// A set of caret positions, registered when the editor was edited.
  908pub struct ChangeList {
  909    changes: Vec<ChangeLocation>,
  910    /// Currently "selected" change.
  911    position: Option<usize>,
  912}
  913
  914impl ChangeList {
  915    pub fn new() -> Self {
  916        Self {
  917            changes: Vec::new(),
  918            position: None,
  919        }
  920    }
  921
  922    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  923    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  924    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  925        if self.changes.is_empty() {
  926            return None;
  927        }
  928
  929        let prev = self.position.unwrap_or(self.changes.len());
  930        let next = if direction == Direction::Prev {
  931            prev.saturating_sub(count)
  932        } else {
  933            (prev + count).min(self.changes.len() - 1)
  934        };
  935        self.position = Some(next);
  936        self.changes.get(next).map(|change| change.locations())
  937    }
  938
  939    /// Adds a new change to the list, resetting the change list position.
  940    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  941        self.position.take();
  942        if let Some(last) = self.changes.last_mut()
  943            && group
  944        {
  945            last.current = Some(new_positions)
  946        } else {
  947            self.changes.push(ChangeLocation {
  948                original: new_positions,
  949                current: None,
  950            });
  951        }
  952    }
  953
  954    pub fn last(&self) -> Option<&[Anchor]> {
  955        self.changes.last().map(|change| change.locations())
  956    }
  957
  958    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  959        self.changes.last().map(|change| change.original.as_slice())
  960    }
  961
  962    pub fn invert_last_group(&mut self) {
  963        if let Some(last) = self.changes.last_mut()
  964            && let Some(current) = last.current.as_mut()
  965        {
  966            mem::swap(&mut last.original, current);
  967        }
  968    }
  969}
  970
  971#[derive(Clone)]
  972struct InlineBlamePopoverState {
  973    scroll_handle: ScrollHandle,
  974    commit_message: Option<ParsedCommitMessage>,
  975    markdown: Entity<Markdown>,
  976}
  977
  978struct InlineBlamePopover {
  979    position: gpui::Point<Pixels>,
  980    hide_task: Option<Task<()>>,
  981    popover_bounds: Option<Bounds<Pixels>>,
  982    popover_state: InlineBlamePopoverState,
  983    keyboard_grace: bool,
  984}
  985
  986enum SelectionDragState {
  987    /// State when no drag related activity is detected.
  988    None,
  989    /// State when the mouse is down on a selection that is about to be dragged.
  990    ReadyToDrag {
  991        selection: Selection<Anchor>,
  992        click_position: gpui::Point<Pixels>,
  993        mouse_down_time: Instant,
  994    },
  995    /// State when the mouse is dragging the selection in the editor.
  996    Dragging {
  997        selection: Selection<Anchor>,
  998        drop_cursor: Selection<Anchor>,
  999        hide_drop_cursor: bool,
 1000    },
 1001}
 1002
 1003enum ColumnarSelectionState {
 1004    FromMouse {
 1005        selection_tail: Anchor,
 1006        display_point: Option<DisplayPoint>,
 1007    },
 1008    FromSelection {
 1009        selection_tail: Anchor,
 1010    },
 1011}
 1012
 1013/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1014/// a breakpoint on them.
 1015#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1016struct PhantomBreakpointIndicator {
 1017    display_row: DisplayRow,
 1018    /// There's a small debounce between hovering over the line and showing the indicator.
 1019    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1020    is_active: bool,
 1021    collides_with_existing_breakpoint: bool,
 1022}
 1023
 1024/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1025/// in diff view mode.
 1026#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1027pub(crate) struct PhantomDiffReviewIndicator {
 1028    pub display_row: DisplayRow,
 1029    /// There's a small debounce between hovering over the line and showing the indicator.
 1030    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1031    pub is_active: bool,
 1032}
 1033
 1034/// Identifies a specific hunk in the diff buffer.
 1035/// Used as a key to group comments by their location.
 1036#[derive(Clone, Debug)]
 1037pub struct DiffHunkKey {
 1038    /// The file path (relative to worktree) this hunk belongs to.
 1039    pub file_path: Arc<util::rel_path::RelPath>,
 1040    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1041    pub hunk_start_anchor: Anchor,
 1042}
 1043
 1044/// A review comment stored locally before being sent to the Agent panel.
 1045#[derive(Clone)]
 1046pub struct StoredReviewComment {
 1047    /// Unique identifier for this comment (for edit/delete operations).
 1048    pub id: usize,
 1049    /// The comment text entered by the user.
 1050    pub comment: String,
 1051    /// The display row where this comment was added (within the hunk).
 1052    pub display_row: DisplayRow,
 1053    /// Anchors for the code range being reviewed.
 1054    pub anchor_range: Range<Anchor>,
 1055    /// Timestamp when the comment was created (for chronological ordering).
 1056    pub created_at: Instant,
 1057    /// Whether this comment is currently being edited inline.
 1058    pub is_editing: bool,
 1059}
 1060
 1061impl StoredReviewComment {
 1062    pub fn new(
 1063        id: usize,
 1064        comment: String,
 1065        display_row: DisplayRow,
 1066        anchor_range: Range<Anchor>,
 1067    ) -> Self {
 1068        Self {
 1069            id,
 1070            comment,
 1071            display_row,
 1072            anchor_range,
 1073            created_at: Instant::now(),
 1074            is_editing: false,
 1075        }
 1076    }
 1077}
 1078
 1079/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1080pub(crate) struct DiffReviewOverlay {
 1081    /// The display row where the overlay is anchored.
 1082    pub display_row: DisplayRow,
 1083    /// The block ID for the overlay.
 1084    pub block_id: CustomBlockId,
 1085    /// The editor entity for the review input.
 1086    pub prompt_editor: Entity<Editor>,
 1087    /// The hunk key this overlay belongs to.
 1088    pub hunk_key: DiffHunkKey,
 1089    /// Whether the comments section is expanded.
 1090    pub comments_expanded: bool,
 1091    /// Editors for comments currently being edited inline.
 1092    /// Key: comment ID, Value: Editor entity for inline editing.
 1093    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1094    /// Subscriptions for inline edit editors' action handlers.
 1095    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1096    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1097    /// The current user's avatar URI for display in comment rows.
 1098    pub user_avatar_uri: Option<SharedUri>,
 1099    /// Subscription to keep the action handler alive.
 1100    _subscription: Subscription,
 1101}
 1102
 1103/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1104///
 1105/// See the [module level documentation](self) for more information.
 1106pub struct Editor {
 1107    focus_handle: FocusHandle,
 1108    last_focused_descendant: Option<WeakFocusHandle>,
 1109    /// The text buffer being edited
 1110    buffer: Entity<MultiBuffer>,
 1111    /// Map of how text in the buffer should be displayed.
 1112    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1113    pub display_map: Entity<DisplayMap>,
 1114    placeholder_display_map: Option<Entity<DisplayMap>>,
 1115    pub selections: SelectionsCollection,
 1116    pub scroll_manager: ScrollManager,
 1117    /// When inline assist editors are linked, they all render cursors because
 1118    /// typing enters text into each of them, even the ones that aren't focused.
 1119    pub(crate) show_cursor_when_unfocused: bool,
 1120    columnar_selection_state: Option<ColumnarSelectionState>,
 1121    add_selections_state: Option<AddSelectionsState>,
 1122    select_next_state: Option<SelectNextState>,
 1123    select_prev_state: Option<SelectNextState>,
 1124    selection_history: SelectionHistory,
 1125    defer_selection_effects: bool,
 1126    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1127    autoclose_regions: Vec<AutocloseRegion>,
 1128    snippet_stack: InvalidationStack<SnippetState>,
 1129    select_syntax_node_history: SelectSyntaxNodeHistory,
 1130    ime_transaction: Option<TransactionId>,
 1131    pub diagnostics_max_severity: DiagnosticSeverity,
 1132    active_diagnostics: ActiveDiagnostic,
 1133    show_inline_diagnostics: bool,
 1134    inline_diagnostics_update: Task<()>,
 1135    inline_diagnostics_enabled: bool,
 1136    diagnostics_enabled: bool,
 1137    word_completions_enabled: bool,
 1138    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1139    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1140    hard_wrap: Option<usize>,
 1141    project: Option<Entity<Project>>,
 1142    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1143    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1144    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1145    blink_manager: Entity<BlinkManager>,
 1146    show_cursor_names: bool,
 1147    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1148    pub show_local_selections: bool,
 1149    mode: EditorMode,
 1150    show_breadcrumbs: bool,
 1151    show_gutter: bool,
 1152    show_scrollbars: ScrollbarAxes,
 1153    minimap_visibility: MinimapVisibility,
 1154    offset_content: bool,
 1155    disable_expand_excerpt_buttons: bool,
 1156    delegate_expand_excerpts: bool,
 1157    show_line_numbers: Option<bool>,
 1158    use_relative_line_numbers: Option<bool>,
 1159    show_git_diff_gutter: Option<bool>,
 1160    show_code_actions: Option<bool>,
 1161    show_runnables: Option<bool>,
 1162    show_breakpoints: Option<bool>,
 1163    show_diff_review_button: bool,
 1164    show_wrap_guides: Option<bool>,
 1165    show_indent_guides: Option<bool>,
 1166    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1167    highlight_order: usize,
 1168    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1169    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1170    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1171    scrollbar_marker_state: ScrollbarMarkerState,
 1172    active_indent_guides_state: ActiveIndentGuidesState,
 1173    nav_history: Option<ItemNavHistory>,
 1174    context_menu: RefCell<Option<CodeContextMenu>>,
 1175    context_menu_options: Option<ContextMenuOptions>,
 1176    mouse_context_menu: Option<MouseContextMenu>,
 1177    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1178    inline_blame_popover: Option<InlineBlamePopover>,
 1179    inline_blame_popover_show_task: Option<Task<()>>,
 1180    signature_help_state: SignatureHelpState,
 1181    auto_signature_help: Option<bool>,
 1182    find_all_references_task_sources: Vec<Anchor>,
 1183    next_completion_id: CompletionId,
 1184    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1185    code_actions_task: Option<Task<Result<()>>>,
 1186    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1187    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1188    debounced_selection_highlight_complete: bool,
 1189    document_highlights_task: Option<Task<()>>,
 1190    linked_editing_range_task: Option<Task<Option<()>>>,
 1191    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1192    pending_rename: Option<RenameState>,
 1193    searchable: bool,
 1194    cursor_shape: CursorShape,
 1195    /// Whether the cursor is offset one character to the left when something is
 1196    /// selected (needed for vim visual mode)
 1197    cursor_offset_on_selection: bool,
 1198    current_line_highlight: Option<CurrentLineHighlight>,
 1199    pub collapse_matches: bool,
 1200    autoindent_mode: Option<AutoindentMode>,
 1201    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1202    input_enabled: bool,
 1203    use_modal_editing: bool,
 1204    read_only: bool,
 1205    leader_id: Option<CollaboratorId>,
 1206    remote_id: Option<ViewId>,
 1207    pub hover_state: HoverState,
 1208    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1209    prev_pressure_stage: Option<PressureStage>,
 1210    gutter_hovered: bool,
 1211    hovered_link_state: Option<HoveredLinkState>,
 1212    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1213    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1214    active_edit_prediction: Option<EditPredictionState>,
 1215    /// Used to prevent flickering as the user types while the menu is open
 1216    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1217    edit_prediction_settings: EditPredictionSettings,
 1218    edit_predictions_hidden_for_vim_mode: bool,
 1219    show_edit_predictions_override: Option<bool>,
 1220    show_completions_on_input_override: Option<bool>,
 1221    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1222    edit_prediction_preview: EditPredictionPreview,
 1223    edit_prediction_indent_conflict: bool,
 1224    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1225    next_inlay_id: usize,
 1226    next_color_inlay_id: usize,
 1227    _subscriptions: Vec<Subscription>,
 1228    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1229    gutter_dimensions: GutterDimensions,
 1230    style: Option<EditorStyle>,
 1231    text_style_refinement: Option<TextStyleRefinement>,
 1232    next_editor_action_id: EditorActionId,
 1233    editor_actions: Rc<
 1234        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1235    >,
 1236    use_autoclose: bool,
 1237    use_auto_surround: bool,
 1238    auto_replace_emoji_shortcode: bool,
 1239    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1240    show_git_blame_gutter: bool,
 1241    show_git_blame_inline: bool,
 1242    show_git_blame_inline_delay_task: Option<Task<()>>,
 1243    git_blame_inline_enabled: bool,
 1244    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1245    buffer_serialization: Option<BufferSerialization>,
 1246    show_selection_menu: Option<bool>,
 1247    blame: Option<Entity<GitBlame>>,
 1248    blame_subscription: Option<Subscription>,
 1249    custom_context_menu: Option<
 1250        Box<
 1251            dyn 'static
 1252                + Fn(
 1253                    &mut Self,
 1254                    DisplayPoint,
 1255                    &mut Window,
 1256                    &mut Context<Self>,
 1257                ) -> Option<Entity<ui::ContextMenu>>,
 1258        >,
 1259    >,
 1260    last_bounds: Option<Bounds<Pixels>>,
 1261    last_position_map: Option<Rc<PositionMap>>,
 1262    expect_bounds_change: Option<Bounds<Pixels>>,
 1263    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1264    tasks_update_task: Option<Task<()>>,
 1265    breakpoint_store: Option<Entity<BreakpointStore>>,
 1266    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1267    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1268    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1269    /// when hunks have comments stored.
 1270    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1271    /// Stored review comments grouped by hunk.
 1272    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1273    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1274    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1275    /// Counter for generating unique comment IDs.
 1276    next_review_comment_id: usize,
 1277    hovered_diff_hunk_row: Option<DisplayRow>,
 1278    pull_diagnostics_task: Task<()>,
 1279    pull_diagnostics_background_task: Task<()>,
 1280    in_project_search: bool,
 1281    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1282    breadcrumb_header: Option<String>,
 1283    focused_block: Option<FocusedBlock>,
 1284    next_scroll_position: NextScrollCursorCenterTopBottom,
 1285    addons: HashMap<TypeId, Box<dyn Addon>>,
 1286    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1287    load_diff_task: Option<Shared<Task<()>>>,
 1288    /// Whether we are temporarily displaying a diff other than git's
 1289    temporary_diff_override: bool,
 1290    selection_mark_mode: bool,
 1291    toggle_fold_multiple_buffers: Task<()>,
 1292    _scroll_cursor_center_top_bottom_task: Task<()>,
 1293    serialize_selections: Task<()>,
 1294    serialize_folds: Task<()>,
 1295    mouse_cursor_hidden: bool,
 1296    minimap: Option<Entity<Self>>,
 1297    hide_mouse_mode: HideMouseMode,
 1298    pub change_list: ChangeList,
 1299    inline_value_cache: InlineValueCache,
 1300    number_deleted_lines: bool,
 1301
 1302    selection_drag_state: SelectionDragState,
 1303    colors: Option<LspColorData>,
 1304    post_scroll_update: Task<()>,
 1305    refresh_colors_task: Task<()>,
 1306    inlay_hints: Option<LspInlayHintData>,
 1307    folding_newlines: Task<()>,
 1308    select_next_is_case_sensitive: Option<bool>,
 1309    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1310    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1311    accent_data: Option<AccentData>,
 1312    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1313}
 1314
 1315#[derive(Debug, PartialEq)]
 1316struct AccentData {
 1317    colors: AccentColors,
 1318    overrides: Vec<SharedString>,
 1319}
 1320
 1321fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1322    if debounce_ms > 0 {
 1323        Some(Duration::from_millis(debounce_ms))
 1324    } else {
 1325        None
 1326    }
 1327}
 1328
 1329#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1330enum NextScrollCursorCenterTopBottom {
 1331    #[default]
 1332    Center,
 1333    Top,
 1334    Bottom,
 1335}
 1336
 1337impl NextScrollCursorCenterTopBottom {
 1338    fn next(&self) -> Self {
 1339        match self {
 1340            Self::Center => Self::Top,
 1341            Self::Top => Self::Bottom,
 1342            Self::Bottom => Self::Center,
 1343        }
 1344    }
 1345}
 1346
 1347#[derive(Clone)]
 1348pub struct EditorSnapshot {
 1349    pub mode: EditorMode,
 1350    show_gutter: bool,
 1351    offset_content: bool,
 1352    show_line_numbers: Option<bool>,
 1353    number_deleted_lines: bool,
 1354    show_git_diff_gutter: Option<bool>,
 1355    show_code_actions: Option<bool>,
 1356    show_runnables: Option<bool>,
 1357    show_breakpoints: Option<bool>,
 1358    git_blame_gutter_max_author_length: Option<usize>,
 1359    pub display_snapshot: DisplaySnapshot,
 1360    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1361    is_focused: bool,
 1362    scroll_anchor: ScrollAnchor,
 1363    ongoing_scroll: OngoingScroll,
 1364    current_line_highlight: CurrentLineHighlight,
 1365    gutter_hovered: bool,
 1366}
 1367
 1368#[derive(Default, Debug, Clone, Copy)]
 1369pub struct GutterDimensions {
 1370    pub left_padding: Pixels,
 1371    pub right_padding: Pixels,
 1372    pub width: Pixels,
 1373    pub margin: Pixels,
 1374    pub git_blame_entries_width: Option<Pixels>,
 1375}
 1376
 1377impl GutterDimensions {
 1378    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1379        Self {
 1380            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1381            ..Default::default()
 1382        }
 1383    }
 1384
 1385    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1386        -cx.text_system().descent(font_id, font_size)
 1387    }
 1388    /// The full width of the space taken up by the gutter.
 1389    pub fn full_width(&self) -> Pixels {
 1390        self.margin + self.width
 1391    }
 1392
 1393    /// The width of the space reserved for the fold indicators,
 1394    /// use alongside 'justify_end' and `gutter_width` to
 1395    /// right align content with the line numbers
 1396    pub fn fold_area_width(&self) -> Pixels {
 1397        self.margin + self.right_padding
 1398    }
 1399}
 1400
 1401struct CharacterDimensions {
 1402    em_width: Pixels,
 1403    em_advance: Pixels,
 1404    line_height: Pixels,
 1405}
 1406
 1407#[derive(Debug)]
 1408pub struct RemoteSelection {
 1409    pub replica_id: ReplicaId,
 1410    pub selection: Selection<Anchor>,
 1411    pub cursor_shape: CursorShape,
 1412    pub collaborator_id: CollaboratorId,
 1413    pub line_mode: bool,
 1414    pub user_name: Option<SharedString>,
 1415    pub color: PlayerColor,
 1416}
 1417
 1418#[derive(Clone, Debug)]
 1419struct SelectionHistoryEntry {
 1420    selections: Arc<[Selection<Anchor>]>,
 1421    select_next_state: Option<SelectNextState>,
 1422    select_prev_state: Option<SelectNextState>,
 1423    add_selections_state: Option<AddSelectionsState>,
 1424}
 1425
 1426#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1427enum SelectionHistoryMode {
 1428    #[default]
 1429    Normal,
 1430    Undoing,
 1431    Redoing,
 1432    Skipping,
 1433}
 1434
 1435#[derive(Clone, PartialEq, Eq, Hash)]
 1436struct HoveredCursor {
 1437    replica_id: ReplicaId,
 1438    selection_id: usize,
 1439}
 1440
 1441#[derive(Debug)]
 1442/// SelectionEffects controls the side-effects of updating the selection.
 1443///
 1444/// The default behaviour does "what you mostly want":
 1445/// - it pushes to the nav history if the cursor moved by >10 lines
 1446/// - it re-triggers completion requests
 1447/// - it scrolls to fit
 1448///
 1449/// You might want to modify these behaviours. For example when doing a "jump"
 1450/// like go to definition, we always want to add to nav history; but when scrolling
 1451/// in vim mode we never do.
 1452///
 1453/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1454/// move.
 1455#[derive(Clone)]
 1456pub struct SelectionEffects {
 1457    nav_history: Option<bool>,
 1458    completions: bool,
 1459    scroll: Option<Autoscroll>,
 1460}
 1461
 1462impl Default for SelectionEffects {
 1463    fn default() -> Self {
 1464        Self {
 1465            nav_history: None,
 1466            completions: true,
 1467            scroll: Some(Autoscroll::fit()),
 1468        }
 1469    }
 1470}
 1471impl SelectionEffects {
 1472    pub fn scroll(scroll: Autoscroll) -> Self {
 1473        Self {
 1474            scroll: Some(scroll),
 1475            ..Default::default()
 1476        }
 1477    }
 1478
 1479    pub fn no_scroll() -> Self {
 1480        Self {
 1481            scroll: None,
 1482            ..Default::default()
 1483        }
 1484    }
 1485
 1486    pub fn completions(self, completions: bool) -> Self {
 1487        Self {
 1488            completions,
 1489            ..self
 1490        }
 1491    }
 1492
 1493    pub fn nav_history(self, nav_history: bool) -> Self {
 1494        Self {
 1495            nav_history: Some(nav_history),
 1496            ..self
 1497        }
 1498    }
 1499}
 1500
 1501struct DeferredSelectionEffectsState {
 1502    changed: bool,
 1503    effects: SelectionEffects,
 1504    old_cursor_position: Anchor,
 1505    history_entry: SelectionHistoryEntry,
 1506}
 1507
 1508#[derive(Default)]
 1509struct SelectionHistory {
 1510    #[allow(clippy::type_complexity)]
 1511    selections_by_transaction:
 1512        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1513    mode: SelectionHistoryMode,
 1514    undo_stack: VecDeque<SelectionHistoryEntry>,
 1515    redo_stack: VecDeque<SelectionHistoryEntry>,
 1516}
 1517
 1518impl SelectionHistory {
 1519    #[track_caller]
 1520    fn insert_transaction(
 1521        &mut self,
 1522        transaction_id: TransactionId,
 1523        selections: Arc<[Selection<Anchor>]>,
 1524    ) {
 1525        if selections.is_empty() {
 1526            log::error!(
 1527                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1528                std::panic::Location::caller()
 1529            );
 1530            return;
 1531        }
 1532        self.selections_by_transaction
 1533            .insert(transaction_id, (selections, None));
 1534    }
 1535
 1536    #[allow(clippy::type_complexity)]
 1537    fn transaction(
 1538        &self,
 1539        transaction_id: TransactionId,
 1540    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1541        self.selections_by_transaction.get(&transaction_id)
 1542    }
 1543
 1544    #[allow(clippy::type_complexity)]
 1545    fn transaction_mut(
 1546        &mut self,
 1547        transaction_id: TransactionId,
 1548    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1549        self.selections_by_transaction.get_mut(&transaction_id)
 1550    }
 1551
 1552    fn push(&mut self, entry: SelectionHistoryEntry) {
 1553        if !entry.selections.is_empty() {
 1554            match self.mode {
 1555                SelectionHistoryMode::Normal => {
 1556                    self.push_undo(entry);
 1557                    self.redo_stack.clear();
 1558                }
 1559                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1560                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1561                SelectionHistoryMode::Skipping => {}
 1562            }
 1563        }
 1564    }
 1565
 1566    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1567        if self
 1568            .undo_stack
 1569            .back()
 1570            .is_none_or(|e| e.selections != entry.selections)
 1571        {
 1572            self.undo_stack.push_back(entry);
 1573            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1574                self.undo_stack.pop_front();
 1575            }
 1576        }
 1577    }
 1578
 1579    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1580        if self
 1581            .redo_stack
 1582            .back()
 1583            .is_none_or(|e| e.selections != entry.selections)
 1584        {
 1585            self.redo_stack.push_back(entry);
 1586            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1587                self.redo_stack.pop_front();
 1588            }
 1589        }
 1590    }
 1591}
 1592
 1593#[derive(Clone, Copy)]
 1594pub struct RowHighlightOptions {
 1595    pub autoscroll: bool,
 1596    pub include_gutter: bool,
 1597}
 1598
 1599impl Default for RowHighlightOptions {
 1600    fn default() -> Self {
 1601        Self {
 1602            autoscroll: Default::default(),
 1603            include_gutter: true,
 1604        }
 1605    }
 1606}
 1607
 1608struct RowHighlight {
 1609    index: usize,
 1610    range: Range<Anchor>,
 1611    color: Hsla,
 1612    options: RowHighlightOptions,
 1613    type_id: TypeId,
 1614}
 1615
 1616#[derive(Clone, Debug)]
 1617struct AddSelectionsState {
 1618    groups: Vec<AddSelectionsGroup>,
 1619}
 1620
 1621#[derive(Clone, Debug)]
 1622struct AddSelectionsGroup {
 1623    above: bool,
 1624    stack: Vec<usize>,
 1625}
 1626
 1627#[derive(Clone)]
 1628struct SelectNextState {
 1629    query: AhoCorasick,
 1630    wordwise: bool,
 1631    done: bool,
 1632}
 1633
 1634impl std::fmt::Debug for SelectNextState {
 1635    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1636        f.debug_struct(std::any::type_name::<Self>())
 1637            .field("wordwise", &self.wordwise)
 1638            .field("done", &self.done)
 1639            .finish()
 1640    }
 1641}
 1642
 1643#[derive(Debug)]
 1644struct AutocloseRegion {
 1645    selection_id: usize,
 1646    range: Range<Anchor>,
 1647    pair: BracketPair,
 1648}
 1649
 1650#[derive(Debug)]
 1651struct SnippetState {
 1652    ranges: Vec<Vec<Range<Anchor>>>,
 1653    active_index: usize,
 1654    choices: Vec<Option<Vec<String>>>,
 1655}
 1656
 1657#[doc(hidden)]
 1658pub struct RenameState {
 1659    pub range: Range<Anchor>,
 1660    pub old_name: Arc<str>,
 1661    pub editor: Entity<Editor>,
 1662    block_id: CustomBlockId,
 1663}
 1664
 1665struct InvalidationStack<T>(Vec<T>);
 1666
 1667struct RegisteredEditPredictionDelegate {
 1668    provider: Arc<dyn EditPredictionDelegateHandle>,
 1669    _subscription: Subscription,
 1670}
 1671
 1672#[derive(Debug, PartialEq, Eq)]
 1673pub struct ActiveDiagnosticGroup {
 1674    pub active_range: Range<Anchor>,
 1675    pub active_message: String,
 1676    pub group_id: usize,
 1677    pub blocks: HashSet<CustomBlockId>,
 1678}
 1679
 1680#[derive(Debug, PartialEq, Eq)]
 1681
 1682pub(crate) enum ActiveDiagnostic {
 1683    None,
 1684    All,
 1685    Group(ActiveDiagnosticGroup),
 1686}
 1687
 1688#[derive(Serialize, Deserialize, Clone, Debug)]
 1689pub struct ClipboardSelection {
 1690    /// The number of bytes in this selection.
 1691    pub len: usize,
 1692    /// Whether this was a full-line selection.
 1693    pub is_entire_line: bool,
 1694    /// The indentation of the first line when this content was originally copied.
 1695    pub first_line_indent: u32,
 1696    #[serde(default)]
 1697    pub file_path: Option<PathBuf>,
 1698    #[serde(default)]
 1699    pub line_range: Option<RangeInclusive<u32>>,
 1700}
 1701
 1702impl ClipboardSelection {
 1703    pub fn for_buffer(
 1704        len: usize,
 1705        is_entire_line: bool,
 1706        range: Range<Point>,
 1707        buffer: &MultiBufferSnapshot,
 1708        project: Option<&Entity<Project>>,
 1709        cx: &App,
 1710    ) -> Self {
 1711        let first_line_indent = buffer
 1712            .indent_size_for_line(MultiBufferRow(range.start.row))
 1713            .len;
 1714
 1715        let file_path = util::maybe!({
 1716            let project = project?.read(cx);
 1717            let file = buffer.file_at(range.start)?;
 1718            let project_path = ProjectPath {
 1719                worktree_id: file.worktree_id(cx),
 1720                path: file.path().clone(),
 1721            };
 1722            project.absolute_path(&project_path, cx)
 1723        });
 1724
 1725        let line_range = file_path.as_ref().and_then(|_| {
 1726            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1727            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1728            if start_excerpt_id == end_excerpt_id {
 1729                Some(start_point.row..=end_point.row)
 1730            } else {
 1731                None
 1732            }
 1733        });
 1734
 1735        Self {
 1736            len,
 1737            is_entire_line,
 1738            first_line_indent,
 1739            file_path,
 1740            line_range,
 1741        }
 1742    }
 1743}
 1744
 1745// selections, scroll behavior, was newest selection reversed
 1746type SelectSyntaxNodeHistoryState = (
 1747    Box<[Selection<MultiBufferOffset>]>,
 1748    SelectSyntaxNodeScrollBehavior,
 1749    bool,
 1750);
 1751
 1752#[derive(Default)]
 1753struct SelectSyntaxNodeHistory {
 1754    stack: Vec<SelectSyntaxNodeHistoryState>,
 1755    // disable temporarily to allow changing selections without losing the stack
 1756    pub disable_clearing: bool,
 1757}
 1758
 1759impl SelectSyntaxNodeHistory {
 1760    pub fn try_clear(&mut self) {
 1761        if !self.disable_clearing {
 1762            self.stack.clear();
 1763        }
 1764    }
 1765
 1766    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1767        self.stack.push(selection);
 1768    }
 1769
 1770    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1771        self.stack.pop()
 1772    }
 1773}
 1774
 1775enum SelectSyntaxNodeScrollBehavior {
 1776    CursorTop,
 1777    FitSelection,
 1778    CursorBottom,
 1779}
 1780
 1781#[derive(Debug, Clone, Copy)]
 1782pub(crate) struct NavigationData {
 1783    cursor_anchor: Anchor,
 1784    cursor_position: Point,
 1785    scroll_anchor: ScrollAnchor,
 1786    scroll_top_row: u32,
 1787}
 1788
 1789#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1790pub enum GotoDefinitionKind {
 1791    Symbol,
 1792    Declaration,
 1793    Type,
 1794    Implementation,
 1795}
 1796
 1797pub enum FormatTarget {
 1798    Buffers(HashSet<Entity<Buffer>>),
 1799    Ranges(Vec<Range<MultiBufferPoint>>),
 1800}
 1801
 1802pub(crate) struct FocusedBlock {
 1803    id: BlockId,
 1804    focus_handle: WeakFocusHandle,
 1805}
 1806
 1807#[derive(Clone, Debug)]
 1808enum JumpData {
 1809    MultiBufferRow {
 1810        row: MultiBufferRow,
 1811        line_offset_from_top: u32,
 1812    },
 1813    MultiBufferPoint {
 1814        excerpt_id: ExcerptId,
 1815        position: Point,
 1816        anchor: text::Anchor,
 1817        line_offset_from_top: u32,
 1818    },
 1819}
 1820
 1821pub enum MultibufferSelectionMode {
 1822    First,
 1823    All,
 1824}
 1825
 1826#[derive(Clone, Copy, Debug, Default)]
 1827pub struct RewrapOptions {
 1828    pub override_language_settings: bool,
 1829    pub preserve_existing_whitespace: bool,
 1830}
 1831
 1832impl Editor {
 1833    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1834        let buffer = cx.new(|cx| Buffer::local("", cx));
 1835        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1836        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1837    }
 1838
 1839    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1840        let buffer = cx.new(|cx| Buffer::local("", cx));
 1841        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1842        Self::new(EditorMode::full(), buffer, None, window, cx)
 1843    }
 1844
 1845    pub fn auto_height(
 1846        min_lines: usize,
 1847        max_lines: usize,
 1848        window: &mut Window,
 1849        cx: &mut Context<Self>,
 1850    ) -> Self {
 1851        let buffer = cx.new(|cx| Buffer::local("", cx));
 1852        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1853        Self::new(
 1854            EditorMode::AutoHeight {
 1855                min_lines,
 1856                max_lines: Some(max_lines),
 1857            },
 1858            buffer,
 1859            None,
 1860            window,
 1861            cx,
 1862        )
 1863    }
 1864
 1865    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1866    /// The editor grows as tall as needed to fit its content.
 1867    pub fn auto_height_unbounded(
 1868        min_lines: usize,
 1869        window: &mut Window,
 1870        cx: &mut Context<Self>,
 1871    ) -> Self {
 1872        let buffer = cx.new(|cx| Buffer::local("", cx));
 1873        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1874        Self::new(
 1875            EditorMode::AutoHeight {
 1876                min_lines,
 1877                max_lines: None,
 1878            },
 1879            buffer,
 1880            None,
 1881            window,
 1882            cx,
 1883        )
 1884    }
 1885
 1886    pub fn for_buffer(
 1887        buffer: Entity<Buffer>,
 1888        project: Option<Entity<Project>>,
 1889        window: &mut Window,
 1890        cx: &mut Context<Self>,
 1891    ) -> Self {
 1892        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1893        Self::new(EditorMode::full(), buffer, project, window, cx)
 1894    }
 1895
 1896    pub fn for_multibuffer(
 1897        buffer: Entity<MultiBuffer>,
 1898        project: Option<Entity<Project>>,
 1899        window: &mut Window,
 1900        cx: &mut Context<Self>,
 1901    ) -> Self {
 1902        Self::new(EditorMode::full(), buffer, project, window, cx)
 1903    }
 1904
 1905    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1906        let mut clone = Self::new(
 1907            self.mode.clone(),
 1908            self.buffer.clone(),
 1909            self.project.clone(),
 1910            window,
 1911            cx,
 1912        );
 1913        self.display_map.update(cx, |display_map, cx| {
 1914            let snapshot = display_map.snapshot(cx);
 1915            clone.display_map.update(cx, |display_map, cx| {
 1916                display_map.set_state(&snapshot, cx);
 1917            });
 1918        });
 1919        clone.folds_did_change(cx);
 1920        clone.selections.clone_state(&self.selections);
 1921        clone.scroll_manager.clone_state(&self.scroll_manager);
 1922        clone.searchable = self.searchable;
 1923        clone.read_only = self.read_only;
 1924        clone
 1925    }
 1926
 1927    pub fn new(
 1928        mode: EditorMode,
 1929        buffer: Entity<MultiBuffer>,
 1930        project: Option<Entity<Project>>,
 1931        window: &mut Window,
 1932        cx: &mut Context<Self>,
 1933    ) -> Self {
 1934        Editor::new_internal(mode, buffer, project, None, window, cx)
 1935    }
 1936
 1937    pub fn sticky_headers(
 1938        &self,
 1939        style: &EditorStyle,
 1940        cx: &App,
 1941    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1942        let multi_buffer = self.buffer().read(cx);
 1943        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1944        let multi_buffer_visible_start = self
 1945            .scroll_manager
 1946            .anchor()
 1947            .anchor
 1948            .to_point(&multi_buffer_snapshot);
 1949        let max_row = multi_buffer_snapshot.max_point().row;
 1950
 1951        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1952        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1953
 1954        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1955            let outline_items = buffer
 1956                .outline_items_containing(
 1957                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1958                    true,
 1959                    Some(style.syntax.as_ref()),
 1960                )
 1961                .into_iter()
 1962                .map(|outline_item| OutlineItem {
 1963                    depth: outline_item.depth,
 1964                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1965                    source_range_for_text: Anchor::range_in_buffer(
 1966                        *excerpt_id,
 1967                        outline_item.source_range_for_text,
 1968                    ),
 1969                    text: outline_item.text,
 1970                    highlight_ranges: outline_item.highlight_ranges,
 1971                    name_ranges: outline_item.name_ranges,
 1972                    body_range: outline_item
 1973                        .body_range
 1974                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1975                    annotation_range: outline_item
 1976                        .annotation_range
 1977                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1978                });
 1979            return Some(outline_items.collect());
 1980        }
 1981
 1982        None
 1983    }
 1984
 1985    fn new_internal(
 1986        mode: EditorMode,
 1987        multi_buffer: Entity<MultiBuffer>,
 1988        project: Option<Entity<Project>>,
 1989        display_map: Option<Entity<DisplayMap>>,
 1990        window: &mut Window,
 1991        cx: &mut Context<Self>,
 1992    ) -> Self {
 1993        debug_assert!(
 1994            display_map.is_none() || mode.is_minimap(),
 1995            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1996        );
 1997
 1998        let full_mode = mode.is_full();
 1999        let is_minimap = mode.is_minimap();
 2000        let diagnostics_max_severity = if full_mode {
 2001            EditorSettings::get_global(cx)
 2002                .diagnostics_max_severity
 2003                .unwrap_or(DiagnosticSeverity::Hint)
 2004        } else {
 2005            DiagnosticSeverity::Off
 2006        };
 2007        let style = window.text_style();
 2008        let font_size = style.font_size.to_pixels(window.rem_size());
 2009        let editor = cx.entity().downgrade();
 2010        let fold_placeholder = FoldPlaceholder {
 2011            constrain_width: false,
 2012            render: Arc::new(move |fold_id, fold_range, cx| {
 2013                let editor = editor.clone();
 2014                div()
 2015                    .id(fold_id)
 2016                    .bg(cx.theme().colors().ghost_element_background)
 2017                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 2018                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 2019                    .rounded_xs()
 2020                    .size_full()
 2021                    .cursor_pointer()
 2022                    .child("")
 2023                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2024                    .on_click(move |_, _window, cx| {
 2025                        editor
 2026                            .update(cx, |editor, cx| {
 2027                                editor.unfold_ranges(
 2028                                    &[fold_range.start..fold_range.end],
 2029                                    true,
 2030                                    false,
 2031                                    cx,
 2032                                );
 2033                                cx.stop_propagation();
 2034                            })
 2035                            .ok();
 2036                    })
 2037                    .into_any()
 2038            }),
 2039            merge_adjacent: true,
 2040            ..FoldPlaceholder::default()
 2041        };
 2042        let display_map = display_map.unwrap_or_else(|| {
 2043            cx.new(|cx| {
 2044                DisplayMap::new(
 2045                    multi_buffer.clone(),
 2046                    style.font(),
 2047                    font_size,
 2048                    None,
 2049                    FILE_HEADER_HEIGHT,
 2050                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2051                    fold_placeholder,
 2052                    diagnostics_max_severity,
 2053                    cx,
 2054                )
 2055            })
 2056        });
 2057
 2058        let selections = SelectionsCollection::new();
 2059
 2060        let blink_manager = cx.new(|cx| {
 2061            let mut blink_manager = BlinkManager::new(
 2062                CURSOR_BLINK_INTERVAL,
 2063                |cx| EditorSettings::get_global(cx).cursor_blink,
 2064                cx,
 2065            );
 2066            if is_minimap {
 2067                blink_manager.disable(cx);
 2068            }
 2069            blink_manager
 2070        });
 2071
 2072        let soft_wrap_mode_override =
 2073            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2074
 2075        let mut project_subscriptions = Vec::new();
 2076        if full_mode && let Some(project) = project.as_ref() {
 2077            project_subscriptions.push(cx.subscribe_in(
 2078                project,
 2079                window,
 2080                |editor, _, event, window, cx| match event {
 2081                    project::Event::RefreshCodeLens => {
 2082                        // we always query lens with actions, without storing them, always refreshing them
 2083                    }
 2084                    project::Event::RefreshInlayHints {
 2085                        server_id,
 2086                        request_id,
 2087                    } => {
 2088                        editor.refresh_inlay_hints(
 2089                            InlayHintRefreshReason::RefreshRequested {
 2090                                server_id: *server_id,
 2091                                request_id: *request_id,
 2092                            },
 2093                            cx,
 2094                        );
 2095                    }
 2096                    project::Event::LanguageServerRemoved(..) => {
 2097                        if editor.tasks_update_task.is_none() {
 2098                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2099                        }
 2100                        editor.registered_buffers.clear();
 2101                        editor.register_visible_buffers(cx);
 2102                    }
 2103                    project::Event::LanguageServerAdded(..) => {
 2104                        if editor.tasks_update_task.is_none() {
 2105                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2106                        }
 2107                    }
 2108                    project::Event::SnippetEdit(id, snippet_edits) => {
 2109                        // todo(lw): Non singletons
 2110                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2111                            let snapshot = buffer.read(cx).snapshot();
 2112                            let focus_handle = editor.focus_handle(cx);
 2113                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2114                                for (range, snippet) in snippet_edits {
 2115                                    let buffer_range =
 2116                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2117                                    editor
 2118                                        .insert_snippet(
 2119                                            &[MultiBufferOffset(buffer_range.start)
 2120                                                ..MultiBufferOffset(buffer_range.end)],
 2121                                            snippet.clone(),
 2122                                            window,
 2123                                            cx,
 2124                                        )
 2125                                        .ok();
 2126                                }
 2127                            }
 2128                        }
 2129                    }
 2130                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2131                        let buffer_id = *buffer_id;
 2132                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2133                            editor.register_buffer(buffer_id, cx);
 2134                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2135                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2136                            refresh_linked_ranges(editor, window, cx);
 2137                            editor.refresh_code_actions(window, cx);
 2138                            editor.refresh_document_highlights(cx);
 2139                        }
 2140                    }
 2141
 2142                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2143                        let Some(workspace) = editor.workspace() else {
 2144                            return;
 2145                        };
 2146                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2147                        else {
 2148                            return;
 2149                        };
 2150
 2151                        if active_editor.entity_id() == cx.entity_id() {
 2152                            let entity_id = cx.entity_id();
 2153                            workspace.update(cx, |this, cx| {
 2154                                this.panes_mut()
 2155                                    .iter_mut()
 2156                                    .filter(|pane| pane.entity_id() != entity_id)
 2157                                    .for_each(|p| {
 2158                                        p.update(cx, |pane, _| {
 2159                                            pane.nav_history_mut().rename_item(
 2160                                                entity_id,
 2161                                                project_path.clone(),
 2162                                                abs_path.clone().into(),
 2163                                            );
 2164                                        })
 2165                                    });
 2166                            });
 2167
 2168                            Self::open_transaction_for_hidden_buffers(
 2169                                workspace,
 2170                                transaction.clone(),
 2171                                "Rename".to_string(),
 2172                                window,
 2173                                cx,
 2174                            );
 2175                        }
 2176                    }
 2177
 2178                    project::Event::WorkspaceEditApplied(transaction) => {
 2179                        let Some(workspace) = editor.workspace() else {
 2180                            return;
 2181                        };
 2182                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2183                        else {
 2184                            return;
 2185                        };
 2186
 2187                        if active_editor.entity_id() == cx.entity_id() {
 2188                            Self::open_transaction_for_hidden_buffers(
 2189                                workspace,
 2190                                transaction.clone(),
 2191                                "LSP Edit".to_string(),
 2192                                window,
 2193                                cx,
 2194                            );
 2195                        }
 2196                    }
 2197
 2198                    _ => {}
 2199                },
 2200            ));
 2201            if let Some(task_inventory) = project
 2202                .read(cx)
 2203                .task_store()
 2204                .read(cx)
 2205                .task_inventory()
 2206                .cloned()
 2207            {
 2208                project_subscriptions.push(cx.observe_in(
 2209                    &task_inventory,
 2210                    window,
 2211                    |editor, _, window, cx| {
 2212                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2213                    },
 2214                ));
 2215            };
 2216
 2217            project_subscriptions.push(cx.subscribe_in(
 2218                &project.read(cx).breakpoint_store(),
 2219                window,
 2220                |editor, _, event, window, cx| match event {
 2221                    BreakpointStoreEvent::ClearDebugLines => {
 2222                        editor.clear_row_highlights::<ActiveDebugLine>();
 2223                        editor.refresh_inline_values(cx);
 2224                    }
 2225                    BreakpointStoreEvent::SetDebugLine => {
 2226                        if editor.go_to_active_debug_line(window, cx) {
 2227                            cx.stop_propagation();
 2228                        }
 2229
 2230                        editor.refresh_inline_values(cx);
 2231                    }
 2232                    _ => {}
 2233                },
 2234            ));
 2235            let git_store = project.read(cx).git_store().clone();
 2236            let project = project.clone();
 2237            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2238                if let GitStoreEvent::RepositoryAdded = event {
 2239                    this.load_diff_task = Some(
 2240                        update_uncommitted_diff_for_buffer(
 2241                            cx.entity(),
 2242                            &project,
 2243                            this.buffer.read(cx).all_buffers(),
 2244                            this.buffer.clone(),
 2245                            cx,
 2246                        )
 2247                        .shared(),
 2248                    );
 2249                }
 2250            }));
 2251        }
 2252
 2253        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2254
 2255        let inlay_hint_settings =
 2256            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2257        let focus_handle = cx.focus_handle();
 2258        if !is_minimap {
 2259            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2260                .detach();
 2261            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2262                .detach();
 2263            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2264                .detach();
 2265            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2266                .detach();
 2267            cx.observe_pending_input(window, Self::observe_pending_input)
 2268                .detach();
 2269        }
 2270
 2271        let show_indent_guides =
 2272            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2273                Some(false)
 2274            } else {
 2275                None
 2276            };
 2277
 2278        let breakpoint_store = match (&mode, project.as_ref()) {
 2279            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2280            _ => None,
 2281        };
 2282
 2283        let mut code_action_providers = Vec::new();
 2284        let mut load_uncommitted_diff = None;
 2285        if let Some(project) = project.clone() {
 2286            load_uncommitted_diff = Some(
 2287                update_uncommitted_diff_for_buffer(
 2288                    cx.entity(),
 2289                    &project,
 2290                    multi_buffer.read(cx).all_buffers(),
 2291                    multi_buffer.clone(),
 2292                    cx,
 2293                )
 2294                .shared(),
 2295            );
 2296            code_action_providers.push(Rc::new(project) as Rc<_>);
 2297        }
 2298
 2299        let mut editor = Self {
 2300            focus_handle,
 2301            show_cursor_when_unfocused: false,
 2302            last_focused_descendant: None,
 2303            buffer: multi_buffer.clone(),
 2304            display_map: display_map.clone(),
 2305            placeholder_display_map: None,
 2306            selections,
 2307            scroll_manager: ScrollManager::new(cx),
 2308            columnar_selection_state: None,
 2309            add_selections_state: None,
 2310            select_next_state: None,
 2311            select_prev_state: None,
 2312            selection_history: SelectionHistory::default(),
 2313            defer_selection_effects: false,
 2314            deferred_selection_effects_state: None,
 2315            autoclose_regions: Vec::new(),
 2316            snippet_stack: InvalidationStack::default(),
 2317            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2318            ime_transaction: None,
 2319            active_diagnostics: ActiveDiagnostic::None,
 2320            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2321            inline_diagnostics_update: Task::ready(()),
 2322            inline_diagnostics: Vec::new(),
 2323            soft_wrap_mode_override,
 2324            diagnostics_max_severity,
 2325            hard_wrap: None,
 2326            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2327            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2328            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2329            project,
 2330            blink_manager: blink_manager.clone(),
 2331            show_local_selections: true,
 2332            show_scrollbars: ScrollbarAxes {
 2333                horizontal: full_mode,
 2334                vertical: full_mode,
 2335            },
 2336            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2337            offset_content: !matches!(mode, EditorMode::SingleLine),
 2338            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2339            show_gutter: full_mode,
 2340            show_line_numbers: (!full_mode).then_some(false),
 2341            use_relative_line_numbers: None,
 2342            disable_expand_excerpt_buttons: !full_mode,
 2343            delegate_expand_excerpts: false,
 2344            show_git_diff_gutter: None,
 2345            show_code_actions: None,
 2346            show_runnables: None,
 2347            show_breakpoints: None,
 2348            show_diff_review_button: false,
 2349            show_wrap_guides: None,
 2350            show_indent_guides,
 2351            buffers_with_disabled_indent_guides: HashSet::default(),
 2352            highlight_order: 0,
 2353            highlighted_rows: HashMap::default(),
 2354            background_highlights: HashMap::default(),
 2355            gutter_highlights: HashMap::default(),
 2356            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2357            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2358            nav_history: None,
 2359            context_menu: RefCell::new(None),
 2360            context_menu_options: None,
 2361            mouse_context_menu: None,
 2362            completion_tasks: Vec::new(),
 2363            inline_blame_popover: None,
 2364            inline_blame_popover_show_task: None,
 2365            signature_help_state: SignatureHelpState::default(),
 2366            auto_signature_help: None,
 2367            find_all_references_task_sources: Vec::new(),
 2368            next_completion_id: 0,
 2369            next_inlay_id: 0,
 2370            code_action_providers,
 2371            available_code_actions: None,
 2372            code_actions_task: None,
 2373            quick_selection_highlight_task: None,
 2374            debounced_selection_highlight_task: None,
 2375            debounced_selection_highlight_complete: false,
 2376            document_highlights_task: None,
 2377            linked_editing_range_task: None,
 2378            pending_rename: None,
 2379            searchable: !is_minimap,
 2380            cursor_shape: EditorSettings::get_global(cx)
 2381                .cursor_shape
 2382                .unwrap_or_default(),
 2383            cursor_offset_on_selection: false,
 2384            current_line_highlight: None,
 2385            autoindent_mode: Some(AutoindentMode::EachLine),
 2386            collapse_matches: false,
 2387            workspace: None,
 2388            input_enabled: !is_minimap,
 2389            use_modal_editing: full_mode,
 2390            read_only: is_minimap,
 2391            use_autoclose: true,
 2392            use_auto_surround: true,
 2393            auto_replace_emoji_shortcode: false,
 2394            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2395            leader_id: None,
 2396            remote_id: None,
 2397            hover_state: HoverState::default(),
 2398            pending_mouse_down: None,
 2399            prev_pressure_stage: None,
 2400            hovered_link_state: None,
 2401            edit_prediction_provider: None,
 2402            active_edit_prediction: None,
 2403            stale_edit_prediction_in_menu: None,
 2404            edit_prediction_preview: EditPredictionPreview::Inactive {
 2405                released_too_fast: false,
 2406            },
 2407            inline_diagnostics_enabled: full_mode,
 2408            diagnostics_enabled: full_mode,
 2409            word_completions_enabled: full_mode,
 2410            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2411            gutter_hovered: false,
 2412            pixel_position_of_newest_cursor: None,
 2413            last_bounds: None,
 2414            last_position_map: None,
 2415            expect_bounds_change: None,
 2416            gutter_dimensions: GutterDimensions::default(),
 2417            style: None,
 2418            show_cursor_names: false,
 2419            hovered_cursors: HashMap::default(),
 2420            next_editor_action_id: EditorActionId::default(),
 2421            editor_actions: Rc::default(),
 2422            edit_predictions_hidden_for_vim_mode: false,
 2423            show_edit_predictions_override: None,
 2424            show_completions_on_input_override: None,
 2425            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2426            edit_prediction_settings: EditPredictionSettings::Disabled,
 2427            edit_prediction_indent_conflict: false,
 2428            edit_prediction_requires_modifier_in_indent_conflict: true,
 2429            custom_context_menu: None,
 2430            show_git_blame_gutter: false,
 2431            show_git_blame_inline: false,
 2432            show_selection_menu: None,
 2433            show_git_blame_inline_delay_task: None,
 2434            git_blame_inline_enabled: full_mode
 2435                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2436            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2437            buffer_serialization: is_minimap.not().then(|| {
 2438                BufferSerialization::new(
 2439                    ProjectSettings::get_global(cx)
 2440                        .session
 2441                        .restore_unsaved_buffers,
 2442                )
 2443            }),
 2444            blame: None,
 2445            blame_subscription: None,
 2446            tasks: BTreeMap::default(),
 2447
 2448            breakpoint_store,
 2449            gutter_breakpoint_indicator: (None, None),
 2450            gutter_diff_review_indicator: (None, None),
 2451            diff_review_overlays: Vec::new(),
 2452            stored_review_comments: Vec::new(),
 2453            next_review_comment_id: 0,
 2454            hovered_diff_hunk_row: None,
 2455            _subscriptions: (!is_minimap)
 2456                .then(|| {
 2457                    vec![
 2458                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2459                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2460                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2461                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2462                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2463                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2464                        cx.observe_window_activation(window, |editor, window, cx| {
 2465                            let active = window.is_window_active();
 2466                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2467                                if active {
 2468                                    blink_manager.enable(cx);
 2469                                } else {
 2470                                    blink_manager.disable(cx);
 2471                                }
 2472                            });
 2473                            if active {
 2474                                editor.show_mouse_cursor(cx);
 2475                            }
 2476                        }),
 2477                    ]
 2478                })
 2479                .unwrap_or_default(),
 2480            tasks_update_task: None,
 2481            pull_diagnostics_task: Task::ready(()),
 2482            pull_diagnostics_background_task: Task::ready(()),
 2483            colors: None,
 2484            refresh_colors_task: Task::ready(()),
 2485            inlay_hints: None,
 2486            next_color_inlay_id: 0,
 2487            post_scroll_update: Task::ready(()),
 2488            linked_edit_ranges: Default::default(),
 2489            in_project_search: false,
 2490            previous_search_ranges: None,
 2491            breadcrumb_header: None,
 2492            focused_block: None,
 2493            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2494            addons: HashMap::default(),
 2495            registered_buffers: HashMap::default(),
 2496            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2497            selection_mark_mode: false,
 2498            toggle_fold_multiple_buffers: Task::ready(()),
 2499            serialize_selections: Task::ready(()),
 2500            serialize_folds: Task::ready(()),
 2501            text_style_refinement: None,
 2502            load_diff_task: load_uncommitted_diff,
 2503            temporary_diff_override: false,
 2504            mouse_cursor_hidden: false,
 2505            minimap: None,
 2506            hide_mouse_mode: EditorSettings::get_global(cx)
 2507                .hide_mouse
 2508                .unwrap_or_default(),
 2509            change_list: ChangeList::new(),
 2510            mode,
 2511            selection_drag_state: SelectionDragState::None,
 2512            folding_newlines: Task::ready(()),
 2513            lookup_key: None,
 2514            select_next_is_case_sensitive: None,
 2515            applicable_language_settings: HashMap::default(),
 2516            accent_data: None,
 2517            fetched_tree_sitter_chunks: HashMap::default(),
 2518            number_deleted_lines: false,
 2519        };
 2520
 2521        if is_minimap {
 2522            return editor;
 2523        }
 2524
 2525        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2526        editor.accent_data = editor.fetch_accent_data(cx);
 2527
 2528        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2529            editor
 2530                ._subscriptions
 2531                .push(cx.observe(breakpoints, |_, _, cx| {
 2532                    cx.notify();
 2533                }));
 2534        }
 2535        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2536        editor._subscriptions.extend(project_subscriptions);
 2537
 2538        editor._subscriptions.push(cx.subscribe_in(
 2539            &cx.entity(),
 2540            window,
 2541            |editor, _, e: &EditorEvent, window, cx| match e {
 2542                EditorEvent::ScrollPositionChanged { local, .. } => {
 2543                    if *local {
 2544                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2545                        editor.inline_blame_popover.take();
 2546                        let new_anchor = editor.scroll_manager.anchor();
 2547                        let snapshot = editor.snapshot(window, cx);
 2548                        editor.update_restoration_data(cx, move |data| {
 2549                            data.scroll_position = (
 2550                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2551                                new_anchor.offset,
 2552                            );
 2553                        });
 2554
 2555                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2556                            cx.background_executor()
 2557                                .timer(Duration::from_millis(50))
 2558                                .await;
 2559                            editor
 2560                                .update_in(cx, |editor, window, cx| {
 2561                                    editor.register_visible_buffers(cx);
 2562                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2563                                    editor.refresh_inlay_hints(
 2564                                        InlayHintRefreshReason::NewLinesShown,
 2565                                        cx,
 2566                                    );
 2567                                    editor.colorize_brackets(false, cx);
 2568                                })
 2569                                .ok();
 2570                        });
 2571                    }
 2572                }
 2573                EditorEvent::Edited { .. } => {
 2574                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2575                        .map(|vim_mode| vim_mode.0)
 2576                        .unwrap_or(false);
 2577                    if !vim_mode {
 2578                        let display_map = editor.display_snapshot(cx);
 2579                        let selections = editor.selections.all_adjusted_display(&display_map);
 2580                        let pop_state = editor
 2581                            .change_list
 2582                            .last()
 2583                            .map(|previous| {
 2584                                previous.len() == selections.len()
 2585                                    && previous.iter().enumerate().all(|(ix, p)| {
 2586                                        p.to_display_point(&display_map).row()
 2587                                            == selections[ix].head().row()
 2588                                    })
 2589                            })
 2590                            .unwrap_or(false);
 2591                        let new_positions = selections
 2592                            .into_iter()
 2593                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2594                            .collect();
 2595                        editor
 2596                            .change_list
 2597                            .push_to_change_list(pop_state, new_positions);
 2598                    }
 2599                }
 2600                _ => (),
 2601            },
 2602        ));
 2603
 2604        if let Some(dap_store) = editor
 2605            .project
 2606            .as_ref()
 2607            .map(|project| project.read(cx).dap_store())
 2608        {
 2609            let weak_editor = cx.weak_entity();
 2610
 2611            editor
 2612                ._subscriptions
 2613                .push(
 2614                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2615                        let session_entity = cx.entity();
 2616                        weak_editor
 2617                            .update(cx, |editor, cx| {
 2618                                editor._subscriptions.push(
 2619                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2620                                );
 2621                            })
 2622                            .ok();
 2623                    }),
 2624                );
 2625
 2626            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2627                editor
 2628                    ._subscriptions
 2629                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2630            }
 2631        }
 2632
 2633        // skip adding the initial selection to selection history
 2634        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2635        editor.end_selection(window, cx);
 2636        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2637
 2638        editor.scroll_manager.show_scrollbars(window, cx);
 2639        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2640
 2641        if full_mode {
 2642            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2643            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2644
 2645            if editor.git_blame_inline_enabled {
 2646                editor.start_git_blame_inline(false, window, cx);
 2647            }
 2648
 2649            editor.go_to_active_debug_line(window, cx);
 2650
 2651            editor.minimap =
 2652                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2653            editor.colors = Some(LspColorData::new(cx));
 2654            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2655
 2656            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2657                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2658            }
 2659            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2660        }
 2661
 2662        editor
 2663    }
 2664
 2665    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2666        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2667    }
 2668
 2669    pub fn deploy_mouse_context_menu(
 2670        &mut self,
 2671        position: gpui::Point<Pixels>,
 2672        context_menu: Entity<ContextMenu>,
 2673        window: &mut Window,
 2674        cx: &mut Context<Self>,
 2675    ) {
 2676        self.mouse_context_menu = Some(MouseContextMenu::new(
 2677            self,
 2678            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2679            context_menu,
 2680            window,
 2681            cx,
 2682        ));
 2683    }
 2684
 2685    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2686        self.mouse_context_menu
 2687            .as_ref()
 2688            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2689    }
 2690
 2691    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2692        if self
 2693            .selections
 2694            .pending_anchor()
 2695            .is_some_and(|pending_selection| {
 2696                let snapshot = self.buffer().read(cx).snapshot(cx);
 2697                pending_selection.range().includes(range, &snapshot)
 2698            })
 2699        {
 2700            return true;
 2701        }
 2702
 2703        self.selections
 2704            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2705            .into_iter()
 2706            .any(|selection| {
 2707                // This is needed to cover a corner case, if we just check for an existing
 2708                // selection in the fold range, having a cursor at the start of the fold
 2709                // marks it as selected. Non-empty selections don't cause this.
 2710                let length = selection.end - selection.start;
 2711                length > 0
 2712            })
 2713    }
 2714
 2715    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2716        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2717    }
 2718
 2719    fn key_context_internal(
 2720        &self,
 2721        has_active_edit_prediction: bool,
 2722        window: &mut Window,
 2723        cx: &mut App,
 2724    ) -> KeyContext {
 2725        let mut key_context = KeyContext::new_with_defaults();
 2726        key_context.add("Editor");
 2727        let mode = match self.mode {
 2728            EditorMode::SingleLine => "single_line",
 2729            EditorMode::AutoHeight { .. } => "auto_height",
 2730            EditorMode::Minimap { .. } => "minimap",
 2731            EditorMode::Full { .. } => "full",
 2732        };
 2733
 2734        if EditorSettings::jupyter_enabled(cx) {
 2735            key_context.add("jupyter");
 2736        }
 2737
 2738        key_context.set("mode", mode);
 2739        if self.pending_rename.is_some() {
 2740            key_context.add("renaming");
 2741        }
 2742
 2743        if let Some(snippet_stack) = self.snippet_stack.last() {
 2744            key_context.add("in_snippet");
 2745
 2746            if snippet_stack.active_index > 0 {
 2747                key_context.add("has_previous_tabstop");
 2748            }
 2749
 2750            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2751                key_context.add("has_next_tabstop");
 2752            }
 2753        }
 2754
 2755        match self.context_menu.borrow().as_ref() {
 2756            Some(CodeContextMenu::Completions(menu)) => {
 2757                if menu.visible() {
 2758                    key_context.add("menu");
 2759                    key_context.add("showing_completions");
 2760                }
 2761            }
 2762            Some(CodeContextMenu::CodeActions(menu)) => {
 2763                if menu.visible() {
 2764                    key_context.add("menu");
 2765                    key_context.add("showing_code_actions")
 2766                }
 2767            }
 2768            None => {}
 2769        }
 2770
 2771        if self.signature_help_state.has_multiple_signatures() {
 2772            key_context.add("showing_signature_help");
 2773        }
 2774
 2775        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2776        if !self.focus_handle(cx).contains_focused(window, cx)
 2777            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2778        {
 2779            for addon in self.addons.values() {
 2780                addon.extend_key_context(&mut key_context, cx)
 2781            }
 2782        }
 2783
 2784        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2785            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2786                Some(
 2787                    file.full_path(cx)
 2788                        .extension()?
 2789                        .to_string_lossy()
 2790                        .to_lowercase(),
 2791                )
 2792            }) {
 2793                key_context.set("extension", extension);
 2794            }
 2795        } else {
 2796            key_context.add("multibuffer");
 2797        }
 2798
 2799        if has_active_edit_prediction {
 2800            if self.edit_prediction_in_conflict() {
 2801                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2802            } else {
 2803                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2804                key_context.add("copilot_suggestion");
 2805            }
 2806        }
 2807
 2808        if self.selection_mark_mode {
 2809            key_context.add("selection_mode");
 2810        }
 2811
 2812        let disjoint = self.selections.disjoint_anchors();
 2813        let snapshot = self.snapshot(window, cx);
 2814        let snapshot = snapshot.buffer_snapshot();
 2815        if self.mode == EditorMode::SingleLine
 2816            && let [selection] = disjoint
 2817            && selection.start == selection.end
 2818            && selection.end.to_offset(snapshot) == snapshot.len()
 2819        {
 2820            key_context.add("end_of_input");
 2821        }
 2822
 2823        if self.has_any_expanded_diff_hunks(cx) {
 2824            key_context.add("diffs_expanded");
 2825        }
 2826
 2827        key_context
 2828    }
 2829
 2830    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2831        self.last_bounds.as_ref()
 2832    }
 2833
 2834    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2835        if self.mouse_cursor_hidden {
 2836            self.mouse_cursor_hidden = false;
 2837            cx.notify();
 2838        }
 2839    }
 2840
 2841    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2842        let hide_mouse_cursor = match origin {
 2843            HideMouseCursorOrigin::TypingAction => {
 2844                matches!(
 2845                    self.hide_mouse_mode,
 2846                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2847                )
 2848            }
 2849            HideMouseCursorOrigin::MovementAction => {
 2850                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2851            }
 2852        };
 2853        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2854            self.mouse_cursor_hidden = hide_mouse_cursor;
 2855            cx.notify();
 2856        }
 2857    }
 2858
 2859    pub fn edit_prediction_in_conflict(&self) -> bool {
 2860        if !self.show_edit_predictions_in_menu() {
 2861            return false;
 2862        }
 2863
 2864        let showing_completions = self
 2865            .context_menu
 2866            .borrow()
 2867            .as_ref()
 2868            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2869
 2870        showing_completions
 2871            || self.edit_prediction_requires_modifier()
 2872            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2873            // bindings to insert tab characters.
 2874            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2875    }
 2876
 2877    pub fn accept_edit_prediction_keybind(
 2878        &self,
 2879        granularity: EditPredictionGranularity,
 2880        window: &mut Window,
 2881        cx: &mut App,
 2882    ) -> AcceptEditPredictionBinding {
 2883        let key_context = self.key_context_internal(true, window, cx);
 2884        let in_conflict = self.edit_prediction_in_conflict();
 2885
 2886        let bindings =
 2887            match granularity {
 2888                EditPredictionGranularity::Word => window
 2889                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2890                EditPredictionGranularity::Line => window
 2891                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2892                EditPredictionGranularity::Full => {
 2893                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2894                }
 2895            };
 2896
 2897        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2898            !in_conflict
 2899                || binding
 2900                    .keystrokes()
 2901                    .first()
 2902                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2903        }))
 2904    }
 2905
 2906    pub fn new_file(
 2907        workspace: &mut Workspace,
 2908        _: &workspace::NewFile,
 2909        window: &mut Window,
 2910        cx: &mut Context<Workspace>,
 2911    ) {
 2912        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2913            "Failed to create buffer",
 2914            window,
 2915            cx,
 2916            |e, _, _| match e.error_code() {
 2917                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2918                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2919                e.error_tag("required").unwrap_or("the latest version")
 2920            )),
 2921                _ => None,
 2922            },
 2923        );
 2924    }
 2925
 2926    pub fn new_in_workspace(
 2927        workspace: &mut Workspace,
 2928        window: &mut Window,
 2929        cx: &mut Context<Workspace>,
 2930    ) -> Task<Result<Entity<Editor>>> {
 2931        let project = workspace.project().clone();
 2932        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 2933
 2934        cx.spawn_in(window, async move |workspace, cx| {
 2935            let buffer = create.await?;
 2936            workspace.update_in(cx, |workspace, window, cx| {
 2937                let editor =
 2938                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2939                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2940                editor
 2941            })
 2942        })
 2943    }
 2944
 2945    fn new_file_vertical(
 2946        workspace: &mut Workspace,
 2947        _: &workspace::NewFileSplitVertical,
 2948        window: &mut Window,
 2949        cx: &mut Context<Workspace>,
 2950    ) {
 2951        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2952    }
 2953
 2954    fn new_file_horizontal(
 2955        workspace: &mut Workspace,
 2956        _: &workspace::NewFileSplitHorizontal,
 2957        window: &mut Window,
 2958        cx: &mut Context<Workspace>,
 2959    ) {
 2960        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2961    }
 2962
 2963    fn new_file_split(
 2964        workspace: &mut Workspace,
 2965        action: &workspace::NewFileSplit,
 2966        window: &mut Window,
 2967        cx: &mut Context<Workspace>,
 2968    ) {
 2969        Self::new_file_in_direction(workspace, action.0, window, cx)
 2970    }
 2971
 2972    fn new_file_in_direction(
 2973        workspace: &mut Workspace,
 2974        direction: SplitDirection,
 2975        window: &mut Window,
 2976        cx: &mut Context<Workspace>,
 2977    ) {
 2978        let project = workspace.project().clone();
 2979        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 2980
 2981        cx.spawn_in(window, async move |workspace, cx| {
 2982            let buffer = create.await?;
 2983            workspace.update_in(cx, move |workspace, window, cx| {
 2984                workspace.split_item(
 2985                    direction,
 2986                    Box::new(
 2987                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2988                    ),
 2989                    window,
 2990                    cx,
 2991                )
 2992            })?;
 2993            anyhow::Ok(())
 2994        })
 2995        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2996            match e.error_code() {
 2997                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2998                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2999                e.error_tag("required").unwrap_or("the latest version")
 3000            )),
 3001                _ => None,
 3002            }
 3003        });
 3004    }
 3005
 3006    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3007        self.leader_id
 3008    }
 3009
 3010    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3011        &self.buffer
 3012    }
 3013
 3014    pub fn project(&self) -> Option<&Entity<Project>> {
 3015        self.project.as_ref()
 3016    }
 3017
 3018    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3019        self.workspace.as_ref()?.0.upgrade()
 3020    }
 3021
 3022    /// Returns the workspace serialization ID if this editor should be serialized.
 3023    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3024        self.workspace
 3025            .as_ref()
 3026            .filter(|_| self.should_serialize_buffer())
 3027            .and_then(|workspace| workspace.1)
 3028    }
 3029
 3030    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3031        self.buffer().read(cx).title(cx)
 3032    }
 3033
 3034    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3035        let git_blame_gutter_max_author_length = self
 3036            .render_git_blame_gutter(cx)
 3037            .then(|| {
 3038                if let Some(blame) = self.blame.as_ref() {
 3039                    let max_author_length =
 3040                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3041                    Some(max_author_length)
 3042                } else {
 3043                    None
 3044                }
 3045            })
 3046            .flatten();
 3047
 3048        EditorSnapshot {
 3049            mode: self.mode.clone(),
 3050            show_gutter: self.show_gutter,
 3051            offset_content: self.offset_content,
 3052            show_line_numbers: self.show_line_numbers,
 3053            number_deleted_lines: self.number_deleted_lines,
 3054            show_git_diff_gutter: self.show_git_diff_gutter,
 3055            show_code_actions: self.show_code_actions,
 3056            show_runnables: self.show_runnables,
 3057            show_breakpoints: self.show_breakpoints,
 3058            git_blame_gutter_max_author_length,
 3059            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 3060            placeholder_display_snapshot: self
 3061                .placeholder_display_map
 3062                .as_ref()
 3063                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3064            scroll_anchor: self.scroll_manager.anchor(),
 3065            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3066            is_focused: self.focus_handle.is_focused(window),
 3067            current_line_highlight: self
 3068                .current_line_highlight
 3069                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3070            gutter_hovered: self.gutter_hovered,
 3071        }
 3072    }
 3073
 3074    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3075        self.buffer.read(cx).language_at(point, cx)
 3076    }
 3077
 3078    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3079        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3080    }
 3081
 3082    pub fn active_excerpt(
 3083        &self,
 3084        cx: &App,
 3085    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3086        self.buffer
 3087            .read(cx)
 3088            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3089    }
 3090
 3091    pub fn mode(&self) -> &EditorMode {
 3092        &self.mode
 3093    }
 3094
 3095    pub fn set_mode(&mut self, mode: EditorMode) {
 3096        self.mode = mode;
 3097    }
 3098
 3099    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3100        self.collaboration_hub.as_deref()
 3101    }
 3102
 3103    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3104        self.collaboration_hub = Some(hub);
 3105    }
 3106
 3107    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3108        self.in_project_search = in_project_search;
 3109    }
 3110
 3111    pub fn set_custom_context_menu(
 3112        &mut self,
 3113        f: impl 'static
 3114        + Fn(
 3115            &mut Self,
 3116            DisplayPoint,
 3117            &mut Window,
 3118            &mut Context<Self>,
 3119        ) -> Option<Entity<ui::ContextMenu>>,
 3120    ) {
 3121        self.custom_context_menu = Some(Box::new(f))
 3122    }
 3123
 3124    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3125        self.completion_provider = provider;
 3126    }
 3127
 3128    #[cfg(any(test, feature = "test-support"))]
 3129    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3130        self.completion_provider.clone()
 3131    }
 3132
 3133    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3134        self.semantics_provider.clone()
 3135    }
 3136
 3137    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3138        self.semantics_provider = provider;
 3139    }
 3140
 3141    pub fn set_edit_prediction_provider<T>(
 3142        &mut self,
 3143        provider: Option<Entity<T>>,
 3144        window: &mut Window,
 3145        cx: &mut Context<Self>,
 3146    ) where
 3147        T: EditPredictionDelegate,
 3148    {
 3149        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3150            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3151                if this.focus_handle.is_focused(window) {
 3152                    this.update_visible_edit_prediction(window, cx);
 3153                }
 3154            }),
 3155            provider: Arc::new(provider),
 3156        });
 3157        self.update_edit_prediction_settings(cx);
 3158        self.refresh_edit_prediction(false, false, window, cx);
 3159    }
 3160
 3161    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3162        self.placeholder_display_map
 3163            .as_ref()
 3164            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3165    }
 3166
 3167    pub fn set_placeholder_text(
 3168        &mut self,
 3169        placeholder_text: &str,
 3170        window: &mut Window,
 3171        cx: &mut Context<Self>,
 3172    ) {
 3173        let multibuffer = cx
 3174            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3175
 3176        let style = window.text_style();
 3177
 3178        self.placeholder_display_map = Some(cx.new(|cx| {
 3179            DisplayMap::new(
 3180                multibuffer,
 3181                style.font(),
 3182                style.font_size.to_pixels(window.rem_size()),
 3183                None,
 3184                FILE_HEADER_HEIGHT,
 3185                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3186                Default::default(),
 3187                DiagnosticSeverity::Off,
 3188                cx,
 3189            )
 3190        }));
 3191        cx.notify();
 3192    }
 3193
 3194    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3195        self.cursor_shape = cursor_shape;
 3196
 3197        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3198        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3199
 3200        cx.notify();
 3201    }
 3202
 3203    pub fn cursor_shape(&self) -> CursorShape {
 3204        self.cursor_shape
 3205    }
 3206
 3207    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3208        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3209    }
 3210
 3211    pub fn set_current_line_highlight(
 3212        &mut self,
 3213        current_line_highlight: Option<CurrentLineHighlight>,
 3214    ) {
 3215        self.current_line_highlight = current_line_highlight;
 3216    }
 3217
 3218    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3219        self.collapse_matches = collapse_matches;
 3220    }
 3221
 3222    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3223        if self.collapse_matches {
 3224            return range.start..range.start;
 3225        }
 3226        range.clone()
 3227    }
 3228
 3229    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3230        self.display_map.read(cx).clip_at_line_ends
 3231    }
 3232
 3233    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3234        if self.display_map.read(cx).clip_at_line_ends != clip {
 3235            self.display_map
 3236                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3237        }
 3238    }
 3239
 3240    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3241        self.input_enabled = input_enabled;
 3242    }
 3243
 3244    pub fn set_edit_predictions_hidden_for_vim_mode(
 3245        &mut self,
 3246        hidden: bool,
 3247        window: &mut Window,
 3248        cx: &mut Context<Self>,
 3249    ) {
 3250        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3251            self.edit_predictions_hidden_for_vim_mode = hidden;
 3252            if hidden {
 3253                self.update_visible_edit_prediction(window, cx);
 3254            } else {
 3255                self.refresh_edit_prediction(true, false, window, cx);
 3256            }
 3257        }
 3258    }
 3259
 3260    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3261        self.menu_edit_predictions_policy = value;
 3262    }
 3263
 3264    pub fn set_autoindent(&mut self, autoindent: bool) {
 3265        if autoindent {
 3266            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3267        } else {
 3268            self.autoindent_mode = None;
 3269        }
 3270    }
 3271
 3272    pub fn capability(&self, cx: &App) -> Capability {
 3273        if self.read_only {
 3274            Capability::ReadOnly
 3275        } else {
 3276            self.buffer.read(cx).capability()
 3277        }
 3278    }
 3279
 3280    pub fn read_only(&self, cx: &App) -> bool {
 3281        self.read_only || self.buffer.read(cx).read_only()
 3282    }
 3283
 3284    pub fn set_read_only(&mut self, read_only: bool) {
 3285        self.read_only = read_only;
 3286    }
 3287
 3288    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3289        self.use_autoclose = autoclose;
 3290    }
 3291
 3292    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3293        self.use_auto_surround = auto_surround;
 3294    }
 3295
 3296    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3297        self.auto_replace_emoji_shortcode = auto_replace;
 3298    }
 3299
 3300    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3301        self.buffer_serialization = should_serialize.then(|| {
 3302            BufferSerialization::new(
 3303                ProjectSettings::get_global(cx)
 3304                    .session
 3305                    .restore_unsaved_buffers,
 3306            )
 3307        })
 3308    }
 3309
 3310    fn should_serialize_buffer(&self) -> bool {
 3311        self.buffer_serialization.is_some()
 3312    }
 3313
 3314    pub fn toggle_edit_predictions(
 3315        &mut self,
 3316        _: &ToggleEditPrediction,
 3317        window: &mut Window,
 3318        cx: &mut Context<Self>,
 3319    ) {
 3320        if self.show_edit_predictions_override.is_some() {
 3321            self.set_show_edit_predictions(None, window, cx);
 3322        } else {
 3323            let show_edit_predictions = !self.edit_predictions_enabled();
 3324            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3325        }
 3326    }
 3327
 3328    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3329        self.show_completions_on_input_override = show_completions_on_input;
 3330    }
 3331
 3332    pub fn set_show_edit_predictions(
 3333        &mut self,
 3334        show_edit_predictions: Option<bool>,
 3335        window: &mut Window,
 3336        cx: &mut Context<Self>,
 3337    ) {
 3338        self.show_edit_predictions_override = show_edit_predictions;
 3339        self.update_edit_prediction_settings(cx);
 3340
 3341        if let Some(false) = show_edit_predictions {
 3342            self.discard_edit_prediction(false, cx);
 3343        } else {
 3344            self.refresh_edit_prediction(false, true, window, cx);
 3345        }
 3346    }
 3347
 3348    fn edit_predictions_disabled_in_scope(
 3349        &self,
 3350        buffer: &Entity<Buffer>,
 3351        buffer_position: language::Anchor,
 3352        cx: &App,
 3353    ) -> bool {
 3354        let snapshot = buffer.read(cx).snapshot();
 3355        let settings = snapshot.settings_at(buffer_position, cx);
 3356
 3357        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3358            return false;
 3359        };
 3360
 3361        scope.override_name().is_some_and(|scope_name| {
 3362            settings
 3363                .edit_predictions_disabled_in
 3364                .iter()
 3365                .any(|s| s == scope_name)
 3366        })
 3367    }
 3368
 3369    pub fn set_use_modal_editing(&mut self, to: bool) {
 3370        self.use_modal_editing = to;
 3371    }
 3372
 3373    pub fn use_modal_editing(&self) -> bool {
 3374        self.use_modal_editing
 3375    }
 3376
 3377    fn selections_did_change(
 3378        &mut self,
 3379        local: bool,
 3380        old_cursor_position: &Anchor,
 3381        effects: SelectionEffects,
 3382        window: &mut Window,
 3383        cx: &mut Context<Self>,
 3384    ) {
 3385        window.invalidate_character_coordinates();
 3386
 3387        // Copy selections to primary selection buffer
 3388        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3389        if local {
 3390            let selections = self
 3391                .selections
 3392                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3393            let buffer_handle = self.buffer.read(cx).read(cx);
 3394
 3395            let mut text = String::new();
 3396            for (index, selection) in selections.iter().enumerate() {
 3397                let text_for_selection = buffer_handle
 3398                    .text_for_range(selection.start..selection.end)
 3399                    .collect::<String>();
 3400
 3401                text.push_str(&text_for_selection);
 3402                if index != selections.len() - 1 {
 3403                    text.push('\n');
 3404                }
 3405            }
 3406
 3407            if !text.is_empty() {
 3408                cx.write_to_primary(ClipboardItem::new_string(text));
 3409            }
 3410        }
 3411
 3412        let selection_anchors = self.selections.disjoint_anchors_arc();
 3413
 3414        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3415            self.buffer.update(cx, |buffer, cx| {
 3416                buffer.set_active_selections(
 3417                    &selection_anchors,
 3418                    self.selections.line_mode(),
 3419                    self.cursor_shape,
 3420                    cx,
 3421                )
 3422            });
 3423        }
 3424        let display_map = self
 3425            .display_map
 3426            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3427        let buffer = display_map.buffer_snapshot();
 3428        if self.selections.count() == 1 {
 3429            self.add_selections_state = None;
 3430        }
 3431        self.select_next_state = None;
 3432        self.select_prev_state = None;
 3433        self.select_syntax_node_history.try_clear();
 3434        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3435        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3436        self.take_rename(false, window, cx);
 3437
 3438        let newest_selection = self.selections.newest_anchor();
 3439        let new_cursor_position = newest_selection.head();
 3440        let selection_start = newest_selection.start;
 3441
 3442        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3443            self.push_to_nav_history(
 3444                *old_cursor_position,
 3445                Some(new_cursor_position.to_point(buffer)),
 3446                false,
 3447                effects.nav_history == Some(true),
 3448                cx,
 3449            );
 3450        }
 3451
 3452        if local {
 3453            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3454                self.register_buffer(buffer_id, cx);
 3455            }
 3456
 3457            let mut context_menu = self.context_menu.borrow_mut();
 3458            let completion_menu = match context_menu.as_ref() {
 3459                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3460                Some(CodeContextMenu::CodeActions(_)) => {
 3461                    *context_menu = None;
 3462                    None
 3463                }
 3464                None => None,
 3465            };
 3466            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3467            drop(context_menu);
 3468
 3469            if effects.completions
 3470                && let Some(completion_position) = completion_position
 3471            {
 3472                let start_offset = selection_start.to_offset(buffer);
 3473                let position_matches = start_offset == completion_position.to_offset(buffer);
 3474                let continue_showing = if let Some((snap, ..)) =
 3475                    buffer.point_to_buffer_offset(completion_position)
 3476                    && !snap.capability.editable()
 3477                {
 3478                    false
 3479                } else if position_matches {
 3480                    if self.snippet_stack.is_empty() {
 3481                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3482                            == Some(CharKind::Word)
 3483                    } else {
 3484                        // Snippet choices can be shown even when the cursor is in whitespace.
 3485                        // Dismissing the menu with actions like backspace is handled by
 3486                        // invalidation regions.
 3487                        true
 3488                    }
 3489                } else {
 3490                    false
 3491                };
 3492
 3493                if continue_showing {
 3494                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3495                } else {
 3496                    self.hide_context_menu(window, cx);
 3497                }
 3498            }
 3499
 3500            hide_hover(self, cx);
 3501
 3502            if old_cursor_position.to_display_point(&display_map).row()
 3503                != new_cursor_position.to_display_point(&display_map).row()
 3504            {
 3505                self.available_code_actions.take();
 3506            }
 3507            self.refresh_code_actions(window, cx);
 3508            self.refresh_document_highlights(cx);
 3509            refresh_linked_ranges(self, window, cx);
 3510
 3511            self.refresh_selected_text_highlights(false, window, cx);
 3512            self.refresh_matching_bracket_highlights(window, cx);
 3513            self.update_visible_edit_prediction(window, cx);
 3514            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3515            self.inline_blame_popover.take();
 3516            if self.git_blame_inline_enabled {
 3517                self.start_inline_blame_timer(window, cx);
 3518            }
 3519        }
 3520
 3521        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3522        cx.emit(EditorEvent::SelectionsChanged { local });
 3523
 3524        let selections = &self.selections.disjoint_anchors_arc();
 3525        if selections.len() == 1 {
 3526            cx.emit(SearchEvent::ActiveMatchChanged)
 3527        }
 3528        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3529            let inmemory_selections = selections
 3530                .iter()
 3531                .map(|s| {
 3532                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3533                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3534                })
 3535                .collect();
 3536            self.update_restoration_data(cx, |data| {
 3537                data.selections = inmemory_selections;
 3538            });
 3539
 3540            if WorkspaceSettings::get(None, cx).restore_on_startup
 3541                != RestoreOnStartupBehavior::EmptyTab
 3542                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3543            {
 3544                let snapshot = self.buffer().read(cx).snapshot(cx);
 3545                let selections = selections.clone();
 3546                let background_executor = cx.background_executor().clone();
 3547                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3548                self.serialize_selections = cx.background_spawn(async move {
 3549                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3550                    let db_selections = selections
 3551                        .iter()
 3552                        .map(|selection| {
 3553                            (
 3554                                selection.start.to_offset(&snapshot).0,
 3555                                selection.end.to_offset(&snapshot).0,
 3556                            )
 3557                        })
 3558                        .collect();
 3559
 3560                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3561                        .await
 3562                        .with_context(|| {
 3563                            format!(
 3564                                "persisting editor selections for editor {editor_id}, \
 3565                                workspace {workspace_id:?}"
 3566                            )
 3567                        })
 3568                        .log_err();
 3569                });
 3570            }
 3571        }
 3572
 3573        cx.notify();
 3574    }
 3575
 3576    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3577        use text::ToOffset as _;
 3578        use text::ToPoint as _;
 3579
 3580        if self.mode.is_minimap()
 3581            || WorkspaceSettings::get(None, cx).restore_on_startup
 3582                == RestoreOnStartupBehavior::EmptyTab
 3583        {
 3584            return;
 3585        }
 3586
 3587        if !self.buffer().read(cx).is_singleton() {
 3588            return;
 3589        }
 3590
 3591        let display_snapshot = self
 3592            .display_map
 3593            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3594        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3595            return;
 3596        };
 3597        let inmemory_folds = display_snapshot
 3598            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3599            .map(|fold| {
 3600                fold.range.start.text_anchor.to_point(&snapshot)
 3601                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3602            })
 3603            .collect();
 3604        self.update_restoration_data(cx, |data| {
 3605            data.folds = inmemory_folds;
 3606        });
 3607
 3608        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3609            return;
 3610        };
 3611        let background_executor = cx.background_executor().clone();
 3612        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3613        const FINGERPRINT_LEN: usize = 32;
 3614        let db_folds = display_snapshot
 3615            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3616            .map(|fold| {
 3617                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3618                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3619
 3620                // Extract fingerprints - content at fold boundaries for validation on restore
 3621                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3622                // content that might change independently.
 3623                // start_fp: first min(32, fold_len) bytes of fold content
 3624                // end_fp: last min(32, fold_len) bytes of fold content
 3625                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3626                let fold_len = end - start;
 3627                let start_fp_end = snapshot
 3628                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3629                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3630                let end_fp_start = snapshot
 3631                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3632                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3633
 3634                (start, end, start_fp, end_fp)
 3635            })
 3636            .collect::<Vec<_>>();
 3637        self.serialize_folds = cx.background_spawn(async move {
 3638            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3639            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3640                .await
 3641                .with_context(|| {
 3642                    format!(
 3643                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3644                    )
 3645                })
 3646                .log_err();
 3647        });
 3648    }
 3649
 3650    pub fn sync_selections(
 3651        &mut self,
 3652        other: Entity<Editor>,
 3653        cx: &mut Context<Self>,
 3654    ) -> gpui::Subscription {
 3655        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3656        if !other_selections.is_empty() {
 3657            self.selections
 3658                .change_with(&self.display_snapshot(cx), |selections| {
 3659                    selections.select_anchors(other_selections);
 3660                });
 3661        }
 3662
 3663        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3664            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3665                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3666                if other_selections.is_empty() {
 3667                    return;
 3668                }
 3669                let snapshot = this.display_snapshot(cx);
 3670                this.selections.change_with(&snapshot, |selections| {
 3671                    selections.select_anchors(other_selections);
 3672                });
 3673            }
 3674        });
 3675
 3676        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3677            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3678                let these_selections = this.selections.disjoint_anchors().to_vec();
 3679                if these_selections.is_empty() {
 3680                    return;
 3681                }
 3682                other.update(cx, |other_editor, cx| {
 3683                    let snapshot = other_editor.display_snapshot(cx);
 3684                    other_editor
 3685                        .selections
 3686                        .change_with(&snapshot, |selections| {
 3687                            selections.select_anchors(these_selections);
 3688                        })
 3689                });
 3690            }
 3691        });
 3692
 3693        Subscription::join(other_subscription, this_subscription)
 3694    }
 3695
 3696    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3697        if self.buffer().read(cx).is_singleton() {
 3698            return;
 3699        }
 3700        let snapshot = self.buffer.read(cx).snapshot(cx);
 3701        let buffer_ids: HashSet<BufferId> = self
 3702            .selections
 3703            .disjoint_anchor_ranges()
 3704            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3705            .collect();
 3706        for buffer_id in buffer_ids {
 3707            self.unfold_buffer(buffer_id, cx);
 3708        }
 3709    }
 3710
 3711    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3712    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3713    /// effects of selection change occur at the end of the transaction.
 3714    pub fn change_selections<R>(
 3715        &mut self,
 3716        effects: SelectionEffects,
 3717        window: &mut Window,
 3718        cx: &mut Context<Self>,
 3719        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3720    ) -> R {
 3721        let snapshot = self.display_snapshot(cx);
 3722        if let Some(state) = &mut self.deferred_selection_effects_state {
 3723            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3724            state.effects.completions = effects.completions;
 3725            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3726            let (changed, result) = self.selections.change_with(&snapshot, change);
 3727            state.changed |= changed;
 3728            return result;
 3729        }
 3730        let mut state = DeferredSelectionEffectsState {
 3731            changed: false,
 3732            effects,
 3733            old_cursor_position: self.selections.newest_anchor().head(),
 3734            history_entry: SelectionHistoryEntry {
 3735                selections: self.selections.disjoint_anchors_arc(),
 3736                select_next_state: self.select_next_state.clone(),
 3737                select_prev_state: self.select_prev_state.clone(),
 3738                add_selections_state: self.add_selections_state.clone(),
 3739            },
 3740        };
 3741        let (changed, result) = self.selections.change_with(&snapshot, change);
 3742        state.changed = state.changed || changed;
 3743        if self.defer_selection_effects {
 3744            self.deferred_selection_effects_state = Some(state);
 3745        } else {
 3746            self.apply_selection_effects(state, window, cx);
 3747        }
 3748        result
 3749    }
 3750
 3751    /// Defers the effects of selection change, so that the effects of multiple calls to
 3752    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3753    /// to selection history and the state of popovers based on selection position aren't
 3754    /// erroneously updated.
 3755    pub fn with_selection_effects_deferred<R>(
 3756        &mut self,
 3757        window: &mut Window,
 3758        cx: &mut Context<Self>,
 3759        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3760    ) -> R {
 3761        let already_deferred = self.defer_selection_effects;
 3762        self.defer_selection_effects = true;
 3763        let result = update(self, window, cx);
 3764        if !already_deferred {
 3765            self.defer_selection_effects = false;
 3766            if let Some(state) = self.deferred_selection_effects_state.take() {
 3767                self.apply_selection_effects(state, window, cx);
 3768            }
 3769        }
 3770        result
 3771    }
 3772
 3773    fn apply_selection_effects(
 3774        &mut self,
 3775        state: DeferredSelectionEffectsState,
 3776        window: &mut Window,
 3777        cx: &mut Context<Self>,
 3778    ) {
 3779        if state.changed {
 3780            self.selection_history.push(state.history_entry);
 3781
 3782            if let Some(autoscroll) = state.effects.scroll {
 3783                self.request_autoscroll(autoscroll, cx);
 3784            }
 3785
 3786            let old_cursor_position = &state.old_cursor_position;
 3787
 3788            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3789
 3790            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3791                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3792            }
 3793        }
 3794    }
 3795
 3796    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3797    where
 3798        I: IntoIterator<Item = (Range<S>, T)>,
 3799        S: ToOffset,
 3800        T: Into<Arc<str>>,
 3801    {
 3802        if self.read_only(cx) {
 3803            return;
 3804        }
 3805
 3806        self.buffer
 3807            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3808    }
 3809
 3810    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3811    where
 3812        I: IntoIterator<Item = (Range<S>, T)>,
 3813        S: ToOffset,
 3814        T: Into<Arc<str>>,
 3815    {
 3816        if self.read_only(cx) {
 3817            return;
 3818        }
 3819
 3820        self.buffer.update(cx, |buffer, cx| {
 3821            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3822        });
 3823    }
 3824
 3825    pub fn edit_with_block_indent<I, S, T>(
 3826        &mut self,
 3827        edits: I,
 3828        original_indent_columns: Vec<Option<u32>>,
 3829        cx: &mut Context<Self>,
 3830    ) where
 3831        I: IntoIterator<Item = (Range<S>, T)>,
 3832        S: ToOffset,
 3833        T: Into<Arc<str>>,
 3834    {
 3835        if self.read_only(cx) {
 3836            return;
 3837        }
 3838
 3839        self.buffer.update(cx, |buffer, cx| {
 3840            buffer.edit(
 3841                edits,
 3842                Some(AutoindentMode::Block {
 3843                    original_indent_columns,
 3844                }),
 3845                cx,
 3846            )
 3847        });
 3848    }
 3849
 3850    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3851        self.hide_context_menu(window, cx);
 3852
 3853        match phase {
 3854            SelectPhase::Begin {
 3855                position,
 3856                add,
 3857                click_count,
 3858            } => self.begin_selection(position, add, click_count, window, cx),
 3859            SelectPhase::BeginColumnar {
 3860                position,
 3861                goal_column,
 3862                reset,
 3863                mode,
 3864            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3865            SelectPhase::Extend {
 3866                position,
 3867                click_count,
 3868            } => self.extend_selection(position, click_count, window, cx),
 3869            SelectPhase::Update {
 3870                position,
 3871                goal_column,
 3872                scroll_delta,
 3873            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3874            SelectPhase::End => self.end_selection(window, cx),
 3875        }
 3876    }
 3877
 3878    fn extend_selection(
 3879        &mut self,
 3880        position: DisplayPoint,
 3881        click_count: usize,
 3882        window: &mut Window,
 3883        cx: &mut Context<Self>,
 3884    ) {
 3885        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3886        let tail = self
 3887            .selections
 3888            .newest::<MultiBufferOffset>(&display_map)
 3889            .tail();
 3890        let click_count = click_count.max(match self.selections.select_mode() {
 3891            SelectMode::Character => 1,
 3892            SelectMode::Word(_) => 2,
 3893            SelectMode::Line(_) => 3,
 3894            SelectMode::All => 4,
 3895        });
 3896        self.begin_selection(position, false, click_count, window, cx);
 3897
 3898        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3899
 3900        let current_selection = match self.selections.select_mode() {
 3901            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3902            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3903        };
 3904
 3905        let mut pending_selection = self
 3906            .selections
 3907            .pending_anchor()
 3908            .cloned()
 3909            .expect("extend_selection not called with pending selection");
 3910
 3911        if pending_selection
 3912            .start
 3913            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3914            == Ordering::Greater
 3915        {
 3916            pending_selection.start = current_selection.start;
 3917        }
 3918        if pending_selection
 3919            .end
 3920            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3921            == Ordering::Less
 3922        {
 3923            pending_selection.end = current_selection.end;
 3924            pending_selection.reversed = true;
 3925        }
 3926
 3927        let mut pending_mode = self.selections.pending_mode().unwrap();
 3928        match &mut pending_mode {
 3929            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3930            _ => {}
 3931        }
 3932
 3933        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3934            SelectionEffects::scroll(Autoscroll::fit())
 3935        } else {
 3936            SelectionEffects::no_scroll()
 3937        };
 3938
 3939        self.change_selections(effects, window, cx, |s| {
 3940            s.set_pending(pending_selection.clone(), pending_mode);
 3941            s.set_is_extending(true);
 3942        });
 3943    }
 3944
 3945    fn begin_selection(
 3946        &mut self,
 3947        position: DisplayPoint,
 3948        add: bool,
 3949        click_count: usize,
 3950        window: &mut Window,
 3951        cx: &mut Context<Self>,
 3952    ) {
 3953        if !self.focus_handle.is_focused(window) {
 3954            self.last_focused_descendant = None;
 3955            window.focus(&self.focus_handle, cx);
 3956        }
 3957
 3958        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3959        let buffer = display_map.buffer_snapshot();
 3960        let position = display_map.clip_point(position, Bias::Left);
 3961
 3962        let start;
 3963        let end;
 3964        let mode;
 3965        let mut auto_scroll;
 3966        match click_count {
 3967            1 => {
 3968                start = buffer.anchor_before(position.to_point(&display_map));
 3969                end = start;
 3970                mode = SelectMode::Character;
 3971                auto_scroll = true;
 3972            }
 3973            2 => {
 3974                let position = display_map
 3975                    .clip_point(position, Bias::Left)
 3976                    .to_offset(&display_map, Bias::Left);
 3977                let (range, _) = buffer.surrounding_word(position, None);
 3978                start = buffer.anchor_before(range.start);
 3979                end = buffer.anchor_before(range.end);
 3980                mode = SelectMode::Word(start..end);
 3981                auto_scroll = true;
 3982            }
 3983            3 => {
 3984                let position = display_map
 3985                    .clip_point(position, Bias::Left)
 3986                    .to_point(&display_map);
 3987                let line_start = display_map.prev_line_boundary(position).0;
 3988                let next_line_start = buffer.clip_point(
 3989                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3990                    Bias::Left,
 3991                );
 3992                start = buffer.anchor_before(line_start);
 3993                end = buffer.anchor_before(next_line_start);
 3994                mode = SelectMode::Line(start..end);
 3995                auto_scroll = true;
 3996            }
 3997            _ => {
 3998                start = buffer.anchor_before(MultiBufferOffset(0));
 3999                end = buffer.anchor_before(buffer.len());
 4000                mode = SelectMode::All;
 4001                auto_scroll = false;
 4002            }
 4003        }
 4004        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4005
 4006        let point_to_delete: Option<usize> = {
 4007            let selected_points: Vec<Selection<Point>> =
 4008                self.selections.disjoint_in_range(start..end, &display_map);
 4009
 4010            if !add || click_count > 1 {
 4011                None
 4012            } else if !selected_points.is_empty() {
 4013                Some(selected_points[0].id)
 4014            } else {
 4015                let clicked_point_already_selected =
 4016                    self.selections.disjoint_anchors().iter().find(|selection| {
 4017                        selection.start.to_point(buffer) == start.to_point(buffer)
 4018                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4019                    });
 4020
 4021                clicked_point_already_selected.map(|selection| selection.id)
 4022            }
 4023        };
 4024
 4025        let selections_count = self.selections.count();
 4026        let effects = if auto_scroll {
 4027            SelectionEffects::default()
 4028        } else {
 4029            SelectionEffects::no_scroll()
 4030        };
 4031
 4032        self.change_selections(effects, window, cx, |s| {
 4033            if let Some(point_to_delete) = point_to_delete {
 4034                s.delete(point_to_delete);
 4035
 4036                if selections_count == 1 {
 4037                    s.set_pending_anchor_range(start..end, mode);
 4038                }
 4039            } else {
 4040                if !add {
 4041                    s.clear_disjoint();
 4042                }
 4043
 4044                s.set_pending_anchor_range(start..end, mode);
 4045            }
 4046        });
 4047    }
 4048
 4049    fn begin_columnar_selection(
 4050        &mut self,
 4051        position: DisplayPoint,
 4052        goal_column: u32,
 4053        reset: bool,
 4054        mode: ColumnarMode,
 4055        window: &mut Window,
 4056        cx: &mut Context<Self>,
 4057    ) {
 4058        if !self.focus_handle.is_focused(window) {
 4059            self.last_focused_descendant = None;
 4060            window.focus(&self.focus_handle, cx);
 4061        }
 4062
 4063        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4064
 4065        if reset {
 4066            let pointer_position = display_map
 4067                .buffer_snapshot()
 4068                .anchor_before(position.to_point(&display_map));
 4069
 4070            self.change_selections(
 4071                SelectionEffects::scroll(Autoscroll::newest()),
 4072                window,
 4073                cx,
 4074                |s| {
 4075                    s.clear_disjoint();
 4076                    s.set_pending_anchor_range(
 4077                        pointer_position..pointer_position,
 4078                        SelectMode::Character,
 4079                    );
 4080                },
 4081            );
 4082        };
 4083
 4084        let tail = self.selections.newest::<Point>(&display_map).tail();
 4085        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4086        self.columnar_selection_state = match mode {
 4087            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4088                selection_tail: selection_anchor,
 4089                display_point: if reset {
 4090                    if position.column() != goal_column {
 4091                        Some(DisplayPoint::new(position.row(), goal_column))
 4092                    } else {
 4093                        None
 4094                    }
 4095                } else {
 4096                    None
 4097                },
 4098            }),
 4099            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4100                selection_tail: selection_anchor,
 4101            }),
 4102        };
 4103
 4104        if !reset {
 4105            self.select_columns(position, goal_column, &display_map, window, cx);
 4106        }
 4107    }
 4108
 4109    fn update_selection(
 4110        &mut self,
 4111        position: DisplayPoint,
 4112        goal_column: u32,
 4113        scroll_delta: gpui::Point<f32>,
 4114        window: &mut Window,
 4115        cx: &mut Context<Self>,
 4116    ) {
 4117        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4118
 4119        if self.columnar_selection_state.is_some() {
 4120            self.select_columns(position, goal_column, &display_map, window, cx);
 4121        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4122            let buffer = display_map.buffer_snapshot();
 4123            let head;
 4124            let tail;
 4125            let mode = self.selections.pending_mode().unwrap();
 4126            match &mode {
 4127                SelectMode::Character => {
 4128                    head = position.to_point(&display_map);
 4129                    tail = pending.tail().to_point(buffer);
 4130                }
 4131                SelectMode::Word(original_range) => {
 4132                    let offset = display_map
 4133                        .clip_point(position, Bias::Left)
 4134                        .to_offset(&display_map, Bias::Left);
 4135                    let original_range = original_range.to_offset(buffer);
 4136
 4137                    let head_offset = if buffer.is_inside_word(offset, None)
 4138                        || original_range.contains(&offset)
 4139                    {
 4140                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4141                        if word_range.start < original_range.start {
 4142                            word_range.start
 4143                        } else {
 4144                            word_range.end
 4145                        }
 4146                    } else {
 4147                        offset
 4148                    };
 4149
 4150                    head = head_offset.to_point(buffer);
 4151                    if head_offset <= original_range.start {
 4152                        tail = original_range.end.to_point(buffer);
 4153                    } else {
 4154                        tail = original_range.start.to_point(buffer);
 4155                    }
 4156                }
 4157                SelectMode::Line(original_range) => {
 4158                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4159
 4160                    let position = display_map
 4161                        .clip_point(position, Bias::Left)
 4162                        .to_point(&display_map);
 4163                    let line_start = display_map.prev_line_boundary(position).0;
 4164                    let next_line_start = buffer.clip_point(
 4165                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4166                        Bias::Left,
 4167                    );
 4168
 4169                    if line_start < original_range.start {
 4170                        head = line_start
 4171                    } else {
 4172                        head = next_line_start
 4173                    }
 4174
 4175                    if head <= original_range.start {
 4176                        tail = original_range.end;
 4177                    } else {
 4178                        tail = original_range.start;
 4179                    }
 4180                }
 4181                SelectMode::All => {
 4182                    return;
 4183                }
 4184            };
 4185
 4186            if head < tail {
 4187                pending.start = buffer.anchor_before(head);
 4188                pending.end = buffer.anchor_before(tail);
 4189                pending.reversed = true;
 4190            } else {
 4191                pending.start = buffer.anchor_before(tail);
 4192                pending.end = buffer.anchor_before(head);
 4193                pending.reversed = false;
 4194            }
 4195
 4196            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4197                s.set_pending(pending.clone(), mode);
 4198            });
 4199        } else {
 4200            log::error!("update_selection dispatched with no pending selection");
 4201            return;
 4202        }
 4203
 4204        self.apply_scroll_delta(scroll_delta, window, cx);
 4205        cx.notify();
 4206    }
 4207
 4208    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4209        self.columnar_selection_state.take();
 4210        if let Some(pending_mode) = self.selections.pending_mode() {
 4211            let selections = self
 4212                .selections
 4213                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4214            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4215                s.select(selections);
 4216                s.clear_pending();
 4217                if s.is_extending() {
 4218                    s.set_is_extending(false);
 4219                } else {
 4220                    s.set_select_mode(pending_mode);
 4221                }
 4222            });
 4223        }
 4224    }
 4225
 4226    fn select_columns(
 4227        &mut self,
 4228        head: DisplayPoint,
 4229        goal_column: u32,
 4230        display_map: &DisplaySnapshot,
 4231        window: &mut Window,
 4232        cx: &mut Context<Self>,
 4233    ) {
 4234        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4235            return;
 4236        };
 4237
 4238        let tail = match columnar_state {
 4239            ColumnarSelectionState::FromMouse {
 4240                selection_tail,
 4241                display_point,
 4242            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4243            ColumnarSelectionState::FromSelection { selection_tail } => {
 4244                selection_tail.to_display_point(display_map)
 4245            }
 4246        };
 4247
 4248        let start_row = cmp::min(tail.row(), head.row());
 4249        let end_row = cmp::max(tail.row(), head.row());
 4250        let start_column = cmp::min(tail.column(), goal_column);
 4251        let end_column = cmp::max(tail.column(), goal_column);
 4252        let reversed = start_column < tail.column();
 4253
 4254        let selection_ranges = (start_row.0..=end_row.0)
 4255            .map(DisplayRow)
 4256            .filter_map(|row| {
 4257                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4258                    || start_column <= display_map.line_len(row))
 4259                    && !display_map.is_block_line(row)
 4260                {
 4261                    let start = display_map
 4262                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4263                        .to_point(display_map);
 4264                    let end = display_map
 4265                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4266                        .to_point(display_map);
 4267                    if reversed {
 4268                        Some(end..start)
 4269                    } else {
 4270                        Some(start..end)
 4271                    }
 4272                } else {
 4273                    None
 4274                }
 4275            })
 4276            .collect::<Vec<_>>();
 4277        if selection_ranges.is_empty() {
 4278            return;
 4279        }
 4280
 4281        let ranges = match columnar_state {
 4282            ColumnarSelectionState::FromMouse { .. } => {
 4283                let mut non_empty_ranges = selection_ranges
 4284                    .iter()
 4285                    .filter(|selection_range| selection_range.start != selection_range.end)
 4286                    .peekable();
 4287                if non_empty_ranges.peek().is_some() {
 4288                    non_empty_ranges.cloned().collect()
 4289                } else {
 4290                    selection_ranges
 4291                }
 4292            }
 4293            _ => selection_ranges,
 4294        };
 4295
 4296        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4297            s.select_ranges(ranges);
 4298        });
 4299        cx.notify();
 4300    }
 4301
 4302    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4303        self.selections
 4304            .all_adjusted(snapshot)
 4305            .iter()
 4306            .any(|selection| !selection.is_empty())
 4307    }
 4308
 4309    pub fn has_pending_nonempty_selection(&self) -> bool {
 4310        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4311            Some(Selection { start, end, .. }) => start != end,
 4312            None => false,
 4313        };
 4314
 4315        pending_nonempty_selection
 4316            || (self.columnar_selection_state.is_some()
 4317                && self.selections.disjoint_anchors().len() > 1)
 4318    }
 4319
 4320    pub fn has_pending_selection(&self) -> bool {
 4321        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4322    }
 4323
 4324    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4325        self.selection_mark_mode = false;
 4326        self.selection_drag_state = SelectionDragState::None;
 4327
 4328        if self.dismiss_menus_and_popups(true, window, cx) {
 4329            cx.notify();
 4330            return;
 4331        }
 4332        if self.clear_expanded_diff_hunks(cx) {
 4333            cx.notify();
 4334            return;
 4335        }
 4336        if self.show_git_blame_gutter {
 4337            self.show_git_blame_gutter = false;
 4338            cx.notify();
 4339            return;
 4340        }
 4341
 4342        if self.mode.is_full()
 4343            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4344        {
 4345            cx.notify();
 4346            return;
 4347        }
 4348
 4349        cx.propagate();
 4350    }
 4351
 4352    pub fn dismiss_menus_and_popups(
 4353        &mut self,
 4354        is_user_requested: bool,
 4355        window: &mut Window,
 4356        cx: &mut Context<Self>,
 4357    ) -> bool {
 4358        let mut dismissed = false;
 4359
 4360        dismissed |= self.take_rename(false, window, cx).is_some();
 4361        dismissed |= self.hide_blame_popover(true, cx);
 4362        dismissed |= hide_hover(self, cx);
 4363        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4364        dismissed |= self.hide_context_menu(window, cx).is_some();
 4365        dismissed |= self.mouse_context_menu.take().is_some();
 4366        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4367        dismissed |= self.snippet_stack.pop().is_some();
 4368        if !self.diff_review_overlays.is_empty() {
 4369            self.dismiss_all_diff_review_overlays(cx);
 4370            dismissed = true;
 4371        }
 4372
 4373        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4374            self.dismiss_diagnostics(cx);
 4375            dismissed = true;
 4376        }
 4377
 4378        dismissed
 4379    }
 4380
 4381    fn linked_editing_ranges_for(
 4382        &self,
 4383        selection: Range<text::Anchor>,
 4384        cx: &App,
 4385    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4386        if self.linked_edit_ranges.is_empty() {
 4387            return None;
 4388        }
 4389        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4390            selection.end.buffer_id.and_then(|end_buffer_id| {
 4391                if selection.start.buffer_id != Some(end_buffer_id) {
 4392                    return None;
 4393                }
 4394                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4395                let snapshot = buffer.read(cx).snapshot();
 4396                self.linked_edit_ranges
 4397                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4398                    .map(|ranges| (ranges, snapshot, buffer))
 4399            })?;
 4400        use text::ToOffset as TO;
 4401        // find offset from the start of current range to current cursor position
 4402        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4403
 4404        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4405        let start_difference = start_offset - start_byte_offset;
 4406        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4407        let end_difference = end_offset - start_byte_offset;
 4408        // Current range has associated linked ranges.
 4409        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4410        for range in linked_ranges.iter() {
 4411            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4412            let end_offset = start_offset + end_difference;
 4413            let start_offset = start_offset + start_difference;
 4414            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4415                continue;
 4416            }
 4417            if self.selections.disjoint_anchor_ranges().any(|s| {
 4418                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4419                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4420                {
 4421                    return false;
 4422                }
 4423                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4424                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4425            }) {
 4426                continue;
 4427            }
 4428            let start = buffer_snapshot.anchor_after(start_offset);
 4429            let end = buffer_snapshot.anchor_after(end_offset);
 4430            linked_edits
 4431                .entry(buffer.clone())
 4432                .or_default()
 4433                .push(start..end);
 4434        }
 4435        Some(linked_edits)
 4436    }
 4437
 4438    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4439        let text: Arc<str> = text.into();
 4440
 4441        if self.read_only(cx) {
 4442            return;
 4443        }
 4444
 4445        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4446
 4447        self.unfold_buffers_with_selections(cx);
 4448
 4449        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4450        let mut bracket_inserted = false;
 4451        let mut edits = Vec::new();
 4452        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4453        let mut new_selections = Vec::with_capacity(selections.len());
 4454        let mut new_autoclose_regions = Vec::new();
 4455        let snapshot = self.buffer.read(cx).read(cx);
 4456        let mut clear_linked_edit_ranges = false;
 4457        let mut all_selections_read_only = true;
 4458        let mut has_adjacent_edits = false;
 4459        let mut in_adjacent_group = false;
 4460
 4461        let mut regions = self
 4462            .selections_with_autoclose_regions(selections, &snapshot)
 4463            .peekable();
 4464
 4465        while let Some((selection, autoclose_region)) = regions.next() {
 4466            if snapshot
 4467                .point_to_buffer_point(selection.head())
 4468                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4469            {
 4470                continue;
 4471            }
 4472            if snapshot
 4473                .point_to_buffer_point(selection.tail())
 4474                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4475            {
 4476                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4477                continue;
 4478            }
 4479            all_selections_read_only = false;
 4480
 4481            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4482                // Determine if the inserted text matches the opening or closing
 4483                // bracket of any of this language's bracket pairs.
 4484                let mut bracket_pair = None;
 4485                let mut is_bracket_pair_start = false;
 4486                let mut is_bracket_pair_end = false;
 4487                if !text.is_empty() {
 4488                    let mut bracket_pair_matching_end = None;
 4489                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4490                    //  and they are removing the character that triggered IME popup.
 4491                    for (pair, enabled) in scope.brackets() {
 4492                        if !pair.close && !pair.surround {
 4493                            continue;
 4494                        }
 4495
 4496                        if enabled && pair.start.ends_with(text.as_ref()) {
 4497                            let prefix_len = pair.start.len() - text.len();
 4498                            let preceding_text_matches_prefix = prefix_len == 0
 4499                                || (selection.start.column >= (prefix_len as u32)
 4500                                    && snapshot.contains_str_at(
 4501                                        Point::new(
 4502                                            selection.start.row,
 4503                                            selection.start.column - (prefix_len as u32),
 4504                                        ),
 4505                                        &pair.start[..prefix_len],
 4506                                    ));
 4507                            if preceding_text_matches_prefix {
 4508                                bracket_pair = Some(pair.clone());
 4509                                is_bracket_pair_start = true;
 4510                                break;
 4511                            }
 4512                        }
 4513                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4514                        {
 4515                            // take first bracket pair matching end, but don't break in case a later bracket
 4516                            // pair matches start
 4517                            bracket_pair_matching_end = Some(pair.clone());
 4518                        }
 4519                    }
 4520                    if let Some(end) = bracket_pair_matching_end
 4521                        && bracket_pair.is_none()
 4522                    {
 4523                        bracket_pair = Some(end);
 4524                        is_bracket_pair_end = true;
 4525                    }
 4526                }
 4527
 4528                if let Some(bracket_pair) = bracket_pair {
 4529                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4530                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4531                    let auto_surround =
 4532                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4533                    if selection.is_empty() {
 4534                        if is_bracket_pair_start {
 4535                            // If the inserted text is a suffix of an opening bracket and the
 4536                            // selection is preceded by the rest of the opening bracket, then
 4537                            // insert the closing bracket.
 4538                            let following_text_allows_autoclose = snapshot
 4539                                .chars_at(selection.start)
 4540                                .next()
 4541                                .is_none_or(|c| scope.should_autoclose_before(c));
 4542
 4543                            let preceding_text_allows_autoclose = selection.start.column == 0
 4544                                || snapshot
 4545                                    .reversed_chars_at(selection.start)
 4546                                    .next()
 4547                                    .is_none_or(|c| {
 4548                                        bracket_pair.start != bracket_pair.end
 4549                                            || !snapshot
 4550                                                .char_classifier_at(selection.start)
 4551                                                .is_word(c)
 4552                                    });
 4553
 4554                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4555                                && bracket_pair.start.len() == 1
 4556                            {
 4557                                let target = bracket_pair.start.chars().next().unwrap();
 4558                                let mut byte_offset = 0u32;
 4559                                let current_line_count = snapshot
 4560                                    .reversed_chars_at(selection.start)
 4561                                    .take_while(|&c| c != '\n')
 4562                                    .filter(|c| {
 4563                                        byte_offset += c.len_utf8() as u32;
 4564                                        if *c != target {
 4565                                            return false;
 4566                                        }
 4567
 4568                                        let point = Point::new(
 4569                                            selection.start.row,
 4570                                            selection.start.column.saturating_sub(byte_offset),
 4571                                        );
 4572
 4573                                        let is_enabled = snapshot
 4574                                            .language_scope_at(point)
 4575                                            .and_then(|scope| {
 4576                                                scope
 4577                                                    .brackets()
 4578                                                    .find(|(pair, _)| {
 4579                                                        pair.start == bracket_pair.start
 4580                                                    })
 4581                                                    .map(|(_, enabled)| enabled)
 4582                                            })
 4583                                            .unwrap_or(true);
 4584
 4585                                        let is_delimiter = snapshot
 4586                                            .language_scope_at(Point::new(
 4587                                                point.row,
 4588                                                point.column + 1,
 4589                                            ))
 4590                                            .and_then(|scope| {
 4591                                                scope
 4592                                                    .brackets()
 4593                                                    .find(|(pair, _)| {
 4594                                                        pair.start == bracket_pair.start
 4595                                                    })
 4596                                                    .map(|(_, enabled)| !enabled)
 4597                                            })
 4598                                            .unwrap_or(false);
 4599
 4600                                        is_enabled && !is_delimiter
 4601                                    })
 4602                                    .count();
 4603                                current_line_count % 2 == 1
 4604                            } else {
 4605                                false
 4606                            };
 4607
 4608                            if autoclose
 4609                                && bracket_pair.close
 4610                                && following_text_allows_autoclose
 4611                                && preceding_text_allows_autoclose
 4612                                && !is_closing_quote
 4613                            {
 4614                                let anchor = snapshot.anchor_before(selection.end);
 4615                                new_selections.push((selection.map(|_| anchor), text.len()));
 4616                                new_autoclose_regions.push((
 4617                                    anchor,
 4618                                    text.len(),
 4619                                    selection.id,
 4620                                    bracket_pair.clone(),
 4621                                ));
 4622                                edits.push((
 4623                                    selection.range(),
 4624                                    format!("{}{}", text, bracket_pair.end).into(),
 4625                                ));
 4626                                bracket_inserted = true;
 4627                                continue;
 4628                            }
 4629                        }
 4630
 4631                        if let Some(region) = autoclose_region {
 4632                            // If the selection is followed by an auto-inserted closing bracket,
 4633                            // then don't insert that closing bracket again; just move the selection
 4634                            // past the closing bracket.
 4635                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4636                                && text.as_ref() == region.pair.end.as_str()
 4637                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4638                            if should_skip {
 4639                                let anchor = snapshot.anchor_after(selection.end);
 4640                                new_selections
 4641                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4642                                continue;
 4643                            }
 4644                        }
 4645
 4646                        let always_treat_brackets_as_autoclosed = snapshot
 4647                            .language_settings_at(selection.start, cx)
 4648                            .always_treat_brackets_as_autoclosed;
 4649                        if always_treat_brackets_as_autoclosed
 4650                            && is_bracket_pair_end
 4651                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4652                        {
 4653                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4654                            // and the inserted text is a closing bracket and the selection is followed
 4655                            // by the closing bracket then move the selection past the closing bracket.
 4656                            let anchor = snapshot.anchor_after(selection.end);
 4657                            new_selections.push((selection.map(|_| anchor), text.len()));
 4658                            continue;
 4659                        }
 4660                    }
 4661                    // If an opening bracket is 1 character long and is typed while
 4662                    // text is selected, then surround that text with the bracket pair.
 4663                    else if auto_surround
 4664                        && bracket_pair.surround
 4665                        && is_bracket_pair_start
 4666                        && bracket_pair.start.chars().count() == 1
 4667                    {
 4668                        edits.push((selection.start..selection.start, text.clone()));
 4669                        edits.push((
 4670                            selection.end..selection.end,
 4671                            bracket_pair.end.as_str().into(),
 4672                        ));
 4673                        bracket_inserted = true;
 4674                        new_selections.push((
 4675                            Selection {
 4676                                id: selection.id,
 4677                                start: snapshot.anchor_after(selection.start),
 4678                                end: snapshot.anchor_before(selection.end),
 4679                                reversed: selection.reversed,
 4680                                goal: selection.goal,
 4681                            },
 4682                            0,
 4683                        ));
 4684                        continue;
 4685                    }
 4686                }
 4687            }
 4688
 4689            if self.auto_replace_emoji_shortcode
 4690                && selection.is_empty()
 4691                && text.as_ref().ends_with(':')
 4692                && let Some(possible_emoji_short_code) =
 4693                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4694                && !possible_emoji_short_code.is_empty()
 4695                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4696            {
 4697                let emoji_shortcode_start = Point::new(
 4698                    selection.start.row,
 4699                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4700                );
 4701
 4702                // Remove shortcode from buffer
 4703                edits.push((
 4704                    emoji_shortcode_start..selection.start,
 4705                    "".to_string().into(),
 4706                ));
 4707                new_selections.push((
 4708                    Selection {
 4709                        id: selection.id,
 4710                        start: snapshot.anchor_after(emoji_shortcode_start),
 4711                        end: snapshot.anchor_before(selection.start),
 4712                        reversed: selection.reversed,
 4713                        goal: selection.goal,
 4714                    },
 4715                    0,
 4716                ));
 4717
 4718                // Insert emoji
 4719                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4720                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4721                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4722
 4723                continue;
 4724            }
 4725
 4726            let next_is_adjacent = regions
 4727                .peek()
 4728                .is_some_and(|(next, _)| selection.end == next.start);
 4729
 4730            // If not handling any auto-close operation, then just replace the selected
 4731            // text with the given input and move the selection to the end of the
 4732            // newly inserted text.
 4733            let anchor = if in_adjacent_group || next_is_adjacent {
 4734                // After edits the right bias would shift those anchor to the next visible fragment
 4735                // but we want to resolve to the previous one
 4736                snapshot.anchor_before(selection.end)
 4737            } else {
 4738                snapshot.anchor_after(selection.end)
 4739            };
 4740
 4741            if !self.linked_edit_ranges.is_empty() {
 4742                let start_anchor = snapshot.anchor_before(selection.start);
 4743
 4744                let is_word_char = text.chars().next().is_none_or(|char| {
 4745                    let classifier = snapshot
 4746                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4747                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4748                    classifier.is_word(char)
 4749                });
 4750
 4751                if is_word_char {
 4752                    if let Some(ranges) = self
 4753                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4754                    {
 4755                        for (buffer, edits) in ranges {
 4756                            linked_edits
 4757                                .entry(buffer.clone())
 4758                                .or_default()
 4759                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4760                        }
 4761                    }
 4762                } else {
 4763                    clear_linked_edit_ranges = true;
 4764                }
 4765            }
 4766
 4767            new_selections.push((selection.map(|_| anchor), 0));
 4768            edits.push((selection.start..selection.end, text.clone()));
 4769
 4770            has_adjacent_edits |= next_is_adjacent;
 4771            in_adjacent_group = next_is_adjacent;
 4772        }
 4773
 4774        if all_selections_read_only {
 4775            return;
 4776        }
 4777
 4778        drop(regions);
 4779        drop(snapshot);
 4780
 4781        self.transact(window, cx, |this, window, cx| {
 4782            if clear_linked_edit_ranges {
 4783                this.linked_edit_ranges.clear();
 4784            }
 4785            let initial_buffer_versions =
 4786                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4787
 4788            this.buffer.update(cx, |buffer, cx| {
 4789                if has_adjacent_edits {
 4790                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4791                } else {
 4792                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4793                }
 4794            });
 4795            for (buffer, edits) in linked_edits {
 4796                buffer.update(cx, |buffer, cx| {
 4797                    let snapshot = buffer.snapshot();
 4798                    let edits = edits
 4799                        .into_iter()
 4800                        .map(|(range, text)| {
 4801                            use text::ToPoint as TP;
 4802                            let end_point = TP::to_point(&range.end, &snapshot);
 4803                            let start_point = TP::to_point(&range.start, &snapshot);
 4804                            (start_point..end_point, text)
 4805                        })
 4806                        .sorted_by_key(|(range, _)| range.start);
 4807                    buffer.edit(edits, None, cx);
 4808                })
 4809            }
 4810            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4811            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4812            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4813            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4814                new_anchor_selections,
 4815                &map,
 4816            )
 4817            .zip(new_selection_deltas)
 4818            .map(|(selection, delta)| Selection {
 4819                id: selection.id,
 4820                start: selection.start + delta,
 4821                end: selection.end + delta,
 4822                reversed: selection.reversed,
 4823                goal: SelectionGoal::None,
 4824            })
 4825            .collect::<Vec<_>>();
 4826
 4827            let mut i = 0;
 4828            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4829                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4830                let start = map.buffer_snapshot().anchor_before(position);
 4831                let end = map.buffer_snapshot().anchor_after(position);
 4832                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4833                    match existing_state
 4834                        .range
 4835                        .start
 4836                        .cmp(&start, map.buffer_snapshot())
 4837                    {
 4838                        Ordering::Less => i += 1,
 4839                        Ordering::Greater => break,
 4840                        Ordering::Equal => {
 4841                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4842                                Ordering::Less => i += 1,
 4843                                Ordering::Equal => break,
 4844                                Ordering::Greater => break,
 4845                            }
 4846                        }
 4847                    }
 4848                }
 4849                this.autoclose_regions.insert(
 4850                    i,
 4851                    AutocloseRegion {
 4852                        selection_id,
 4853                        range: start..end,
 4854                        pair,
 4855                    },
 4856                );
 4857            }
 4858
 4859            let had_active_edit_prediction = this.has_active_edit_prediction();
 4860            this.change_selections(
 4861                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4862                window,
 4863                cx,
 4864                |s| s.select(new_selections),
 4865            );
 4866
 4867            if !bracket_inserted
 4868                && let Some(on_type_format_task) =
 4869                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4870            {
 4871                on_type_format_task.detach_and_log_err(cx);
 4872            }
 4873
 4874            let editor_settings = EditorSettings::get_global(cx);
 4875            if bracket_inserted
 4876                && (editor_settings.auto_signature_help
 4877                    || editor_settings.show_signature_help_after_edits)
 4878            {
 4879                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4880            }
 4881
 4882            let trigger_in_words =
 4883                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4884            if this.hard_wrap.is_some() {
 4885                let latest: Range<Point> = this.selections.newest(&map).range();
 4886                if latest.is_empty()
 4887                    && this
 4888                        .buffer()
 4889                        .read(cx)
 4890                        .snapshot(cx)
 4891                        .line_len(MultiBufferRow(latest.start.row))
 4892                        == latest.start.column
 4893                {
 4894                    this.rewrap_impl(
 4895                        RewrapOptions {
 4896                            override_language_settings: true,
 4897                            preserve_existing_whitespace: true,
 4898                        },
 4899                        cx,
 4900                    )
 4901                }
 4902            }
 4903            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4904            refresh_linked_ranges(this, window, cx);
 4905            this.refresh_edit_prediction(true, false, window, cx);
 4906            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4907        });
 4908    }
 4909
 4910    fn find_possible_emoji_shortcode_at_position(
 4911        snapshot: &MultiBufferSnapshot,
 4912        position: Point,
 4913    ) -> Option<String> {
 4914        let mut chars = Vec::new();
 4915        let mut found_colon = false;
 4916        for char in snapshot.reversed_chars_at(position).take(100) {
 4917            // Found a possible emoji shortcode in the middle of the buffer
 4918            if found_colon {
 4919                if char.is_whitespace() {
 4920                    chars.reverse();
 4921                    return Some(chars.iter().collect());
 4922                }
 4923                // If the previous character is not a whitespace, we are in the middle of a word
 4924                // and we only want to complete the shortcode if the word is made up of other emojis
 4925                let mut containing_word = String::new();
 4926                for ch in snapshot
 4927                    .reversed_chars_at(position)
 4928                    .skip(chars.len() + 1)
 4929                    .take(100)
 4930                {
 4931                    if ch.is_whitespace() {
 4932                        break;
 4933                    }
 4934                    containing_word.push(ch);
 4935                }
 4936                let containing_word = containing_word.chars().rev().collect::<String>();
 4937                if util::word_consists_of_emojis(containing_word.as_str()) {
 4938                    chars.reverse();
 4939                    return Some(chars.iter().collect());
 4940                }
 4941            }
 4942
 4943            if char.is_whitespace() || !char.is_ascii() {
 4944                return None;
 4945            }
 4946            if char == ':' {
 4947                found_colon = true;
 4948            } else {
 4949                chars.push(char);
 4950            }
 4951        }
 4952        // Found a possible emoji shortcode at the beginning of the buffer
 4953        chars.reverse();
 4954        Some(chars.iter().collect())
 4955    }
 4956
 4957    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4958        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4959        self.transact(window, cx, |this, window, cx| {
 4960            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4961                let selections = this
 4962                    .selections
 4963                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4964                let multi_buffer = this.buffer.read(cx);
 4965                let buffer = multi_buffer.snapshot(cx);
 4966                selections
 4967                    .iter()
 4968                    .map(|selection| {
 4969                        let start_point = selection.start.to_point(&buffer);
 4970                        let mut existing_indent =
 4971                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4972                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4973                        let start = selection.start;
 4974                        let end = selection.end;
 4975                        let selection_is_empty = start == end;
 4976                        let language_scope = buffer.language_scope_at(start);
 4977                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4978                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4979                                &buffer,
 4980                                start..end,
 4981                                language,
 4982                            )
 4983                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4984                                    &buffer,
 4985                                    start..end,
 4986                                );
 4987
 4988                            let mut newline_config = NewlineConfig::Newline {
 4989                                additional_indent: IndentSize::spaces(0),
 4990                                extra_line_additional_indent: if needs_extra_newline {
 4991                                    Some(IndentSize::spaces(0))
 4992                                } else {
 4993                                    None
 4994                                },
 4995                                prevent_auto_indent: false,
 4996                            };
 4997
 4998                            let comment_delimiter = maybe!({
 4999                                if !selection_is_empty {
 5000                                    return None;
 5001                                }
 5002
 5003                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5004                                    return None;
 5005                                }
 5006
 5007                                return comment_delimiter_for_newline(
 5008                                    &start_point,
 5009                                    &buffer,
 5010                                    language,
 5011                                );
 5012                            });
 5013
 5014                            let doc_delimiter = maybe!({
 5015                                if !selection_is_empty {
 5016                                    return None;
 5017                                }
 5018
 5019                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5020                                    return None;
 5021                                }
 5022
 5023                                return documentation_delimiter_for_newline(
 5024                                    &start_point,
 5025                                    &buffer,
 5026                                    language,
 5027                                    &mut newline_config,
 5028                                );
 5029                            });
 5030
 5031                            let list_delimiter = maybe!({
 5032                                if !selection_is_empty {
 5033                                    return None;
 5034                                }
 5035
 5036                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5037                                    return None;
 5038                                }
 5039
 5040                                return list_delimiter_for_newline(
 5041                                    &start_point,
 5042                                    &buffer,
 5043                                    language,
 5044                                    &mut newline_config,
 5045                                );
 5046                            });
 5047
 5048                            (
 5049                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5050                                newline_config,
 5051                            )
 5052                        } else {
 5053                            (
 5054                                None,
 5055                                NewlineConfig::Newline {
 5056                                    additional_indent: IndentSize::spaces(0),
 5057                                    extra_line_additional_indent: None,
 5058                                    prevent_auto_indent: false,
 5059                                },
 5060                            )
 5061                        };
 5062
 5063                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5064                            NewlineConfig::ClearCurrentLine => {
 5065                                let row_start =
 5066                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5067                                (row_start, String::new(), false)
 5068                            }
 5069                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5070                                let row_start =
 5071                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5072                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5073                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5074                                let reduced_indent =
 5075                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5076                                let mut new_text = String::new();
 5077                                new_text.extend(reduced_indent.chars());
 5078                                new_text.push_str(continuation);
 5079                                (row_start, new_text, true)
 5080                            }
 5081                            NewlineConfig::Newline {
 5082                                additional_indent,
 5083                                extra_line_additional_indent,
 5084                                prevent_auto_indent,
 5085                            } => {
 5086                                let capacity_for_delimiter =
 5087                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5088                                let extra_line_len = extra_line_additional_indent
 5089                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 5090                                    .unwrap_or(0);
 5091                                let mut new_text = String::with_capacity(
 5092                                    1 + capacity_for_delimiter
 5093                                        + existing_indent.len as usize
 5094                                        + additional_indent.len as usize
 5095                                        + extra_line_len,
 5096                                );
 5097                                new_text.push('\n');
 5098                                new_text.extend(existing_indent.chars());
 5099                                new_text.extend(additional_indent.chars());
 5100                                if let Some(delimiter) = &delimiter {
 5101                                    new_text.push_str(delimiter);
 5102                                }
 5103                                if let Some(extra_indent) = extra_line_additional_indent {
 5104                                    new_text.push('\n');
 5105                                    new_text.extend(existing_indent.chars());
 5106                                    new_text.extend(extra_indent.chars());
 5107                                }
 5108                                (start, new_text, *prevent_auto_indent)
 5109                            }
 5110                        };
 5111
 5112                        let anchor = buffer.anchor_after(end);
 5113                        let new_selection = selection.map(|_| anchor);
 5114                        (
 5115                            ((edit_start..end, new_text), prevent_auto_indent),
 5116                            (newline_config.has_extra_line(), new_selection),
 5117                        )
 5118                    })
 5119                    .unzip()
 5120            };
 5121
 5122            let mut auto_indent_edits = Vec::new();
 5123            let mut edits = Vec::new();
 5124            for (edit, prevent_auto_indent) in edits_with_flags {
 5125                if prevent_auto_indent {
 5126                    edits.push(edit);
 5127                } else {
 5128                    auto_indent_edits.push(edit);
 5129                }
 5130            }
 5131            if !edits.is_empty() {
 5132                this.edit(edits, cx);
 5133            }
 5134            if !auto_indent_edits.is_empty() {
 5135                this.edit_with_autoindent(auto_indent_edits, cx);
 5136            }
 5137
 5138            let buffer = this.buffer.read(cx).snapshot(cx);
 5139            let new_selections = selection_info
 5140                .into_iter()
 5141                .map(|(extra_newline_inserted, new_selection)| {
 5142                    let mut cursor = new_selection.end.to_point(&buffer);
 5143                    if extra_newline_inserted {
 5144                        cursor.row -= 1;
 5145                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5146                    }
 5147                    new_selection.map(|_| cursor)
 5148                })
 5149                .collect();
 5150
 5151            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5152            this.refresh_edit_prediction(true, false, window, cx);
 5153            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5154                task.detach_and_log_err(cx);
 5155            }
 5156        });
 5157    }
 5158
 5159    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5160        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5161
 5162        let buffer = self.buffer.read(cx);
 5163        let snapshot = buffer.snapshot(cx);
 5164
 5165        let mut edits = Vec::new();
 5166        let mut rows = Vec::new();
 5167
 5168        for (rows_inserted, selection) in self
 5169            .selections
 5170            .all_adjusted(&self.display_snapshot(cx))
 5171            .into_iter()
 5172            .enumerate()
 5173        {
 5174            let cursor = selection.head();
 5175            let row = cursor.row;
 5176
 5177            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5178
 5179            let newline = "\n".to_string();
 5180            edits.push((start_of_line..start_of_line, newline));
 5181
 5182            rows.push(row + rows_inserted as u32);
 5183        }
 5184
 5185        self.transact(window, cx, |editor, window, cx| {
 5186            editor.edit(edits, cx);
 5187
 5188            editor.change_selections(Default::default(), window, cx, |s| {
 5189                let mut index = 0;
 5190                s.move_cursors_with(|map, _, _| {
 5191                    let row = rows[index];
 5192                    index += 1;
 5193
 5194                    let point = Point::new(row, 0);
 5195                    let boundary = map.next_line_boundary(point).1;
 5196                    let clipped = map.clip_point(boundary, Bias::Left);
 5197
 5198                    (clipped, SelectionGoal::None)
 5199                });
 5200            });
 5201
 5202            let mut indent_edits = Vec::new();
 5203            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5204            for row in rows {
 5205                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5206                for (row, indent) in indents {
 5207                    if indent.len == 0 {
 5208                        continue;
 5209                    }
 5210
 5211                    let text = match indent.kind {
 5212                        IndentKind::Space => " ".repeat(indent.len as usize),
 5213                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5214                    };
 5215                    let point = Point::new(row.0, 0);
 5216                    indent_edits.push((point..point, text));
 5217                }
 5218            }
 5219            editor.edit(indent_edits, cx);
 5220            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5221                format.detach_and_log_err(cx);
 5222            }
 5223        });
 5224    }
 5225
 5226    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5228
 5229        let buffer = self.buffer.read(cx);
 5230        let snapshot = buffer.snapshot(cx);
 5231
 5232        let mut edits = Vec::new();
 5233        let mut rows = Vec::new();
 5234        let mut rows_inserted = 0;
 5235
 5236        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5237            let cursor = selection.head();
 5238            let row = cursor.row;
 5239
 5240            let point = Point::new(row + 1, 0);
 5241            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5242
 5243            let newline = "\n".to_string();
 5244            edits.push((start_of_line..start_of_line, newline));
 5245
 5246            rows_inserted += 1;
 5247            rows.push(row + rows_inserted);
 5248        }
 5249
 5250        self.transact(window, cx, |editor, window, cx| {
 5251            editor.edit(edits, cx);
 5252
 5253            editor.change_selections(Default::default(), window, cx, |s| {
 5254                let mut index = 0;
 5255                s.move_cursors_with(|map, _, _| {
 5256                    let row = rows[index];
 5257                    index += 1;
 5258
 5259                    let point = Point::new(row, 0);
 5260                    let boundary = map.next_line_boundary(point).1;
 5261                    let clipped = map.clip_point(boundary, Bias::Left);
 5262
 5263                    (clipped, SelectionGoal::None)
 5264                });
 5265            });
 5266
 5267            let mut indent_edits = Vec::new();
 5268            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5269            for row in rows {
 5270                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5271                for (row, indent) in indents {
 5272                    if indent.len == 0 {
 5273                        continue;
 5274                    }
 5275
 5276                    let text = match indent.kind {
 5277                        IndentKind::Space => " ".repeat(indent.len as usize),
 5278                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5279                    };
 5280                    let point = Point::new(row.0, 0);
 5281                    indent_edits.push((point..point, text));
 5282                }
 5283            }
 5284            editor.edit(indent_edits, cx);
 5285            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5286                format.detach_and_log_err(cx);
 5287            }
 5288        });
 5289    }
 5290
 5291    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5292        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5293            original_indent_columns: Vec::new(),
 5294        });
 5295        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5296    }
 5297
 5298    fn insert_with_autoindent_mode(
 5299        &mut self,
 5300        text: &str,
 5301        autoindent_mode: Option<AutoindentMode>,
 5302        window: &mut Window,
 5303        cx: &mut Context<Self>,
 5304    ) {
 5305        if self.read_only(cx) {
 5306            return;
 5307        }
 5308
 5309        let text: Arc<str> = text.into();
 5310        self.transact(window, cx, |this, window, cx| {
 5311            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5312            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5313                let anchors = {
 5314                    let snapshot = buffer.read(cx);
 5315                    old_selections
 5316                        .iter()
 5317                        .map(|s| {
 5318                            let anchor = snapshot.anchor_after(s.head());
 5319                            s.map(|_| anchor)
 5320                        })
 5321                        .collect::<Vec<_>>()
 5322                };
 5323                buffer.edit(
 5324                    old_selections
 5325                        .iter()
 5326                        .map(|s| (s.start..s.end, text.clone())),
 5327                    autoindent_mode,
 5328                    cx,
 5329                );
 5330                anchors
 5331            });
 5332
 5333            this.change_selections(Default::default(), window, cx, |s| {
 5334                s.select_anchors(selection_anchors);
 5335            });
 5336
 5337            cx.notify();
 5338        });
 5339    }
 5340
 5341    fn trigger_completion_on_input(
 5342        &mut self,
 5343        text: &str,
 5344        trigger_in_words: bool,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) {
 5348        let completions_source = self
 5349            .context_menu
 5350            .borrow()
 5351            .as_ref()
 5352            .and_then(|menu| match menu {
 5353                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5354                CodeContextMenu::CodeActions(_) => None,
 5355            });
 5356
 5357        match completions_source {
 5358            Some(CompletionsMenuSource::Words { .. }) => {
 5359                self.open_or_update_completions_menu(
 5360                    Some(CompletionsMenuSource::Words {
 5361                        ignore_threshold: false,
 5362                    }),
 5363                    None,
 5364                    trigger_in_words,
 5365                    window,
 5366                    cx,
 5367                );
 5368            }
 5369            _ => self.open_or_update_completions_menu(
 5370                None,
 5371                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5372                true,
 5373                window,
 5374                cx,
 5375            ),
 5376        }
 5377    }
 5378
 5379    /// If any empty selections is touching the start of its innermost containing autoclose
 5380    /// region, expand it to select the brackets.
 5381    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5382        let selections = self
 5383            .selections
 5384            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5385        let buffer = self.buffer.read(cx).read(cx);
 5386        let new_selections = self
 5387            .selections_with_autoclose_regions(selections, &buffer)
 5388            .map(|(mut selection, region)| {
 5389                if !selection.is_empty() {
 5390                    return selection;
 5391                }
 5392
 5393                if let Some(region) = region {
 5394                    let mut range = region.range.to_offset(&buffer);
 5395                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5396                        range.start -= region.pair.start.len();
 5397                        if buffer.contains_str_at(range.start, &region.pair.start)
 5398                            && buffer.contains_str_at(range.end, &region.pair.end)
 5399                        {
 5400                            range.end += region.pair.end.len();
 5401                            selection.start = range.start;
 5402                            selection.end = range.end;
 5403
 5404                            return selection;
 5405                        }
 5406                    }
 5407                }
 5408
 5409                let always_treat_brackets_as_autoclosed = buffer
 5410                    .language_settings_at(selection.start, cx)
 5411                    .always_treat_brackets_as_autoclosed;
 5412
 5413                if !always_treat_brackets_as_autoclosed {
 5414                    return selection;
 5415                }
 5416
 5417                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5418                    for (pair, enabled) in scope.brackets() {
 5419                        if !enabled || !pair.close {
 5420                            continue;
 5421                        }
 5422
 5423                        if buffer.contains_str_at(selection.start, &pair.end) {
 5424                            let pair_start_len = pair.start.len();
 5425                            if buffer.contains_str_at(
 5426                                selection.start.saturating_sub_usize(pair_start_len),
 5427                                &pair.start,
 5428                            ) {
 5429                                selection.start -= pair_start_len;
 5430                                selection.end += pair.end.len();
 5431
 5432                                return selection;
 5433                            }
 5434                        }
 5435                    }
 5436                }
 5437
 5438                selection
 5439            })
 5440            .collect();
 5441
 5442        drop(buffer);
 5443        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5444            selections.select(new_selections)
 5445        });
 5446    }
 5447
 5448    /// Iterate the given selections, and for each one, find the smallest surrounding
 5449    /// autoclose region. This uses the ordering of the selections and the autoclose
 5450    /// regions to avoid repeated comparisons.
 5451    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5452        &'a self,
 5453        selections: impl IntoIterator<Item = Selection<D>>,
 5454        buffer: &'a MultiBufferSnapshot,
 5455    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5456        let mut i = 0;
 5457        let mut regions = self.autoclose_regions.as_slice();
 5458        selections.into_iter().map(move |selection| {
 5459            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5460
 5461            let mut enclosing = None;
 5462            while let Some(pair_state) = regions.get(i) {
 5463                if pair_state.range.end.to_offset(buffer) < range.start {
 5464                    regions = &regions[i + 1..];
 5465                    i = 0;
 5466                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5467                    break;
 5468                } else {
 5469                    if pair_state.selection_id == selection.id {
 5470                        enclosing = Some(pair_state);
 5471                    }
 5472                    i += 1;
 5473                }
 5474            }
 5475
 5476            (selection, enclosing)
 5477        })
 5478    }
 5479
 5480    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5481    fn invalidate_autoclose_regions(
 5482        &mut self,
 5483        mut selections: &[Selection<Anchor>],
 5484        buffer: &MultiBufferSnapshot,
 5485    ) {
 5486        self.autoclose_regions.retain(|state| {
 5487            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5488                return false;
 5489            }
 5490
 5491            let mut i = 0;
 5492            while let Some(selection) = selections.get(i) {
 5493                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5494                    selections = &selections[1..];
 5495                    continue;
 5496                }
 5497                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5498                    break;
 5499                }
 5500                if selection.id == state.selection_id {
 5501                    return true;
 5502                } else {
 5503                    i += 1;
 5504                }
 5505            }
 5506            false
 5507        });
 5508    }
 5509
 5510    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5511        let offset = position.to_offset(buffer);
 5512        let (word_range, kind) =
 5513            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5514        if offset > word_range.start && kind == Some(CharKind::Word) {
 5515            Some(
 5516                buffer
 5517                    .text_for_range(word_range.start..offset)
 5518                    .collect::<String>(),
 5519            )
 5520        } else {
 5521            None
 5522        }
 5523    }
 5524
 5525    pub fn visible_excerpts(
 5526        &self,
 5527        lsp_related_only: bool,
 5528        cx: &mut Context<Editor>,
 5529    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5530        let project = self.project().cloned();
 5531        let multi_buffer = self.buffer().read(cx);
 5532        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5533        let multi_buffer_visible_start = self
 5534            .scroll_manager
 5535            .anchor()
 5536            .anchor
 5537            .to_point(&multi_buffer_snapshot);
 5538        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5539            multi_buffer_visible_start
 5540                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5541            Bias::Left,
 5542        );
 5543        multi_buffer_snapshot
 5544            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5545            .into_iter()
 5546            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5547            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5548                if !lsp_related_only {
 5549                    return Some((
 5550                        excerpt_id,
 5551                        (
 5552                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5553                            buffer.version().clone(),
 5554                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5555                        ),
 5556                    ));
 5557                }
 5558
 5559                let project = project.as_ref()?.read(cx);
 5560                let buffer_file = project::File::from_dyn(buffer.file())?;
 5561                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5562                let worktree_entry = buffer_worktree
 5563                    .read(cx)
 5564                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5565                if worktree_entry.is_ignored {
 5566                    None
 5567                } else {
 5568                    Some((
 5569                        excerpt_id,
 5570                        (
 5571                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5572                            buffer.version().clone(),
 5573                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5574                        ),
 5575                    ))
 5576                }
 5577            })
 5578            .collect()
 5579    }
 5580
 5581    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5582        TextLayoutDetails {
 5583            text_system: window.text_system().clone(),
 5584            editor_style: self.style.clone().unwrap(),
 5585            rem_size: window.rem_size(),
 5586            scroll_anchor: self.scroll_manager.anchor(),
 5587            visible_rows: self.visible_line_count(),
 5588            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5589        }
 5590    }
 5591
 5592    fn trigger_on_type_formatting(
 5593        &self,
 5594        input: String,
 5595        window: &mut Window,
 5596        cx: &mut Context<Self>,
 5597    ) -> Option<Task<Result<()>>> {
 5598        if input.chars().count() != 1 {
 5599            return None;
 5600        }
 5601
 5602        let project = self.project()?;
 5603        let position = self.selections.newest_anchor().head();
 5604        let (buffer, buffer_position) = self
 5605            .buffer
 5606            .read(cx)
 5607            .text_anchor_for_position(position, cx)?;
 5608
 5609        let settings = language_settings::language_settings(
 5610            buffer
 5611                .read(cx)
 5612                .language_at(buffer_position)
 5613                .map(|l| l.name()),
 5614            buffer.read(cx).file(),
 5615            cx,
 5616        );
 5617        if !settings.use_on_type_format {
 5618            return None;
 5619        }
 5620
 5621        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5622        // hence we do LSP request & edit on host side only — add formats to host's history.
 5623        let push_to_lsp_host_history = true;
 5624        // If this is not the host, append its history with new edits.
 5625        let push_to_client_history = project.read(cx).is_via_collab();
 5626
 5627        let on_type_formatting = project.update(cx, |project, cx| {
 5628            project.on_type_format(
 5629                buffer.clone(),
 5630                buffer_position,
 5631                input,
 5632                push_to_lsp_host_history,
 5633                cx,
 5634            )
 5635        });
 5636        Some(cx.spawn_in(window, async move |editor, cx| {
 5637            if let Some(transaction) = on_type_formatting.await? {
 5638                if push_to_client_history {
 5639                    buffer.update(cx, |buffer, _| {
 5640                        buffer.push_transaction(transaction, Instant::now());
 5641                        buffer.finalize_last_transaction();
 5642                    });
 5643                }
 5644                editor.update(cx, |editor, cx| {
 5645                    editor.refresh_document_highlights(cx);
 5646                })?;
 5647            }
 5648            Ok(())
 5649        }))
 5650    }
 5651
 5652    pub fn show_word_completions(
 5653        &mut self,
 5654        _: &ShowWordCompletions,
 5655        window: &mut Window,
 5656        cx: &mut Context<Self>,
 5657    ) {
 5658        self.open_or_update_completions_menu(
 5659            Some(CompletionsMenuSource::Words {
 5660                ignore_threshold: true,
 5661            }),
 5662            None,
 5663            false,
 5664            window,
 5665            cx,
 5666        );
 5667    }
 5668
 5669    pub fn show_completions(
 5670        &mut self,
 5671        _: &ShowCompletions,
 5672        window: &mut Window,
 5673        cx: &mut Context<Self>,
 5674    ) {
 5675        self.open_or_update_completions_menu(None, None, false, window, cx);
 5676    }
 5677
 5678    fn open_or_update_completions_menu(
 5679        &mut self,
 5680        requested_source: Option<CompletionsMenuSource>,
 5681        trigger: Option<String>,
 5682        trigger_in_words: bool,
 5683        window: &mut Window,
 5684        cx: &mut Context<Self>,
 5685    ) {
 5686        if self.pending_rename.is_some() {
 5687            return;
 5688        }
 5689
 5690        let completions_source = self
 5691            .context_menu
 5692            .borrow()
 5693            .as_ref()
 5694            .and_then(|menu| match menu {
 5695                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5696                CodeContextMenu::CodeActions(_) => None,
 5697            });
 5698
 5699        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5700
 5701        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5702        // inserted and selected. To handle that case, the start of the selection is used so that
 5703        // the menu starts with all choices.
 5704        let position = self
 5705            .selections
 5706            .newest_anchor()
 5707            .start
 5708            .bias_right(&multibuffer_snapshot);
 5709        if position.diff_base_anchor.is_some() {
 5710            return;
 5711        }
 5712        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5713        let Some(buffer) = buffer_position
 5714            .text_anchor
 5715            .buffer_id
 5716            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5717        else {
 5718            return;
 5719        };
 5720        let buffer_snapshot = buffer.read(cx).snapshot();
 5721
 5722        let menu_is_open = matches!(
 5723            self.context_menu.borrow().as_ref(),
 5724            Some(CodeContextMenu::Completions(_))
 5725        );
 5726
 5727        let language = buffer_snapshot
 5728            .language_at(buffer_position.text_anchor)
 5729            .map(|language| language.name());
 5730
 5731        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5732        let completion_settings = language_settings.completions.clone();
 5733
 5734        let show_completions_on_input = self
 5735            .show_completions_on_input_override
 5736            .unwrap_or(language_settings.show_completions_on_input);
 5737        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5738            return;
 5739        }
 5740
 5741        let query: Option<Arc<String>> =
 5742            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5743                .map(|query| query.into());
 5744
 5745        drop(multibuffer_snapshot);
 5746
 5747        // Hide the current completions menu when query is empty. Without this, cached
 5748        // completions from before the trigger char may be reused (#32774).
 5749        if query.is_none() && menu_is_open {
 5750            self.hide_context_menu(window, cx);
 5751        }
 5752
 5753        let mut ignore_word_threshold = false;
 5754        let provider = match requested_source {
 5755            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5756            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5757                ignore_word_threshold = ignore_threshold;
 5758                None
 5759            }
 5760            Some(CompletionsMenuSource::SnippetChoices)
 5761            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5762                log::error!("bug: SnippetChoices requested_source is not handled");
 5763                None
 5764            }
 5765        };
 5766
 5767        let sort_completions = provider
 5768            .as_ref()
 5769            .is_some_and(|provider| provider.sort_completions());
 5770
 5771        let filter_completions = provider
 5772            .as_ref()
 5773            .is_none_or(|provider| provider.filter_completions());
 5774
 5775        let was_snippets_only = matches!(
 5776            completions_source,
 5777            Some(CompletionsMenuSource::SnippetsOnly)
 5778        );
 5779
 5780        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5781            if filter_completions {
 5782                menu.filter(
 5783                    query.clone().unwrap_or_default(),
 5784                    buffer_position.text_anchor,
 5785                    &buffer,
 5786                    provider.clone(),
 5787                    window,
 5788                    cx,
 5789                );
 5790            }
 5791            // When `is_incomplete` is false, no need to re-query completions when the current query
 5792            // is a suffix of the initial query.
 5793            let was_complete = !menu.is_incomplete;
 5794            if was_complete && !was_snippets_only {
 5795                // If the new query is a suffix of the old query (typing more characters) and
 5796                // the previous result was complete, the existing completions can be filtered.
 5797                //
 5798                // Note that snippet completions are always complete.
 5799                let query_matches = match (&menu.initial_query, &query) {
 5800                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5801                    (None, _) => true,
 5802                    _ => false,
 5803                };
 5804                if query_matches {
 5805                    let position_matches = if menu.initial_position == position {
 5806                        true
 5807                    } else {
 5808                        let snapshot = self.buffer.read(cx).read(cx);
 5809                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5810                    };
 5811                    if position_matches {
 5812                        return;
 5813                    }
 5814                }
 5815            }
 5816        };
 5817
 5818        let Anchor {
 5819            excerpt_id: buffer_excerpt_id,
 5820            text_anchor: buffer_position,
 5821            ..
 5822        } = buffer_position;
 5823
 5824        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5825            buffer_snapshot.surrounding_word(buffer_position, None)
 5826        {
 5827            let word_to_exclude = buffer_snapshot
 5828                .text_for_range(word_range.clone())
 5829                .collect::<String>();
 5830            (
 5831                buffer_snapshot.anchor_before(word_range.start)
 5832                    ..buffer_snapshot.anchor_after(buffer_position),
 5833                Some(word_to_exclude),
 5834            )
 5835        } else {
 5836            (buffer_position..buffer_position, None)
 5837        };
 5838
 5839        let show_completion_documentation = buffer_snapshot
 5840            .settings_at(buffer_position, cx)
 5841            .show_completion_documentation;
 5842
 5843        // The document can be large, so stay in reasonable bounds when searching for words,
 5844        // otherwise completion pop-up might be slow to appear.
 5845        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5846        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5847        let min_word_search = buffer_snapshot.clip_point(
 5848            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5849            Bias::Left,
 5850        );
 5851        let max_word_search = buffer_snapshot.clip_point(
 5852            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5853            Bias::Right,
 5854        );
 5855        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5856            ..buffer_snapshot.point_to_offset(max_word_search);
 5857
 5858        let skip_digits = query
 5859            .as_ref()
 5860            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5861
 5862        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5863            trigger.as_ref().is_none_or(|trigger| {
 5864                provider.is_completion_trigger(
 5865                    &buffer,
 5866                    position.text_anchor,
 5867                    trigger,
 5868                    trigger_in_words,
 5869                    cx,
 5870                )
 5871            })
 5872        });
 5873
 5874        let provider_responses = if let Some(provider) = &provider
 5875            && load_provider_completions
 5876        {
 5877            let trigger_character =
 5878                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5879            let completion_context = CompletionContext {
 5880                trigger_kind: match &trigger_character {
 5881                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5882                    None => CompletionTriggerKind::INVOKED,
 5883                },
 5884                trigger_character,
 5885            };
 5886
 5887            provider.completions(
 5888                buffer_excerpt_id,
 5889                &buffer,
 5890                buffer_position,
 5891                completion_context,
 5892                window,
 5893                cx,
 5894            )
 5895        } else {
 5896            Task::ready(Ok(Vec::new()))
 5897        };
 5898
 5899        let load_word_completions = if !self.word_completions_enabled {
 5900            false
 5901        } else if requested_source
 5902            == Some(CompletionsMenuSource::Words {
 5903                ignore_threshold: true,
 5904            })
 5905        {
 5906            true
 5907        } else {
 5908            load_provider_completions
 5909                && completion_settings.words != WordsCompletionMode::Disabled
 5910                && (ignore_word_threshold || {
 5911                    let words_min_length = completion_settings.words_min_length;
 5912                    // check whether word has at least `words_min_length` characters
 5913                    let query_chars = query.iter().flat_map(|q| q.chars());
 5914                    query_chars.take(words_min_length).count() == words_min_length
 5915                })
 5916        };
 5917
 5918        let mut words = if load_word_completions {
 5919            cx.background_spawn({
 5920                let buffer_snapshot = buffer_snapshot.clone();
 5921                async move {
 5922                    buffer_snapshot.words_in_range(WordsQuery {
 5923                        fuzzy_contents: None,
 5924                        range: word_search_range,
 5925                        skip_digits,
 5926                    })
 5927                }
 5928            })
 5929        } else {
 5930            Task::ready(BTreeMap::default())
 5931        };
 5932
 5933        let snippets = if let Some(provider) = &provider
 5934            && provider.show_snippets()
 5935            && let Some(project) = self.project()
 5936        {
 5937            let char_classifier = buffer_snapshot
 5938                .char_classifier_at(buffer_position)
 5939                .scope_context(Some(CharScopeContext::Completion));
 5940            project.update(cx, |project, cx| {
 5941                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5942            })
 5943        } else {
 5944            Task::ready(Ok(CompletionResponse {
 5945                completions: Vec::new(),
 5946                display_options: Default::default(),
 5947                is_incomplete: false,
 5948            }))
 5949        };
 5950
 5951        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5952
 5953        let id = post_inc(&mut self.next_completion_id);
 5954        let task = cx.spawn_in(window, async move |editor, cx| {
 5955            let Ok(()) = editor.update(cx, |this, _| {
 5956                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5957            }) else {
 5958                return;
 5959            };
 5960
 5961            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5962            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5963            let mut completions = Vec::new();
 5964            let mut is_incomplete = false;
 5965            let mut display_options: Option<CompletionDisplayOptions> = None;
 5966            if let Some(provider_responses) = provider_responses.await.log_err()
 5967                && !provider_responses.is_empty()
 5968            {
 5969                for response in provider_responses {
 5970                    completions.extend(response.completions);
 5971                    is_incomplete = is_incomplete || response.is_incomplete;
 5972                    match display_options.as_mut() {
 5973                        None => {
 5974                            display_options = Some(response.display_options);
 5975                        }
 5976                        Some(options) => options.merge(&response.display_options),
 5977                    }
 5978                }
 5979                if completion_settings.words == WordsCompletionMode::Fallback {
 5980                    words = Task::ready(BTreeMap::default());
 5981                }
 5982            }
 5983            let display_options = display_options.unwrap_or_default();
 5984
 5985            let mut words = words.await;
 5986            if let Some(word_to_exclude) = &word_to_exclude {
 5987                words.remove(word_to_exclude);
 5988            }
 5989            for lsp_completion in &completions {
 5990                words.remove(&lsp_completion.new_text);
 5991            }
 5992            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5993                replace_range: word_replace_range.clone(),
 5994                new_text: word.clone(),
 5995                label: CodeLabel::plain(word, None),
 5996                match_start: None,
 5997                snippet_deduplication_key: None,
 5998                icon_path: None,
 5999                documentation: None,
 6000                source: CompletionSource::BufferWord {
 6001                    word_range,
 6002                    resolved: false,
 6003                },
 6004                insert_text_mode: Some(InsertTextMode::AS_IS),
 6005                confirm: None,
 6006            }));
 6007
 6008            completions.extend(
 6009                snippets
 6010                    .await
 6011                    .into_iter()
 6012                    .flat_map(|response| response.completions),
 6013            );
 6014
 6015            let menu = if completions.is_empty() {
 6016                None
 6017            } else {
 6018                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6019                    let languages = editor
 6020                        .workspace
 6021                        .as_ref()
 6022                        .and_then(|(workspace, _)| workspace.upgrade())
 6023                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6024                    let menu = CompletionsMenu::new(
 6025                        id,
 6026                        requested_source.unwrap_or(if load_provider_completions {
 6027                            CompletionsMenuSource::Normal
 6028                        } else {
 6029                            CompletionsMenuSource::SnippetsOnly
 6030                        }),
 6031                        sort_completions,
 6032                        show_completion_documentation,
 6033                        position,
 6034                        query.clone(),
 6035                        is_incomplete,
 6036                        buffer.clone(),
 6037                        completions.into(),
 6038                        editor
 6039                            .context_menu()
 6040                            .borrow_mut()
 6041                            .as_ref()
 6042                            .map(|menu| menu.primary_scroll_handle()),
 6043                        display_options,
 6044                        snippet_sort_order,
 6045                        languages,
 6046                        language,
 6047                        cx,
 6048                    );
 6049
 6050                    let query = if filter_completions { query } else { None };
 6051                    let matches_task = menu.do_async_filtering(
 6052                        query.unwrap_or_default(),
 6053                        buffer_position,
 6054                        &buffer,
 6055                        cx,
 6056                    );
 6057                    (menu, matches_task)
 6058                }) else {
 6059                    return;
 6060                };
 6061
 6062                let matches = matches_task.await;
 6063
 6064                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6065                    // Newer menu already set, so exit.
 6066                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6067                        editor.context_menu.borrow().as_ref()
 6068                        && prev_menu.id > id
 6069                    {
 6070                        return;
 6071                    };
 6072
 6073                    // Only valid to take prev_menu because either the new menu is immediately set
 6074                    // below, or the menu is hidden.
 6075                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6076                        editor.context_menu.borrow_mut().take()
 6077                    {
 6078                        let position_matches =
 6079                            if prev_menu.initial_position == menu.initial_position {
 6080                                true
 6081                            } else {
 6082                                let snapshot = editor.buffer.read(cx).read(cx);
 6083                                prev_menu.initial_position.to_offset(&snapshot)
 6084                                    == menu.initial_position.to_offset(&snapshot)
 6085                            };
 6086                        if position_matches {
 6087                            // Preserve markdown cache before `set_filter_results` because it will
 6088                            // try to populate the documentation cache.
 6089                            menu.preserve_markdown_cache(prev_menu);
 6090                        }
 6091                    };
 6092
 6093                    menu.set_filter_results(matches, provider, window, cx);
 6094                }) else {
 6095                    return;
 6096                };
 6097
 6098                menu.visible().then_some(menu)
 6099            };
 6100
 6101            editor
 6102                .update_in(cx, |editor, window, cx| {
 6103                    if editor.focus_handle.is_focused(window)
 6104                        && let Some(menu) = menu
 6105                    {
 6106                        *editor.context_menu.borrow_mut() =
 6107                            Some(CodeContextMenu::Completions(menu));
 6108
 6109                        crate::hover_popover::hide_hover(editor, cx);
 6110                        if editor.show_edit_predictions_in_menu() {
 6111                            editor.update_visible_edit_prediction(window, cx);
 6112                        } else {
 6113                            editor.discard_edit_prediction(false, cx);
 6114                        }
 6115
 6116                        cx.notify();
 6117                        return;
 6118                    }
 6119
 6120                    if editor.completion_tasks.len() <= 1 {
 6121                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6122                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6123                        // If it was already hidden and we don't show edit predictions in the menu,
 6124                        // we should also show the edit prediction when available.
 6125                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6126                            editor.update_visible_edit_prediction(window, cx);
 6127                        }
 6128                    }
 6129                })
 6130                .ok();
 6131        });
 6132
 6133        self.completion_tasks.push((id, task));
 6134    }
 6135
 6136    #[cfg(feature = "test-support")]
 6137    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6138        let menu = self.context_menu.borrow();
 6139        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6140            let completions = menu.completions.borrow();
 6141            Some(completions.to_vec())
 6142        } else {
 6143            None
 6144        }
 6145    }
 6146
 6147    pub fn with_completions_menu_matching_id<R>(
 6148        &self,
 6149        id: CompletionId,
 6150        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6151    ) -> R {
 6152        let mut context_menu = self.context_menu.borrow_mut();
 6153        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6154            return f(None);
 6155        };
 6156        if completions_menu.id != id {
 6157            return f(None);
 6158        }
 6159        f(Some(completions_menu))
 6160    }
 6161
 6162    pub fn confirm_completion(
 6163        &mut self,
 6164        action: &ConfirmCompletion,
 6165        window: &mut Window,
 6166        cx: &mut Context<Self>,
 6167    ) -> Option<Task<Result<()>>> {
 6168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6169        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6170    }
 6171
 6172    pub fn confirm_completion_insert(
 6173        &mut self,
 6174        _: &ConfirmCompletionInsert,
 6175        window: &mut Window,
 6176        cx: &mut Context<Self>,
 6177    ) -> Option<Task<Result<()>>> {
 6178        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6179        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6180    }
 6181
 6182    pub fn confirm_completion_replace(
 6183        &mut self,
 6184        _: &ConfirmCompletionReplace,
 6185        window: &mut Window,
 6186        cx: &mut Context<Self>,
 6187    ) -> Option<Task<Result<()>>> {
 6188        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6189        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6190    }
 6191
 6192    pub fn compose_completion(
 6193        &mut self,
 6194        action: &ComposeCompletion,
 6195        window: &mut Window,
 6196        cx: &mut Context<Self>,
 6197    ) -> Option<Task<Result<()>>> {
 6198        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6199        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6200    }
 6201
 6202    fn do_completion(
 6203        &mut self,
 6204        item_ix: Option<usize>,
 6205        intent: CompletionIntent,
 6206        window: &mut Window,
 6207        cx: &mut Context<Editor>,
 6208    ) -> Option<Task<Result<()>>> {
 6209        use language::ToOffset as _;
 6210
 6211        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6212        else {
 6213            return None;
 6214        };
 6215
 6216        let candidate_id = {
 6217            let entries = completions_menu.entries.borrow();
 6218            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6219            if self.show_edit_predictions_in_menu() {
 6220                self.discard_edit_prediction(true, cx);
 6221            }
 6222            mat.candidate_id
 6223        };
 6224
 6225        let completion = completions_menu
 6226            .completions
 6227            .borrow()
 6228            .get(candidate_id)?
 6229            .clone();
 6230        cx.stop_propagation();
 6231
 6232        let buffer_handle = completions_menu.buffer.clone();
 6233
 6234        let CompletionEdit {
 6235            new_text,
 6236            snippet,
 6237            replace_range,
 6238        } = process_completion_for_edit(
 6239            &completion,
 6240            intent,
 6241            &buffer_handle,
 6242            &completions_menu.initial_position.text_anchor,
 6243            cx,
 6244        );
 6245
 6246        let buffer = buffer_handle.read(cx);
 6247        let snapshot = self.buffer.read(cx).snapshot(cx);
 6248        let newest_anchor = self.selections.newest_anchor();
 6249        let replace_range_multibuffer = {
 6250            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6251            excerpt.map_range_from_buffer(replace_range.clone())
 6252        };
 6253        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6254            return None;
 6255        }
 6256
 6257        let old_text = buffer
 6258            .text_for_range(replace_range.clone())
 6259            .collect::<String>();
 6260        let lookbehind = newest_anchor
 6261            .start
 6262            .text_anchor
 6263            .to_offset(buffer)
 6264            .saturating_sub(replace_range.start.0);
 6265        let lookahead = replace_range
 6266            .end
 6267            .0
 6268            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6269        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6270        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6271
 6272        let selections = self
 6273            .selections
 6274            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6275        let mut ranges = Vec::new();
 6276        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6277
 6278        for selection in &selections {
 6279            let range = if selection.id == newest_anchor.id {
 6280                replace_range_multibuffer.clone()
 6281            } else {
 6282                let mut range = selection.range();
 6283
 6284                // if prefix is present, don't duplicate it
 6285                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6286                    range.start = range.start.saturating_sub_usize(lookbehind);
 6287
 6288                    // if suffix is also present, mimic the newest cursor and replace it
 6289                    if selection.id != newest_anchor.id
 6290                        && snapshot.contains_str_at(range.end, suffix)
 6291                    {
 6292                        range.end += lookahead;
 6293                    }
 6294                }
 6295                range
 6296            };
 6297
 6298            ranges.push(range.clone());
 6299
 6300            if !self.linked_edit_ranges.is_empty() {
 6301                let start_anchor = snapshot.anchor_before(range.start);
 6302                let end_anchor = snapshot.anchor_after(range.end);
 6303                if let Some(ranges) = self
 6304                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6305                {
 6306                    for (buffer, edits) in ranges {
 6307                        linked_edits
 6308                            .entry(buffer.clone())
 6309                            .or_default()
 6310                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6311                    }
 6312                }
 6313            }
 6314        }
 6315
 6316        let common_prefix_len = old_text
 6317            .chars()
 6318            .zip(new_text.chars())
 6319            .take_while(|(a, b)| a == b)
 6320            .map(|(a, _)| a.len_utf8())
 6321            .sum::<usize>();
 6322
 6323        cx.emit(EditorEvent::InputHandled {
 6324            utf16_range_to_replace: None,
 6325            text: new_text[common_prefix_len..].into(),
 6326        });
 6327
 6328        self.transact(window, cx, |editor, window, cx| {
 6329            if let Some(mut snippet) = snippet {
 6330                snippet.text = new_text.to_string();
 6331                editor
 6332                    .insert_snippet(&ranges, snippet, window, cx)
 6333                    .log_err();
 6334            } else {
 6335                editor.buffer.update(cx, |multi_buffer, cx| {
 6336                    let auto_indent = match completion.insert_text_mode {
 6337                        Some(InsertTextMode::AS_IS) => None,
 6338                        _ => editor.autoindent_mode.clone(),
 6339                    };
 6340                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6341                    multi_buffer.edit(edits, auto_indent, cx);
 6342                });
 6343            }
 6344            for (buffer, edits) in linked_edits {
 6345                buffer.update(cx, |buffer, cx| {
 6346                    let snapshot = buffer.snapshot();
 6347                    let edits = edits
 6348                        .into_iter()
 6349                        .map(|(range, text)| {
 6350                            use text::ToPoint as TP;
 6351                            let end_point = TP::to_point(&range.end, &snapshot);
 6352                            let start_point = TP::to_point(&range.start, &snapshot);
 6353                            (start_point..end_point, text)
 6354                        })
 6355                        .sorted_by_key(|(range, _)| range.start);
 6356                    buffer.edit(edits, None, cx);
 6357                })
 6358            }
 6359
 6360            editor.refresh_edit_prediction(true, false, window, cx);
 6361        });
 6362        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6363
 6364        let show_new_completions_on_confirm = completion
 6365            .confirm
 6366            .as_ref()
 6367            .is_some_and(|confirm| confirm(intent, window, cx));
 6368        if show_new_completions_on_confirm {
 6369            self.open_or_update_completions_menu(None, None, false, window, cx);
 6370        }
 6371
 6372        let provider = self.completion_provider.as_ref()?;
 6373
 6374        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6375        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6376            let CompletionSource::Lsp {
 6377                lsp_completion,
 6378                server_id,
 6379                ..
 6380            } = &completion.source
 6381            else {
 6382                return None;
 6383            };
 6384            let lsp_command = lsp_completion.command.as_ref()?;
 6385            let available_commands = lsp_store
 6386                .read(cx)
 6387                .lsp_server_capabilities
 6388                .get(server_id)
 6389                .and_then(|server_capabilities| {
 6390                    server_capabilities
 6391                        .execute_command_provider
 6392                        .as_ref()
 6393                        .map(|options| options.commands.as_slice())
 6394                })?;
 6395            if available_commands.contains(&lsp_command.command) {
 6396                Some(CodeAction {
 6397                    server_id: *server_id,
 6398                    range: language::Anchor::MIN..language::Anchor::MIN,
 6399                    lsp_action: LspAction::Command(lsp_command.clone()),
 6400                    resolved: false,
 6401                })
 6402            } else {
 6403                None
 6404            }
 6405        });
 6406
 6407        drop(completion);
 6408        let apply_edits = provider.apply_additional_edits_for_completion(
 6409            buffer_handle.clone(),
 6410            completions_menu.completions.clone(),
 6411            candidate_id,
 6412            true,
 6413            cx,
 6414        );
 6415
 6416        let editor_settings = EditorSettings::get_global(cx);
 6417        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6418            // After the code completion is finished, users often want to know what signatures are needed.
 6419            // so we should automatically call signature_help
 6420            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6421        }
 6422
 6423        Some(cx.spawn_in(window, async move |editor, cx| {
 6424            apply_edits.await?;
 6425
 6426            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6427                let title = command.lsp_action.title().to_owned();
 6428                let project_transaction = lsp_store
 6429                    .update(cx, |lsp_store, cx| {
 6430                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6431                    })
 6432                    .await
 6433                    .context("applying post-completion command")?;
 6434                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6435                    Self::open_project_transaction(
 6436                        &editor,
 6437                        workspace.downgrade(),
 6438                        project_transaction,
 6439                        title,
 6440                        cx,
 6441                    )
 6442                    .await?;
 6443                }
 6444            }
 6445
 6446            Ok(())
 6447        }))
 6448    }
 6449
 6450    pub fn toggle_code_actions(
 6451        &mut self,
 6452        action: &ToggleCodeActions,
 6453        window: &mut Window,
 6454        cx: &mut Context<Self>,
 6455    ) {
 6456        let quick_launch = action.quick_launch;
 6457        let mut context_menu = self.context_menu.borrow_mut();
 6458        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6459            if code_actions.deployed_from == action.deployed_from {
 6460                // Toggle if we're selecting the same one
 6461                *context_menu = None;
 6462                cx.notify();
 6463                return;
 6464            } else {
 6465                // Otherwise, clear it and start a new one
 6466                *context_menu = None;
 6467                cx.notify();
 6468            }
 6469        }
 6470        drop(context_menu);
 6471        let snapshot = self.snapshot(window, cx);
 6472        let deployed_from = action.deployed_from.clone();
 6473        let action = action.clone();
 6474        self.completion_tasks.clear();
 6475        self.discard_edit_prediction(false, cx);
 6476
 6477        let multibuffer_point = match &action.deployed_from {
 6478            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6479                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6480            }
 6481            _ => self
 6482                .selections
 6483                .newest::<Point>(&snapshot.display_snapshot)
 6484                .head(),
 6485        };
 6486        let Some((buffer, buffer_row)) = snapshot
 6487            .buffer_snapshot()
 6488            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6489            .and_then(|(buffer_snapshot, range)| {
 6490                self.buffer()
 6491                    .read(cx)
 6492                    .buffer(buffer_snapshot.remote_id())
 6493                    .map(|buffer| (buffer, range.start.row))
 6494            })
 6495        else {
 6496            return;
 6497        };
 6498        let buffer_id = buffer.read(cx).remote_id();
 6499        let tasks = self
 6500            .tasks
 6501            .get(&(buffer_id, buffer_row))
 6502            .map(|t| Arc::new(t.to_owned()));
 6503
 6504        if !self.focus_handle.is_focused(window) {
 6505            return;
 6506        }
 6507        let project = self.project.clone();
 6508
 6509        let code_actions_task = match deployed_from {
 6510            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6511            _ => self.code_actions(buffer_row, window, cx),
 6512        };
 6513
 6514        let runnable_task = match deployed_from {
 6515            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6516            _ => {
 6517                let mut task_context_task = Task::ready(None);
 6518                if let Some(tasks) = &tasks
 6519                    && let Some(project) = project
 6520                {
 6521                    task_context_task =
 6522                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6523                }
 6524
 6525                cx.spawn_in(window, {
 6526                    let buffer = buffer.clone();
 6527                    async move |editor, cx| {
 6528                        let task_context = task_context_task.await;
 6529
 6530                        let resolved_tasks =
 6531                            tasks
 6532                                .zip(task_context.clone())
 6533                                .map(|(tasks, task_context)| ResolvedTasks {
 6534                                    templates: tasks.resolve(&task_context).collect(),
 6535                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6536                                        multibuffer_point.row,
 6537                                        tasks.column,
 6538                                    )),
 6539                                });
 6540                        let debug_scenarios = editor
 6541                            .update(cx, |editor, cx| {
 6542                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6543                            })?
 6544                            .await;
 6545                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6546                    }
 6547                })
 6548            }
 6549        };
 6550
 6551        cx.spawn_in(window, async move |editor, cx| {
 6552            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6553            let code_actions = code_actions_task.await;
 6554            let spawn_straight_away = quick_launch
 6555                && resolved_tasks
 6556                    .as_ref()
 6557                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6558                && code_actions
 6559                    .as_ref()
 6560                    .is_none_or(|actions| actions.is_empty())
 6561                && debug_scenarios.is_empty();
 6562
 6563            editor.update_in(cx, |editor, window, cx| {
 6564                crate::hover_popover::hide_hover(editor, cx);
 6565                let actions = CodeActionContents::new(
 6566                    resolved_tasks,
 6567                    code_actions,
 6568                    debug_scenarios,
 6569                    task_context.unwrap_or_default(),
 6570                );
 6571
 6572                // Don't show the menu if there are no actions available
 6573                if actions.is_empty() {
 6574                    cx.notify();
 6575                    return Task::ready(Ok(()));
 6576                }
 6577
 6578                *editor.context_menu.borrow_mut() =
 6579                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6580                        buffer,
 6581                        actions,
 6582                        selected_item: Default::default(),
 6583                        scroll_handle: UniformListScrollHandle::default(),
 6584                        deployed_from,
 6585                    }));
 6586                cx.notify();
 6587                if spawn_straight_away
 6588                    && let Some(task) = editor.confirm_code_action(
 6589                        &ConfirmCodeAction { item_ix: Some(0) },
 6590                        window,
 6591                        cx,
 6592                    )
 6593                {
 6594                    return task;
 6595                }
 6596
 6597                Task::ready(Ok(()))
 6598            })
 6599        })
 6600        .detach_and_log_err(cx);
 6601    }
 6602
 6603    fn debug_scenarios(
 6604        &mut self,
 6605        resolved_tasks: &Option<ResolvedTasks>,
 6606        buffer: &Entity<Buffer>,
 6607        cx: &mut App,
 6608    ) -> Task<Vec<task::DebugScenario>> {
 6609        maybe!({
 6610            let project = self.project()?;
 6611            let dap_store = project.read(cx).dap_store();
 6612            let mut scenarios = vec![];
 6613            let resolved_tasks = resolved_tasks.as_ref()?;
 6614            let buffer = buffer.read(cx);
 6615            let language = buffer.language()?;
 6616            let file = buffer.file();
 6617            let debug_adapter = language_settings(language.name().into(), file, cx)
 6618                .debuggers
 6619                .first()
 6620                .map(SharedString::from)
 6621                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6622
 6623            dap_store.update(cx, |dap_store, cx| {
 6624                for (_, task) in &resolved_tasks.templates {
 6625                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6626                        task.original_task().clone(),
 6627                        debug_adapter.clone().into(),
 6628                        task.display_label().to_owned().into(),
 6629                        cx,
 6630                    );
 6631                    scenarios.push(maybe_scenario);
 6632                }
 6633            });
 6634            Some(cx.background_spawn(async move {
 6635                futures::future::join_all(scenarios)
 6636                    .await
 6637                    .into_iter()
 6638                    .flatten()
 6639                    .collect::<Vec<_>>()
 6640            }))
 6641        })
 6642        .unwrap_or_else(|| Task::ready(vec![]))
 6643    }
 6644
 6645    fn code_actions(
 6646        &mut self,
 6647        buffer_row: u32,
 6648        window: &mut Window,
 6649        cx: &mut Context<Self>,
 6650    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6651        let mut task = self.code_actions_task.take();
 6652        cx.spawn_in(window, async move |editor, cx| {
 6653            while let Some(prev_task) = task {
 6654                prev_task.await.log_err();
 6655                task = editor
 6656                    .update(cx, |this, _| this.code_actions_task.take())
 6657                    .ok()?;
 6658            }
 6659
 6660            editor
 6661                .update(cx, |editor, cx| {
 6662                    editor
 6663                        .available_code_actions
 6664                        .clone()
 6665                        .and_then(|(location, code_actions)| {
 6666                            let snapshot = location.buffer.read(cx).snapshot();
 6667                            let point_range = location.range.to_point(&snapshot);
 6668                            let point_range = point_range.start.row..=point_range.end.row;
 6669                            if point_range.contains(&buffer_row) {
 6670                                Some(code_actions)
 6671                            } else {
 6672                                None
 6673                            }
 6674                        })
 6675                })
 6676                .ok()
 6677                .flatten()
 6678        })
 6679    }
 6680
 6681    pub fn confirm_code_action(
 6682        &mut self,
 6683        action: &ConfirmCodeAction,
 6684        window: &mut Window,
 6685        cx: &mut Context<Self>,
 6686    ) -> Option<Task<Result<()>>> {
 6687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6688
 6689        let actions_menu =
 6690            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6691                menu
 6692            } else {
 6693                return None;
 6694            };
 6695
 6696        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6697        let action = actions_menu.actions.get(action_ix)?;
 6698        let title = action.label();
 6699        let buffer = actions_menu.buffer;
 6700        let workspace = self.workspace()?;
 6701
 6702        match action {
 6703            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6704                workspace.update(cx, |workspace, cx| {
 6705                    workspace.schedule_resolved_task(
 6706                        task_source_kind,
 6707                        resolved_task,
 6708                        false,
 6709                        window,
 6710                        cx,
 6711                    );
 6712
 6713                    Some(Task::ready(Ok(())))
 6714                })
 6715            }
 6716            CodeActionsItem::CodeAction {
 6717                excerpt_id,
 6718                action,
 6719                provider,
 6720            } => {
 6721                let apply_code_action =
 6722                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6723                let workspace = workspace.downgrade();
 6724                Some(cx.spawn_in(window, async move |editor, cx| {
 6725                    let project_transaction = apply_code_action.await?;
 6726                    Self::open_project_transaction(
 6727                        &editor,
 6728                        workspace,
 6729                        project_transaction,
 6730                        title,
 6731                        cx,
 6732                    )
 6733                    .await
 6734                }))
 6735            }
 6736            CodeActionsItem::DebugScenario(scenario) => {
 6737                let context = actions_menu.actions.context;
 6738
 6739                workspace.update(cx, |workspace, cx| {
 6740                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6741                    workspace.start_debug_session(
 6742                        scenario,
 6743                        context,
 6744                        Some(buffer),
 6745                        None,
 6746                        window,
 6747                        cx,
 6748                    );
 6749                });
 6750                Some(Task::ready(Ok(())))
 6751            }
 6752        }
 6753    }
 6754
 6755    fn open_transaction_for_hidden_buffers(
 6756        workspace: Entity<Workspace>,
 6757        transaction: ProjectTransaction,
 6758        title: String,
 6759        window: &mut Window,
 6760        cx: &mut Context<Self>,
 6761    ) {
 6762        if transaction.0.is_empty() {
 6763            return;
 6764        }
 6765
 6766        let edited_buffers_already_open = {
 6767            let other_editors: Vec<Entity<Editor>> = workspace
 6768                .read(cx)
 6769                .panes()
 6770                .iter()
 6771                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6772                .filter(|editor| editor.entity_id() != cx.entity_id())
 6773                .collect();
 6774
 6775            transaction.0.keys().all(|buffer| {
 6776                other_editors.iter().any(|editor| {
 6777                    let multi_buffer = editor.read(cx).buffer();
 6778                    multi_buffer.read(cx).is_singleton()
 6779                        && multi_buffer
 6780                            .read(cx)
 6781                            .as_singleton()
 6782                            .map_or(false, |singleton| {
 6783                                singleton.entity_id() == buffer.entity_id()
 6784                            })
 6785                })
 6786            })
 6787        };
 6788        if !edited_buffers_already_open {
 6789            let workspace = workspace.downgrade();
 6790            cx.defer_in(window, move |_, window, cx| {
 6791                cx.spawn_in(window, async move |editor, cx| {
 6792                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6793                        .await
 6794                        .ok()
 6795                })
 6796                .detach();
 6797            });
 6798        }
 6799    }
 6800
 6801    pub async fn open_project_transaction(
 6802        editor: &WeakEntity<Editor>,
 6803        workspace: WeakEntity<Workspace>,
 6804        transaction: ProjectTransaction,
 6805        title: String,
 6806        cx: &mut AsyncWindowContext,
 6807    ) -> Result<()> {
 6808        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6809        cx.update(|_, cx| {
 6810            entries.sort_unstable_by_key(|(buffer, _)| {
 6811                buffer.read(cx).file().map(|f| f.path().clone())
 6812            });
 6813        })?;
 6814        if entries.is_empty() {
 6815            return Ok(());
 6816        }
 6817
 6818        // If the project transaction's edits are all contained within this editor, then
 6819        // avoid opening a new editor to display them.
 6820
 6821        if let [(buffer, transaction)] = &*entries {
 6822            let excerpt = editor.update(cx, |editor, cx| {
 6823                editor
 6824                    .buffer()
 6825                    .read(cx)
 6826                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6827            })?;
 6828            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6829                && excerpted_buffer == *buffer
 6830            {
 6831                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6832                    let excerpt_range = excerpt_range.to_offset(buffer);
 6833                    buffer
 6834                        .edited_ranges_for_transaction::<usize>(transaction)
 6835                        .all(|range| {
 6836                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6837                        })
 6838                });
 6839
 6840                if all_edits_within_excerpt {
 6841                    return Ok(());
 6842                }
 6843            }
 6844        }
 6845
 6846        let mut ranges_to_highlight = Vec::new();
 6847        let excerpt_buffer = cx.new(|cx| {
 6848            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6849            for (buffer_handle, transaction) in &entries {
 6850                let edited_ranges = buffer_handle
 6851                    .read(cx)
 6852                    .edited_ranges_for_transaction::<Point>(transaction)
 6853                    .collect::<Vec<_>>();
 6854                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6855                    PathKey::for_buffer(buffer_handle, cx),
 6856                    buffer_handle.clone(),
 6857                    edited_ranges,
 6858                    multibuffer_context_lines(cx),
 6859                    cx,
 6860                );
 6861
 6862                ranges_to_highlight.extend(ranges);
 6863            }
 6864            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6865            multibuffer
 6866        });
 6867
 6868        workspace.update_in(cx, |workspace, window, cx| {
 6869            let project = workspace.project().clone();
 6870            let editor =
 6871                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6872            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6873            editor.update(cx, |editor, cx| {
 6874                editor.highlight_background::<Self>(
 6875                    &ranges_to_highlight,
 6876                    |_, theme| theme.colors().editor_highlighted_line_background,
 6877                    cx,
 6878                );
 6879            });
 6880        })?;
 6881
 6882        Ok(())
 6883    }
 6884
 6885    pub fn clear_code_action_providers(&mut self) {
 6886        self.code_action_providers.clear();
 6887        self.available_code_actions.take();
 6888    }
 6889
 6890    pub fn add_code_action_provider(
 6891        &mut self,
 6892        provider: Rc<dyn CodeActionProvider>,
 6893        window: &mut Window,
 6894        cx: &mut Context<Self>,
 6895    ) {
 6896        if self
 6897            .code_action_providers
 6898            .iter()
 6899            .any(|existing_provider| existing_provider.id() == provider.id())
 6900        {
 6901            return;
 6902        }
 6903
 6904        self.code_action_providers.push(provider);
 6905        self.refresh_code_actions(window, cx);
 6906    }
 6907
 6908    pub fn remove_code_action_provider(
 6909        &mut self,
 6910        id: Arc<str>,
 6911        window: &mut Window,
 6912        cx: &mut Context<Self>,
 6913    ) {
 6914        self.code_action_providers
 6915            .retain(|provider| provider.id() != id);
 6916        self.refresh_code_actions(window, cx);
 6917    }
 6918
 6919    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6920        !self.code_action_providers.is_empty()
 6921            && EditorSettings::get_global(cx).toolbar.code_actions
 6922    }
 6923
 6924    pub fn has_available_code_actions(&self) -> bool {
 6925        self.available_code_actions
 6926            .as_ref()
 6927            .is_some_and(|(_, actions)| !actions.is_empty())
 6928    }
 6929
 6930    fn render_inline_code_actions(
 6931        &self,
 6932        icon_size: ui::IconSize,
 6933        display_row: DisplayRow,
 6934        is_active: bool,
 6935        cx: &mut Context<Self>,
 6936    ) -> AnyElement {
 6937        let show_tooltip = !self.context_menu_visible();
 6938        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6939            .icon_size(icon_size)
 6940            .shape(ui::IconButtonShape::Square)
 6941            .icon_color(ui::Color::Hidden)
 6942            .toggle_state(is_active)
 6943            .when(show_tooltip, |this| {
 6944                this.tooltip({
 6945                    let focus_handle = self.focus_handle.clone();
 6946                    move |_window, cx| {
 6947                        Tooltip::for_action_in(
 6948                            "Toggle Code Actions",
 6949                            &ToggleCodeActions {
 6950                                deployed_from: None,
 6951                                quick_launch: false,
 6952                            },
 6953                            &focus_handle,
 6954                            cx,
 6955                        )
 6956                    }
 6957                })
 6958            })
 6959            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6960                window.focus(&editor.focus_handle(cx), cx);
 6961                editor.toggle_code_actions(
 6962                    &crate::actions::ToggleCodeActions {
 6963                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6964                            display_row,
 6965                        )),
 6966                        quick_launch: false,
 6967                    },
 6968                    window,
 6969                    cx,
 6970                );
 6971            }))
 6972            .into_any_element()
 6973    }
 6974
 6975    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6976        &self.context_menu
 6977    }
 6978
 6979    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6980        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6981            cx.background_executor()
 6982                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6983                .await;
 6984
 6985            let (start_buffer, start, _, end, newest_selection) = this
 6986                .update(cx, |this, cx| {
 6987                    let newest_selection = this.selections.newest_anchor().clone();
 6988                    if newest_selection.head().diff_base_anchor.is_some() {
 6989                        return None;
 6990                    }
 6991                    let display_snapshot = this.display_snapshot(cx);
 6992                    let newest_selection_adjusted =
 6993                        this.selections.newest_adjusted(&display_snapshot);
 6994                    let buffer = this.buffer.read(cx);
 6995
 6996                    let (start_buffer, start) =
 6997                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6998                    let (end_buffer, end) =
 6999                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7000
 7001                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7002                })?
 7003                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7004                .context(
 7005                    "Expected selection to lie in a single buffer when refreshing code actions",
 7006                )?;
 7007            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7008                let providers = this.code_action_providers.clone();
 7009                let tasks = this
 7010                    .code_action_providers
 7011                    .iter()
 7012                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7013                    .collect::<Vec<_>>();
 7014                (providers, tasks)
 7015            })?;
 7016
 7017            let mut actions = Vec::new();
 7018            for (provider, provider_actions) in
 7019                providers.into_iter().zip(future::join_all(tasks).await)
 7020            {
 7021                if let Some(provider_actions) = provider_actions.log_err() {
 7022                    actions.extend(provider_actions.into_iter().map(|action| {
 7023                        AvailableCodeAction {
 7024                            excerpt_id: newest_selection.start.excerpt_id,
 7025                            action,
 7026                            provider: provider.clone(),
 7027                        }
 7028                    }));
 7029                }
 7030            }
 7031
 7032            this.update(cx, |this, cx| {
 7033                this.available_code_actions = if actions.is_empty() {
 7034                    None
 7035                } else {
 7036                    Some((
 7037                        Location {
 7038                            buffer: start_buffer,
 7039                            range: start..end,
 7040                        },
 7041                        actions.into(),
 7042                    ))
 7043                };
 7044                cx.notify();
 7045            })
 7046        }));
 7047    }
 7048
 7049    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7050        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7051            self.show_git_blame_inline = false;
 7052
 7053            self.show_git_blame_inline_delay_task =
 7054                Some(cx.spawn_in(window, async move |this, cx| {
 7055                    cx.background_executor().timer(delay).await;
 7056
 7057                    this.update(cx, |this, cx| {
 7058                        this.show_git_blame_inline = true;
 7059                        cx.notify();
 7060                    })
 7061                    .log_err();
 7062                }));
 7063        }
 7064    }
 7065
 7066    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7067        let snapshot = self.snapshot(window, cx);
 7068        let cursor = self
 7069            .selections
 7070            .newest::<Point>(&snapshot.display_snapshot)
 7071            .head();
 7072        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 7073        else {
 7074            return;
 7075        };
 7076
 7077        if self.blame.is_none() {
 7078            self.start_git_blame(true, window, cx);
 7079        }
 7080        let Some(blame) = self.blame.as_ref() else {
 7081            return;
 7082        };
 7083
 7084        let row_info = RowInfo {
 7085            buffer_id: Some(buffer.remote_id()),
 7086            buffer_row: Some(point.row),
 7087            ..Default::default()
 7088        };
 7089        let Some((buffer, blame_entry)) = blame
 7090            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7091            .flatten()
 7092        else {
 7093            return;
 7094        };
 7095
 7096        let anchor = self.selections.newest_anchor().head();
 7097        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7098        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7099            self.show_blame_popover(
 7100                buffer,
 7101                &blame_entry,
 7102                position + last_bounds.origin,
 7103                true,
 7104                cx,
 7105            );
 7106        };
 7107    }
 7108
 7109    fn show_blame_popover(
 7110        &mut self,
 7111        buffer: BufferId,
 7112        blame_entry: &BlameEntry,
 7113        position: gpui::Point<Pixels>,
 7114        ignore_timeout: bool,
 7115        cx: &mut Context<Self>,
 7116    ) {
 7117        if let Some(state) = &mut self.inline_blame_popover {
 7118            state.hide_task.take();
 7119        } else {
 7120            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7121            let blame_entry = blame_entry.clone();
 7122            let show_task = cx.spawn(async move |editor, cx| {
 7123                if !ignore_timeout {
 7124                    cx.background_executor()
 7125                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7126                        .await;
 7127                }
 7128                editor
 7129                    .update(cx, |editor, cx| {
 7130                        editor.inline_blame_popover_show_task.take();
 7131                        let Some(blame) = editor.blame.as_ref() else {
 7132                            return;
 7133                        };
 7134                        let blame = blame.read(cx);
 7135                        let details = blame.details_for_entry(buffer, &blame_entry);
 7136                        let markdown = cx.new(|cx| {
 7137                            Markdown::new(
 7138                                details
 7139                                    .as_ref()
 7140                                    .map(|message| message.message.clone())
 7141                                    .unwrap_or_default(),
 7142                                None,
 7143                                None,
 7144                                cx,
 7145                            )
 7146                        });
 7147                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7148                            position,
 7149                            hide_task: None,
 7150                            popover_bounds: None,
 7151                            popover_state: InlineBlamePopoverState {
 7152                                scroll_handle: ScrollHandle::new(),
 7153                                commit_message: details,
 7154                                markdown,
 7155                            },
 7156                            keyboard_grace: ignore_timeout,
 7157                        });
 7158                        cx.notify();
 7159                    })
 7160                    .ok();
 7161            });
 7162            self.inline_blame_popover_show_task = Some(show_task);
 7163        }
 7164    }
 7165
 7166    pub fn has_mouse_context_menu(&self) -> bool {
 7167        self.mouse_context_menu.is_some()
 7168    }
 7169
 7170    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7171        self.inline_blame_popover_show_task.take();
 7172        if let Some(state) = &mut self.inline_blame_popover {
 7173            let hide_task = cx.spawn(async move |editor, cx| {
 7174                if !ignore_timeout {
 7175                    cx.background_executor()
 7176                        .timer(std::time::Duration::from_millis(100))
 7177                        .await;
 7178                }
 7179                editor
 7180                    .update(cx, |editor, cx| {
 7181                        editor.inline_blame_popover.take();
 7182                        cx.notify();
 7183                    })
 7184                    .ok();
 7185            });
 7186            state.hide_task = Some(hide_task);
 7187            true
 7188        } else {
 7189            false
 7190        }
 7191    }
 7192
 7193    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7194        if self.pending_rename.is_some() {
 7195            return None;
 7196        }
 7197
 7198        let provider = self.semantics_provider.clone()?;
 7199        let buffer = self.buffer.read(cx);
 7200        let newest_selection = self.selections.newest_anchor().clone();
 7201        let cursor_position = newest_selection.head();
 7202        let (cursor_buffer, cursor_buffer_position) =
 7203            buffer.text_anchor_for_position(cursor_position, cx)?;
 7204        let (tail_buffer, tail_buffer_position) =
 7205            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7206        if cursor_buffer != tail_buffer {
 7207            return None;
 7208        }
 7209
 7210        let snapshot = cursor_buffer.read(cx).snapshot();
 7211        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7212        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7213        if start_word_range != end_word_range {
 7214            self.document_highlights_task.take();
 7215            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7216            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7217            return None;
 7218        }
 7219
 7220        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7221        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7222            cx.background_executor()
 7223                .timer(Duration::from_millis(debounce))
 7224                .await;
 7225
 7226            let highlights = if let Some(highlights) = cx.update(|cx| {
 7227                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7228            }) {
 7229                highlights.await.log_err()
 7230            } else {
 7231                None
 7232            };
 7233
 7234            if let Some(highlights) = highlights {
 7235                this.update(cx, |this, cx| {
 7236                    if this.pending_rename.is_some() {
 7237                        return;
 7238                    }
 7239
 7240                    let buffer = this.buffer.read(cx);
 7241                    if buffer
 7242                        .text_anchor_for_position(cursor_position, cx)
 7243                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7244                    {
 7245                        return;
 7246                    }
 7247
 7248                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7249                    let mut write_ranges = Vec::new();
 7250                    let mut read_ranges = Vec::new();
 7251                    for highlight in highlights {
 7252                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7253                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7254                        {
 7255                            let start = highlight
 7256                                .range
 7257                                .start
 7258                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7259                            let end = highlight
 7260                                .range
 7261                                .end
 7262                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7263                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7264                                continue;
 7265                            }
 7266
 7267                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7268                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7269                                write_ranges.push(range);
 7270                            } else {
 7271                                read_ranges.push(range);
 7272                            }
 7273                        }
 7274                    }
 7275
 7276                    this.highlight_background::<DocumentHighlightRead>(
 7277                        &read_ranges,
 7278                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7279                        cx,
 7280                    );
 7281                    this.highlight_background::<DocumentHighlightWrite>(
 7282                        &write_ranges,
 7283                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7284                        cx,
 7285                    );
 7286                    cx.notify();
 7287                })
 7288                .log_err();
 7289            }
 7290        }));
 7291        None
 7292    }
 7293
 7294    fn prepare_highlight_query_from_selection(
 7295        &mut self,
 7296        window: &Window,
 7297        cx: &mut Context<Editor>,
 7298    ) -> Option<(String, Range<Anchor>)> {
 7299        if matches!(self.mode, EditorMode::SingleLine) {
 7300            return None;
 7301        }
 7302        if !EditorSettings::get_global(cx).selection_highlight {
 7303            return None;
 7304        }
 7305        if self.selections.count() != 1 || self.selections.line_mode() {
 7306            return None;
 7307        }
 7308        let snapshot = self.snapshot(window, cx);
 7309        let selection = self.selections.newest::<Point>(&snapshot);
 7310        // If the selection spans multiple rows OR it is empty
 7311        if selection.start.row != selection.end.row
 7312            || selection.start.column == selection.end.column
 7313        {
 7314            return None;
 7315        }
 7316        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7317        let query = snapshot
 7318            .buffer_snapshot()
 7319            .text_for_range(selection_anchor_range.clone())
 7320            .collect::<String>();
 7321        if query.trim().is_empty() {
 7322            return None;
 7323        }
 7324        Some((query, selection_anchor_range))
 7325    }
 7326
 7327    #[ztracing::instrument(skip_all)]
 7328    fn update_selection_occurrence_highlights(
 7329        &mut self,
 7330        query_text: String,
 7331        query_range: Range<Anchor>,
 7332        multi_buffer_range_to_query: Range<Point>,
 7333        use_debounce: bool,
 7334        window: &mut Window,
 7335        cx: &mut Context<Editor>,
 7336    ) -> Task<()> {
 7337        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7338        cx.spawn_in(window, async move |editor, cx| {
 7339            if use_debounce {
 7340                cx.background_executor()
 7341                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7342                    .await;
 7343            }
 7344            let match_task = cx.background_spawn(async move {
 7345                let buffer_ranges = multi_buffer_snapshot
 7346                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7347                    .into_iter()
 7348                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7349                let mut match_ranges = Vec::new();
 7350                let Ok(regex) = project::search::SearchQuery::text(
 7351                    query_text.clone(),
 7352                    false,
 7353                    false,
 7354                    false,
 7355                    Default::default(),
 7356                    Default::default(),
 7357                    false,
 7358                    None,
 7359                ) else {
 7360                    return Vec::default();
 7361                };
 7362                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7363                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7364                    match_ranges.extend(
 7365                        regex
 7366                            .search(
 7367                                buffer_snapshot,
 7368                                Some(search_range.start.0..search_range.end.0),
 7369                            )
 7370                            .await
 7371                            .into_iter()
 7372                            .filter_map(|match_range| {
 7373                                let match_start = buffer_snapshot
 7374                                    .anchor_after(search_range.start + match_range.start);
 7375                                let match_end = buffer_snapshot
 7376                                    .anchor_before(search_range.start + match_range.end);
 7377                                let match_anchor_range =
 7378                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7379                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7380                            }),
 7381                    );
 7382                }
 7383                match_ranges
 7384            });
 7385            let match_ranges = match_task.await;
 7386            editor
 7387                .update_in(cx, |editor, _, cx| {
 7388                    if use_debounce {
 7389                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7390                        editor.debounced_selection_highlight_complete = true;
 7391                    } else if editor.debounced_selection_highlight_complete {
 7392                        return;
 7393                    }
 7394                    if !match_ranges.is_empty() {
 7395                        editor.highlight_background::<SelectedTextHighlight>(
 7396                            &match_ranges,
 7397                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7398                            cx,
 7399                        )
 7400                    }
 7401                })
 7402                .log_err();
 7403        })
 7404    }
 7405
 7406    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7407        struct NewlineFold;
 7408        let type_id = std::any::TypeId::of::<NewlineFold>();
 7409        if !self.mode.is_single_line() {
 7410            return;
 7411        }
 7412        let snapshot = self.snapshot(window, cx);
 7413        if snapshot.buffer_snapshot().max_point().row == 0 {
 7414            return;
 7415        }
 7416        let task = cx.background_spawn(async move {
 7417            let new_newlines = snapshot
 7418                .buffer_chars_at(MultiBufferOffset(0))
 7419                .filter_map(|(c, i)| {
 7420                    if c == '\n' {
 7421                        Some(
 7422                            snapshot.buffer_snapshot().anchor_after(i)
 7423                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7424                        )
 7425                    } else {
 7426                        None
 7427                    }
 7428                })
 7429                .collect::<Vec<_>>();
 7430            let existing_newlines = snapshot
 7431                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7432                .filter_map(|fold| {
 7433                    if fold.placeholder.type_tag == Some(type_id) {
 7434                        Some(fold.range.start..fold.range.end)
 7435                    } else {
 7436                        None
 7437                    }
 7438                })
 7439                .collect::<Vec<_>>();
 7440
 7441            (new_newlines, existing_newlines)
 7442        });
 7443        self.folding_newlines = cx.spawn(async move |this, cx| {
 7444            let (new_newlines, existing_newlines) = task.await;
 7445            if new_newlines == existing_newlines {
 7446                return;
 7447            }
 7448            let placeholder = FoldPlaceholder {
 7449                render: Arc::new(move |_, _, cx| {
 7450                    div()
 7451                        .bg(cx.theme().status().hint_background)
 7452                        .border_b_1()
 7453                        .size_full()
 7454                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7455                        .border_color(cx.theme().status().hint)
 7456                        .child("\\n")
 7457                        .into_any()
 7458                }),
 7459                constrain_width: false,
 7460                merge_adjacent: false,
 7461                type_tag: Some(type_id),
 7462            };
 7463            let creases = new_newlines
 7464                .into_iter()
 7465                .map(|range| Crease::simple(range, placeholder.clone()))
 7466                .collect();
 7467            this.update(cx, |this, cx| {
 7468                this.display_map.update(cx, |display_map, cx| {
 7469                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7470                    display_map.fold(creases, cx);
 7471                });
 7472            })
 7473            .ok();
 7474        });
 7475    }
 7476
 7477    #[ztracing::instrument(skip_all)]
 7478    fn refresh_selected_text_highlights(
 7479        &mut self,
 7480        on_buffer_edit: bool,
 7481        window: &mut Window,
 7482        cx: &mut Context<Editor>,
 7483    ) {
 7484        let Some((query_text, query_range)) =
 7485            self.prepare_highlight_query_from_selection(window, cx)
 7486        else {
 7487            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7488            self.quick_selection_highlight_task.take();
 7489            self.debounced_selection_highlight_task.take();
 7490            self.debounced_selection_highlight_complete = false;
 7491            return;
 7492        };
 7493        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7494        let query_changed = self
 7495            .quick_selection_highlight_task
 7496            .as_ref()
 7497            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7498        if query_changed {
 7499            self.debounced_selection_highlight_complete = false;
 7500        }
 7501        if on_buffer_edit || query_changed {
 7502            let multi_buffer_visible_start = self
 7503                .scroll_manager
 7504                .anchor()
 7505                .anchor
 7506                .to_point(&multi_buffer_snapshot);
 7507            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7508                multi_buffer_visible_start
 7509                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7510                Bias::Left,
 7511            );
 7512            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7513            self.quick_selection_highlight_task = Some((
 7514                query_range.clone(),
 7515                self.update_selection_occurrence_highlights(
 7516                    query_text.clone(),
 7517                    query_range.clone(),
 7518                    multi_buffer_visible_range,
 7519                    false,
 7520                    window,
 7521                    cx,
 7522                ),
 7523            ));
 7524        }
 7525        if on_buffer_edit
 7526            || self
 7527                .debounced_selection_highlight_task
 7528                .as_ref()
 7529                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7530        {
 7531            let multi_buffer_start = multi_buffer_snapshot
 7532                .anchor_before(MultiBufferOffset(0))
 7533                .to_point(&multi_buffer_snapshot);
 7534            let multi_buffer_end = multi_buffer_snapshot
 7535                .anchor_after(multi_buffer_snapshot.len())
 7536                .to_point(&multi_buffer_snapshot);
 7537            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7538            self.debounced_selection_highlight_task = Some((
 7539                query_range.clone(),
 7540                self.update_selection_occurrence_highlights(
 7541                    query_text,
 7542                    query_range,
 7543                    multi_buffer_full_range,
 7544                    true,
 7545                    window,
 7546                    cx,
 7547                ),
 7548            ));
 7549        }
 7550    }
 7551
 7552    pub fn refresh_edit_prediction(
 7553        &mut self,
 7554        debounce: bool,
 7555        user_requested: bool,
 7556        window: &mut Window,
 7557        cx: &mut Context<Self>,
 7558    ) -> Option<()> {
 7559        if DisableAiSettings::get_global(cx).disable_ai {
 7560            return None;
 7561        }
 7562
 7563        let provider = self.edit_prediction_provider()?;
 7564        let cursor = self.selections.newest_anchor().head();
 7565        let (buffer, cursor_buffer_position) =
 7566            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7567
 7568        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7569            self.discard_edit_prediction(false, cx);
 7570            return None;
 7571        }
 7572
 7573        self.update_visible_edit_prediction(window, cx);
 7574
 7575        if !user_requested
 7576            && (!self.should_show_edit_predictions()
 7577                || !self.is_focused(window)
 7578                || buffer.read(cx).is_empty())
 7579        {
 7580            self.discard_edit_prediction(false, cx);
 7581            return None;
 7582        }
 7583
 7584        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7585        Some(())
 7586    }
 7587
 7588    fn show_edit_predictions_in_menu(&self) -> bool {
 7589        match self.edit_prediction_settings {
 7590            EditPredictionSettings::Disabled => false,
 7591            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7592        }
 7593    }
 7594
 7595    pub fn edit_predictions_enabled(&self) -> bool {
 7596        match self.edit_prediction_settings {
 7597            EditPredictionSettings::Disabled => false,
 7598            EditPredictionSettings::Enabled { .. } => true,
 7599        }
 7600    }
 7601
 7602    fn edit_prediction_requires_modifier(&self) -> bool {
 7603        match self.edit_prediction_settings {
 7604            EditPredictionSettings::Disabled => false,
 7605            EditPredictionSettings::Enabled {
 7606                preview_requires_modifier,
 7607                ..
 7608            } => preview_requires_modifier,
 7609        }
 7610    }
 7611
 7612    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7613        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7614            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7615            self.discard_edit_prediction(false, cx);
 7616        } else {
 7617            let selection = self.selections.newest_anchor();
 7618            let cursor = selection.head();
 7619
 7620            if let Some((buffer, cursor_buffer_position)) =
 7621                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7622            {
 7623                self.edit_prediction_settings =
 7624                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7625            }
 7626        }
 7627    }
 7628
 7629    fn edit_prediction_settings_at_position(
 7630        &self,
 7631        buffer: &Entity<Buffer>,
 7632        buffer_position: language::Anchor,
 7633        cx: &App,
 7634    ) -> EditPredictionSettings {
 7635        if !self.mode.is_full()
 7636            || !self.show_edit_predictions_override.unwrap_or(true)
 7637            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7638        {
 7639            return EditPredictionSettings::Disabled;
 7640        }
 7641
 7642        let buffer = buffer.read(cx);
 7643
 7644        let file = buffer.file();
 7645
 7646        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7647            return EditPredictionSettings::Disabled;
 7648        };
 7649
 7650        let by_provider = matches!(
 7651            self.menu_edit_predictions_policy,
 7652            MenuEditPredictionsPolicy::ByProvider
 7653        );
 7654
 7655        let show_in_menu = by_provider
 7656            && self
 7657                .edit_prediction_provider
 7658                .as_ref()
 7659                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7660
 7661        let preview_requires_modifier =
 7662            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7663
 7664        EditPredictionSettings::Enabled {
 7665            show_in_menu,
 7666            preview_requires_modifier,
 7667        }
 7668    }
 7669
 7670    fn should_show_edit_predictions(&self) -> bool {
 7671        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7672    }
 7673
 7674    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7675        matches!(
 7676            self.edit_prediction_preview,
 7677            EditPredictionPreview::Active { .. }
 7678        )
 7679    }
 7680
 7681    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7682        let cursor = self.selections.newest_anchor().head();
 7683        if let Some((buffer, cursor_position)) =
 7684            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7685        {
 7686            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7687        } else {
 7688            false
 7689        }
 7690    }
 7691
 7692    pub fn supports_minimap(&self, cx: &App) -> bool {
 7693        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7694    }
 7695
 7696    fn edit_predictions_enabled_in_buffer(
 7697        &self,
 7698        buffer: &Entity<Buffer>,
 7699        buffer_position: language::Anchor,
 7700        cx: &App,
 7701    ) -> bool {
 7702        maybe!({
 7703            if self.read_only(cx) {
 7704                return Some(false);
 7705            }
 7706            let provider = self.edit_prediction_provider()?;
 7707            if !provider.is_enabled(buffer, buffer_position, cx) {
 7708                return Some(false);
 7709            }
 7710            let buffer = buffer.read(cx);
 7711            let Some(file) = buffer.file() else {
 7712                return Some(true);
 7713            };
 7714            let settings = all_language_settings(Some(file), cx);
 7715            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7716        })
 7717        .unwrap_or(false)
 7718    }
 7719
 7720    pub fn show_edit_prediction(
 7721        &mut self,
 7722        _: &ShowEditPrediction,
 7723        window: &mut Window,
 7724        cx: &mut Context<Self>,
 7725    ) {
 7726        if !self.has_active_edit_prediction() {
 7727            self.refresh_edit_prediction(false, true, window, cx);
 7728            return;
 7729        }
 7730
 7731        self.update_visible_edit_prediction(window, cx);
 7732    }
 7733
 7734    pub fn display_cursor_names(
 7735        &mut self,
 7736        _: &DisplayCursorNames,
 7737        window: &mut Window,
 7738        cx: &mut Context<Self>,
 7739    ) {
 7740        self.show_cursor_names(window, cx);
 7741    }
 7742
 7743    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7744        self.show_cursor_names = true;
 7745        cx.notify();
 7746        cx.spawn_in(window, async move |this, cx| {
 7747            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7748            this.update(cx, |this, cx| {
 7749                this.show_cursor_names = false;
 7750                cx.notify()
 7751            })
 7752            .ok()
 7753        })
 7754        .detach();
 7755    }
 7756
 7757    pub fn accept_partial_edit_prediction(
 7758        &mut self,
 7759        granularity: EditPredictionGranularity,
 7760        window: &mut Window,
 7761        cx: &mut Context<Self>,
 7762    ) {
 7763        if self.show_edit_predictions_in_menu() {
 7764            self.hide_context_menu(window, cx);
 7765        }
 7766
 7767        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7768            return;
 7769        };
 7770
 7771        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7772            return;
 7773        }
 7774
 7775        match &active_edit_prediction.completion {
 7776            EditPrediction::MoveWithin { target, .. } => {
 7777                let target = *target;
 7778
 7779                if matches!(granularity, EditPredictionGranularity::Full) {
 7780                    if let Some(position_map) = &self.last_position_map {
 7781                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7782                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7783
 7784                        if is_visible || !self.edit_prediction_requires_modifier() {
 7785                            self.unfold_ranges(&[target..target], true, false, cx);
 7786                            self.change_selections(
 7787                                SelectionEffects::scroll(Autoscroll::newest()),
 7788                                window,
 7789                                cx,
 7790                                |selections| {
 7791                                    selections.select_anchor_ranges([target..target]);
 7792                                },
 7793                            );
 7794                            self.clear_row_highlights::<EditPredictionPreview>();
 7795                            self.edit_prediction_preview
 7796                                .set_previous_scroll_position(None);
 7797                        } else {
 7798                            // Highlight and request scroll
 7799                            self.edit_prediction_preview
 7800                                .set_previous_scroll_position(Some(
 7801                                    position_map.snapshot.scroll_anchor,
 7802                                ));
 7803                            self.highlight_rows::<EditPredictionPreview>(
 7804                                target..target,
 7805                                cx.theme().colors().editor_highlighted_line_background,
 7806                                RowHighlightOptions {
 7807                                    autoscroll: true,
 7808                                    ..Default::default()
 7809                                },
 7810                                cx,
 7811                            );
 7812                            self.request_autoscroll(Autoscroll::fit(), cx);
 7813                        }
 7814                    }
 7815                } else {
 7816                    self.change_selections(
 7817                        SelectionEffects::scroll(Autoscroll::newest()),
 7818                        window,
 7819                        cx,
 7820                        |selections| {
 7821                            selections.select_anchor_ranges([target..target]);
 7822                        },
 7823                    );
 7824                }
 7825            }
 7826            EditPrediction::MoveOutside { snapshot, target } => {
 7827                if let Some(workspace) = self.workspace() {
 7828                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7829                        .detach_and_log_err(cx);
 7830                }
 7831            }
 7832            EditPrediction::Edit { edits, .. } => {
 7833                self.report_edit_prediction_event(
 7834                    active_edit_prediction.completion_id.clone(),
 7835                    true,
 7836                    cx,
 7837                );
 7838
 7839                match granularity {
 7840                    EditPredictionGranularity::Full => {
 7841                        if let Some(provider) = self.edit_prediction_provider() {
 7842                            provider.accept(cx);
 7843                        }
 7844
 7845                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7846                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7847                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7848
 7849                        self.buffer.update(cx, |buffer, cx| {
 7850                            buffer.edit(edits.iter().cloned(), None, cx)
 7851                        });
 7852
 7853                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7854                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7855                        });
 7856
 7857                        let selections = self.selections.disjoint_anchors_arc();
 7858                        if let Some(transaction_id_now) =
 7859                            self.buffer.read(cx).last_transaction_id(cx)
 7860                        {
 7861                            if transaction_id_prev != Some(transaction_id_now) {
 7862                                self.selection_history
 7863                                    .insert_transaction(transaction_id_now, selections);
 7864                            }
 7865                        }
 7866
 7867                        self.update_visible_edit_prediction(window, cx);
 7868                        if self.active_edit_prediction.is_none() {
 7869                            self.refresh_edit_prediction(true, true, window, cx);
 7870                        }
 7871                        cx.notify();
 7872                    }
 7873                    _ => {
 7874                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7875                        let cursor_offset = self
 7876                            .selections
 7877                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7878                            .head();
 7879
 7880                        let insertion = edits.iter().find_map(|(range, text)| {
 7881                            let range = range.to_offset(&snapshot);
 7882                            if range.is_empty() && range.start == cursor_offset {
 7883                                Some(text)
 7884                            } else {
 7885                                None
 7886                            }
 7887                        });
 7888
 7889                        if let Some(text) = insertion {
 7890                            let text_to_insert = match granularity {
 7891                                EditPredictionGranularity::Word => {
 7892                                    let mut partial = text
 7893                                        .chars()
 7894                                        .by_ref()
 7895                                        .take_while(|c| c.is_alphabetic())
 7896                                        .collect::<String>();
 7897                                    if partial.is_empty() {
 7898                                        partial = text
 7899                                            .chars()
 7900                                            .by_ref()
 7901                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7902                                            .collect::<String>();
 7903                                    }
 7904                                    partial
 7905                                }
 7906                                EditPredictionGranularity::Line => {
 7907                                    if let Some(line) = text.split_inclusive('\n').next() {
 7908                                        line.to_string()
 7909                                    } else {
 7910                                        text.to_string()
 7911                                    }
 7912                                }
 7913                                EditPredictionGranularity::Full => unreachable!(),
 7914                            };
 7915
 7916                            cx.emit(EditorEvent::InputHandled {
 7917                                utf16_range_to_replace: None,
 7918                                text: text_to_insert.clone().into(),
 7919                            });
 7920
 7921                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7922                            self.refresh_edit_prediction(true, true, window, cx);
 7923                            cx.notify();
 7924                        } else {
 7925                            self.accept_partial_edit_prediction(
 7926                                EditPredictionGranularity::Full,
 7927                                window,
 7928                                cx,
 7929                            );
 7930                        }
 7931                    }
 7932                }
 7933            }
 7934        }
 7935
 7936        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7937    }
 7938
 7939    pub fn accept_next_word_edit_prediction(
 7940        &mut self,
 7941        _: &AcceptNextWordEditPrediction,
 7942        window: &mut Window,
 7943        cx: &mut Context<Self>,
 7944    ) {
 7945        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7946    }
 7947
 7948    pub fn accept_next_line_edit_prediction(
 7949        &mut self,
 7950        _: &AcceptNextLineEditPrediction,
 7951        window: &mut Window,
 7952        cx: &mut Context<Self>,
 7953    ) {
 7954        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7955    }
 7956
 7957    pub fn accept_edit_prediction(
 7958        &mut self,
 7959        _: &AcceptEditPrediction,
 7960        window: &mut Window,
 7961        cx: &mut Context<Self>,
 7962    ) {
 7963        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7964    }
 7965
 7966    fn discard_edit_prediction(
 7967        &mut self,
 7968        should_report_edit_prediction_event: bool,
 7969        cx: &mut Context<Self>,
 7970    ) -> bool {
 7971        if should_report_edit_prediction_event {
 7972            let completion_id = self
 7973                .active_edit_prediction
 7974                .as_ref()
 7975                .and_then(|active_completion| active_completion.completion_id.clone());
 7976
 7977            self.report_edit_prediction_event(completion_id, false, cx);
 7978        }
 7979
 7980        if let Some(provider) = self.edit_prediction_provider() {
 7981            provider.discard(cx);
 7982        }
 7983
 7984        self.take_active_edit_prediction(cx)
 7985    }
 7986
 7987    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7988        let Some(provider) = self.edit_prediction_provider() else {
 7989            return;
 7990        };
 7991
 7992        let Some((_, buffer, _)) = self
 7993            .buffer
 7994            .read(cx)
 7995            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7996        else {
 7997            return;
 7998        };
 7999
 8000        let extension = buffer
 8001            .read(cx)
 8002            .file()
 8003            .and_then(|file| Some(file.path().extension()?.to_string()));
 8004
 8005        let event_type = match accepted {
 8006            true => "Edit Prediction Accepted",
 8007            false => "Edit Prediction Discarded",
 8008        };
 8009        telemetry::event!(
 8010            event_type,
 8011            provider = provider.name(),
 8012            prediction_id = id,
 8013            suggestion_accepted = accepted,
 8014            file_extension = extension,
 8015        );
 8016    }
 8017
 8018    fn open_editor_at_anchor(
 8019        snapshot: &language::BufferSnapshot,
 8020        target: language::Anchor,
 8021        workspace: &Entity<Workspace>,
 8022        window: &mut Window,
 8023        cx: &mut App,
 8024    ) -> Task<Result<()>> {
 8025        workspace.update(cx, |workspace, cx| {
 8026            let path = snapshot.file().map(|file| file.full_path(cx));
 8027            let Some(path) =
 8028                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8029            else {
 8030                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8031            };
 8032            let target = text::ToPoint::to_point(&target, snapshot);
 8033            let item = workspace.open_path(path, None, true, window, cx);
 8034            window.spawn(cx, async move |cx| {
 8035                let Some(editor) = item.await?.downcast::<Editor>() else {
 8036                    return Ok(());
 8037                };
 8038                editor
 8039                    .update_in(cx, |editor, window, cx| {
 8040                        editor.go_to_singleton_buffer_point(target, window, cx);
 8041                    })
 8042                    .ok();
 8043                anyhow::Ok(())
 8044            })
 8045        })
 8046    }
 8047
 8048    pub fn has_active_edit_prediction(&self) -> bool {
 8049        self.active_edit_prediction.is_some()
 8050    }
 8051
 8052    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 8053        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8054            return false;
 8055        };
 8056
 8057        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8058        self.clear_highlights::<EditPredictionHighlight>(cx);
 8059        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 8060        true
 8061    }
 8062
 8063    /// Returns true when we're displaying the edit prediction popover below the cursor
 8064    /// like we are not previewing and the LSP autocomplete menu is visible
 8065    /// or we are in `when_holding_modifier` mode.
 8066    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8067        if self.edit_prediction_preview_is_active()
 8068            || !self.show_edit_predictions_in_menu()
 8069            || !self.edit_predictions_enabled()
 8070        {
 8071            return false;
 8072        }
 8073
 8074        if self.has_visible_completions_menu() {
 8075            return true;
 8076        }
 8077
 8078        has_completion && self.edit_prediction_requires_modifier()
 8079    }
 8080
 8081    fn handle_modifiers_changed(
 8082        &mut self,
 8083        modifiers: Modifiers,
 8084        position_map: &PositionMap,
 8085        window: &mut Window,
 8086        cx: &mut Context<Self>,
 8087    ) {
 8088        // Ensure that the edit prediction preview is updated, even when not
 8089        // enabled, if there's an active edit prediction preview.
 8090        if self.show_edit_predictions_in_menu()
 8091            || matches!(
 8092                self.edit_prediction_preview,
 8093                EditPredictionPreview::Active { .. }
 8094            )
 8095        {
 8096            self.update_edit_prediction_preview(&modifiers, window, cx);
 8097        }
 8098
 8099        self.update_selection_mode(&modifiers, position_map, window, cx);
 8100
 8101        let mouse_position = window.mouse_position();
 8102        if !position_map.text_hitbox.is_hovered(window) {
 8103            return;
 8104        }
 8105
 8106        self.update_hovered_link(
 8107            position_map.point_for_position(mouse_position),
 8108            &position_map.snapshot,
 8109            modifiers,
 8110            window,
 8111            cx,
 8112        )
 8113    }
 8114
 8115    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8116        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8117            MultiCursorModifier::Alt => modifiers.secondary(),
 8118            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8119        }
 8120    }
 8121
 8122    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8123        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8124            MultiCursorModifier::Alt => modifiers.alt,
 8125            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8126        }
 8127    }
 8128
 8129    fn columnar_selection_mode(
 8130        modifiers: &Modifiers,
 8131        cx: &mut Context<Self>,
 8132    ) -> Option<ColumnarMode> {
 8133        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8134            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8135                Some(ColumnarMode::FromMouse)
 8136            } else if Self::is_alt_pressed(modifiers, cx) {
 8137                Some(ColumnarMode::FromSelection)
 8138            } else {
 8139                None
 8140            }
 8141        } else {
 8142            None
 8143        }
 8144    }
 8145
 8146    fn update_selection_mode(
 8147        &mut self,
 8148        modifiers: &Modifiers,
 8149        position_map: &PositionMap,
 8150        window: &mut Window,
 8151        cx: &mut Context<Self>,
 8152    ) {
 8153        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8154            return;
 8155        };
 8156        if self.selections.pending_anchor().is_none() {
 8157            return;
 8158        }
 8159
 8160        let mouse_position = window.mouse_position();
 8161        let point_for_position = position_map.point_for_position(mouse_position);
 8162        let position = point_for_position.previous_valid;
 8163
 8164        self.select(
 8165            SelectPhase::BeginColumnar {
 8166                position,
 8167                reset: false,
 8168                mode,
 8169                goal_column: point_for_position.exact_unclipped.column(),
 8170            },
 8171            window,
 8172            cx,
 8173        );
 8174    }
 8175
 8176    fn update_edit_prediction_preview(
 8177        &mut self,
 8178        modifiers: &Modifiers,
 8179        window: &mut Window,
 8180        cx: &mut Context<Self>,
 8181    ) {
 8182        let mut modifiers_held = false;
 8183
 8184        // Check bindings for all granularities.
 8185        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8186        let granularities = [
 8187            EditPredictionGranularity::Full,
 8188            EditPredictionGranularity::Line,
 8189            EditPredictionGranularity::Word,
 8190        ];
 8191
 8192        for granularity in granularities {
 8193            if let Some(keystroke) = self
 8194                .accept_edit_prediction_keybind(granularity, window, cx)
 8195                .keystroke()
 8196            {
 8197                modifiers_held = modifiers_held
 8198                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8199            }
 8200        }
 8201
 8202        if modifiers_held {
 8203            if matches!(
 8204                self.edit_prediction_preview,
 8205                EditPredictionPreview::Inactive { .. }
 8206            ) {
 8207                self.edit_prediction_preview = EditPredictionPreview::Active {
 8208                    previous_scroll_position: None,
 8209                    since: Instant::now(),
 8210                };
 8211
 8212                self.update_visible_edit_prediction(window, cx);
 8213                cx.notify();
 8214            }
 8215        } else if let EditPredictionPreview::Active {
 8216            previous_scroll_position,
 8217            since,
 8218        } = self.edit_prediction_preview
 8219        {
 8220            if let (Some(previous_scroll_position), Some(position_map)) =
 8221                (previous_scroll_position, self.last_position_map.as_ref())
 8222            {
 8223                self.set_scroll_position(
 8224                    previous_scroll_position
 8225                        .scroll_position(&position_map.snapshot.display_snapshot),
 8226                    window,
 8227                    cx,
 8228                );
 8229            }
 8230
 8231            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8232                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8233            };
 8234            self.clear_row_highlights::<EditPredictionPreview>();
 8235            self.update_visible_edit_prediction(window, cx);
 8236            cx.notify();
 8237        }
 8238    }
 8239
 8240    fn update_visible_edit_prediction(
 8241        &mut self,
 8242        _window: &mut Window,
 8243        cx: &mut Context<Self>,
 8244    ) -> Option<()> {
 8245        if DisableAiSettings::get_global(cx).disable_ai {
 8246            return None;
 8247        }
 8248
 8249        if self.ime_transaction.is_some() {
 8250            self.discard_edit_prediction(false, cx);
 8251            return None;
 8252        }
 8253
 8254        let selection = self.selections.newest_anchor();
 8255        let cursor = selection.head();
 8256        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8257        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8258        let excerpt_id = cursor.excerpt_id;
 8259
 8260        let show_in_menu = self.show_edit_predictions_in_menu();
 8261        let completions_menu_has_precedence = !show_in_menu
 8262            && (self.context_menu.borrow().is_some()
 8263                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8264
 8265        if completions_menu_has_precedence
 8266            || !offset_selection.is_empty()
 8267            || self
 8268                .active_edit_prediction
 8269                .as_ref()
 8270                .is_some_and(|completion| {
 8271                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8272                        return false;
 8273                    };
 8274                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8275                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8276                    !invalidation_range.contains(&offset_selection.head())
 8277                })
 8278        {
 8279            self.discard_edit_prediction(false, cx);
 8280            return None;
 8281        }
 8282
 8283        self.take_active_edit_prediction(cx);
 8284        let Some(provider) = self.edit_prediction_provider() else {
 8285            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8286            return None;
 8287        };
 8288
 8289        let (buffer, cursor_buffer_position) =
 8290            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8291
 8292        self.edit_prediction_settings =
 8293            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8294
 8295        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8296
 8297        if self.edit_prediction_indent_conflict {
 8298            let cursor_point = cursor.to_point(&multibuffer);
 8299            let mut suggested_indent = None;
 8300            multibuffer.suggested_indents_callback(
 8301                cursor_point.row..cursor_point.row + 1,
 8302                |_, indent| {
 8303                    suggested_indent = Some(indent);
 8304                    ControlFlow::Break(())
 8305                },
 8306                cx,
 8307            );
 8308
 8309            if let Some(indent) = suggested_indent
 8310                && indent.len == cursor_point.column
 8311            {
 8312                self.edit_prediction_indent_conflict = false;
 8313            }
 8314        }
 8315
 8316        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8317
 8318        let (completion_id, edits, edit_preview) = match edit_prediction {
 8319            edit_prediction_types::EditPrediction::Local {
 8320                id,
 8321                edits,
 8322                edit_preview,
 8323            } => (id, edits, edit_preview),
 8324            edit_prediction_types::EditPrediction::Jump {
 8325                id,
 8326                snapshot,
 8327                target,
 8328            } => {
 8329                if let Some(provider) = &self.edit_prediction_provider {
 8330                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8331                }
 8332                self.stale_edit_prediction_in_menu = None;
 8333                self.active_edit_prediction = Some(EditPredictionState {
 8334                    inlay_ids: vec![],
 8335                    completion: EditPrediction::MoveOutside { snapshot, target },
 8336                    completion_id: id,
 8337                    invalidation_range: None,
 8338                });
 8339                cx.notify();
 8340                return Some(());
 8341            }
 8342        };
 8343
 8344        let edits = edits
 8345            .into_iter()
 8346            .flat_map(|(range, new_text)| {
 8347                Some((
 8348                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8349                    new_text,
 8350                ))
 8351            })
 8352            .collect::<Vec<_>>();
 8353        if edits.is_empty() {
 8354            return None;
 8355        }
 8356
 8357        let first_edit_start = edits.first().unwrap().0.start;
 8358        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8359        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8360
 8361        let last_edit_end = edits.last().unwrap().0.end;
 8362        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8363        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8364
 8365        let cursor_row = cursor.to_point(&multibuffer).row;
 8366
 8367        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8368
 8369        let mut inlay_ids = Vec::new();
 8370        let invalidation_row_range;
 8371        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8372            Some(cursor_row..edit_end_row)
 8373        } else if cursor_row > edit_end_row {
 8374            Some(edit_start_row..cursor_row)
 8375        } else {
 8376            None
 8377        };
 8378        let supports_jump = self
 8379            .edit_prediction_provider
 8380            .as_ref()
 8381            .map(|provider| provider.provider.supports_jump_to_edit())
 8382            .unwrap_or(true);
 8383
 8384        let is_move = supports_jump
 8385            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8386        let completion = if is_move {
 8387            if let Some(provider) = &self.edit_prediction_provider {
 8388                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8389            }
 8390            invalidation_row_range =
 8391                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8392            let target = first_edit_start;
 8393            EditPrediction::MoveWithin { target, snapshot }
 8394        } else {
 8395            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8396                && !self.edit_predictions_hidden_for_vim_mode;
 8397
 8398            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8399                if provider.show_tab_accept_marker() {
 8400                    EditDisplayMode::TabAccept
 8401                } else {
 8402                    EditDisplayMode::Inline
 8403                }
 8404            } else {
 8405                EditDisplayMode::DiffPopover
 8406            };
 8407
 8408            if show_completions_in_buffer {
 8409                if let Some(provider) = &self.edit_prediction_provider {
 8410                    let suggestion_display_type = match display_mode {
 8411                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8412                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8413                            SuggestionDisplayType::GhostText
 8414                        }
 8415                    };
 8416                    provider.provider.did_show(suggestion_display_type, cx);
 8417                }
 8418                if edits
 8419                    .iter()
 8420                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8421                {
 8422                    let mut inlays = Vec::new();
 8423                    for (range, new_text) in &edits {
 8424                        let inlay = Inlay::edit_prediction(
 8425                            post_inc(&mut self.next_inlay_id),
 8426                            range.start,
 8427                            new_text.as_ref(),
 8428                        );
 8429                        inlay_ids.push(inlay.id);
 8430                        inlays.push(inlay);
 8431                    }
 8432
 8433                    self.splice_inlays(&[], inlays, cx);
 8434                } else {
 8435                    let background_color = cx.theme().status().deleted_background;
 8436                    self.highlight_text::<EditPredictionHighlight>(
 8437                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8438                        HighlightStyle {
 8439                            background_color: Some(background_color),
 8440                            ..Default::default()
 8441                        },
 8442                        cx,
 8443                    );
 8444                }
 8445            }
 8446
 8447            invalidation_row_range = edit_start_row..edit_end_row;
 8448
 8449            EditPrediction::Edit {
 8450                edits,
 8451                edit_preview,
 8452                display_mode,
 8453                snapshot,
 8454            }
 8455        };
 8456
 8457        let invalidation_range = multibuffer
 8458            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8459            ..multibuffer.anchor_after(Point::new(
 8460                invalidation_row_range.end,
 8461                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8462            ));
 8463
 8464        self.stale_edit_prediction_in_menu = None;
 8465        self.active_edit_prediction = Some(EditPredictionState {
 8466            inlay_ids,
 8467            completion,
 8468            completion_id,
 8469            invalidation_range: Some(invalidation_range),
 8470        });
 8471
 8472        cx.notify();
 8473
 8474        Some(())
 8475    }
 8476
 8477    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8478        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8479    }
 8480
 8481    fn clear_tasks(&mut self) {
 8482        self.tasks.clear()
 8483    }
 8484
 8485    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8486        if self.tasks.insert(key, value).is_some() {
 8487            // This case should hopefully be rare, but just in case...
 8488            log::error!(
 8489                "multiple different run targets found on a single line, only the last target will be rendered"
 8490            )
 8491        }
 8492    }
 8493
 8494    /// Get all display points of breakpoints that will be rendered within editor
 8495    ///
 8496    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8497    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8498    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8499    fn active_breakpoints(
 8500        &self,
 8501        range: Range<DisplayRow>,
 8502        window: &mut Window,
 8503        cx: &mut Context<Self>,
 8504    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8505        let mut breakpoint_display_points = HashMap::default();
 8506
 8507        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8508            return breakpoint_display_points;
 8509        };
 8510
 8511        let snapshot = self.snapshot(window, cx);
 8512
 8513        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8514        let Some(project) = self.project() else {
 8515            return breakpoint_display_points;
 8516        };
 8517
 8518        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8519            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8520
 8521        for (buffer_snapshot, range, excerpt_id) in
 8522            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8523        {
 8524            let Some(buffer) = project
 8525                .read(cx)
 8526                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8527            else {
 8528                continue;
 8529            };
 8530            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8531                &buffer,
 8532                Some(
 8533                    buffer_snapshot.anchor_before(range.start)
 8534                        ..buffer_snapshot.anchor_after(range.end),
 8535                ),
 8536                buffer_snapshot,
 8537                cx,
 8538            );
 8539            for (breakpoint, state) in breakpoints {
 8540                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8541                let position = multi_buffer_anchor
 8542                    .to_point(&multi_buffer_snapshot)
 8543                    .to_display_point(&snapshot);
 8544
 8545                breakpoint_display_points.insert(
 8546                    position.row(),
 8547                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8548                );
 8549            }
 8550        }
 8551
 8552        breakpoint_display_points
 8553    }
 8554
 8555    fn breakpoint_context_menu(
 8556        &self,
 8557        anchor: Anchor,
 8558        window: &mut Window,
 8559        cx: &mut Context<Self>,
 8560    ) -> Entity<ui::ContextMenu> {
 8561        let weak_editor = cx.weak_entity();
 8562        let focus_handle = self.focus_handle(cx);
 8563
 8564        let row = self
 8565            .buffer
 8566            .read(cx)
 8567            .snapshot(cx)
 8568            .summary_for_anchor::<Point>(&anchor)
 8569            .row;
 8570
 8571        let breakpoint = self
 8572            .breakpoint_at_row(row, window, cx)
 8573            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8574
 8575        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8576            "Edit Log Breakpoint"
 8577        } else {
 8578            "Set Log Breakpoint"
 8579        };
 8580
 8581        let condition_breakpoint_msg = if breakpoint
 8582            .as_ref()
 8583            .is_some_and(|bp| bp.1.condition.is_some())
 8584        {
 8585            "Edit Condition Breakpoint"
 8586        } else {
 8587            "Set Condition Breakpoint"
 8588        };
 8589
 8590        let hit_condition_breakpoint_msg = if breakpoint
 8591            .as_ref()
 8592            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8593        {
 8594            "Edit Hit Condition Breakpoint"
 8595        } else {
 8596            "Set Hit Condition Breakpoint"
 8597        };
 8598
 8599        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8600            "Unset Breakpoint"
 8601        } else {
 8602            "Set Breakpoint"
 8603        };
 8604
 8605        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8606
 8607        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8608            BreakpointState::Enabled => Some("Disable"),
 8609            BreakpointState::Disabled => Some("Enable"),
 8610        });
 8611
 8612        let (anchor, breakpoint) =
 8613            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8614
 8615        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8616            menu.on_blur_subscription(Subscription::new(|| {}))
 8617                .context(focus_handle)
 8618                .when(run_to_cursor, |this| {
 8619                    let weak_editor = weak_editor.clone();
 8620                    this.entry("Run to cursor", None, move |window, cx| {
 8621                        weak_editor
 8622                            .update(cx, |editor, cx| {
 8623                                editor.change_selections(
 8624                                    SelectionEffects::no_scroll(),
 8625                                    window,
 8626                                    cx,
 8627                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8628                                );
 8629                            })
 8630                            .ok();
 8631
 8632                        window.dispatch_action(Box::new(RunToCursor), cx);
 8633                    })
 8634                    .separator()
 8635                })
 8636                .when_some(toggle_state_msg, |this, msg| {
 8637                    this.entry(msg, None, {
 8638                        let weak_editor = weak_editor.clone();
 8639                        let breakpoint = breakpoint.clone();
 8640                        move |_window, cx| {
 8641                            weak_editor
 8642                                .update(cx, |this, cx| {
 8643                                    this.edit_breakpoint_at_anchor(
 8644                                        anchor,
 8645                                        breakpoint.as_ref().clone(),
 8646                                        BreakpointEditAction::InvertState,
 8647                                        cx,
 8648                                    );
 8649                                })
 8650                                .log_err();
 8651                        }
 8652                    })
 8653                })
 8654                .entry(set_breakpoint_msg, None, {
 8655                    let weak_editor = weak_editor.clone();
 8656                    let breakpoint = breakpoint.clone();
 8657                    move |_window, cx| {
 8658                        weak_editor
 8659                            .update(cx, |this, cx| {
 8660                                this.edit_breakpoint_at_anchor(
 8661                                    anchor,
 8662                                    breakpoint.as_ref().clone(),
 8663                                    BreakpointEditAction::Toggle,
 8664                                    cx,
 8665                                );
 8666                            })
 8667                            .log_err();
 8668                    }
 8669                })
 8670                .entry(log_breakpoint_msg, None, {
 8671                    let breakpoint = breakpoint.clone();
 8672                    let weak_editor = weak_editor.clone();
 8673                    move |window, cx| {
 8674                        weak_editor
 8675                            .update(cx, |this, cx| {
 8676                                this.add_edit_breakpoint_block(
 8677                                    anchor,
 8678                                    breakpoint.as_ref(),
 8679                                    BreakpointPromptEditAction::Log,
 8680                                    window,
 8681                                    cx,
 8682                                );
 8683                            })
 8684                            .log_err();
 8685                    }
 8686                })
 8687                .entry(condition_breakpoint_msg, None, {
 8688                    let breakpoint = breakpoint.clone();
 8689                    let weak_editor = weak_editor.clone();
 8690                    move |window, cx| {
 8691                        weak_editor
 8692                            .update(cx, |this, cx| {
 8693                                this.add_edit_breakpoint_block(
 8694                                    anchor,
 8695                                    breakpoint.as_ref(),
 8696                                    BreakpointPromptEditAction::Condition,
 8697                                    window,
 8698                                    cx,
 8699                                );
 8700                            })
 8701                            .log_err();
 8702                    }
 8703                })
 8704                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8705                    weak_editor
 8706                        .update(cx, |this, cx| {
 8707                            this.add_edit_breakpoint_block(
 8708                                anchor,
 8709                                breakpoint.as_ref(),
 8710                                BreakpointPromptEditAction::HitCondition,
 8711                                window,
 8712                                cx,
 8713                            );
 8714                        })
 8715                        .log_err();
 8716                })
 8717        })
 8718    }
 8719
 8720    fn render_breakpoint(
 8721        &self,
 8722        position: Anchor,
 8723        row: DisplayRow,
 8724        breakpoint: &Breakpoint,
 8725        state: Option<BreakpointSessionState>,
 8726        cx: &mut Context<Self>,
 8727    ) -> IconButton {
 8728        let is_rejected = state.is_some_and(|s| !s.verified);
 8729        // Is it a breakpoint that shows up when hovering over gutter?
 8730        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8731            (false, false),
 8732            |PhantomBreakpointIndicator {
 8733                 is_active,
 8734                 display_row,
 8735                 collides_with_existing_breakpoint,
 8736             }| {
 8737                (
 8738                    is_active && display_row == row,
 8739                    collides_with_existing_breakpoint,
 8740                )
 8741            },
 8742        );
 8743
 8744        let (color, icon) = {
 8745            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8746                (false, false) => ui::IconName::DebugBreakpoint,
 8747                (true, false) => ui::IconName::DebugLogBreakpoint,
 8748                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8749                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8750            };
 8751
 8752            let theme_colors = cx.theme().colors();
 8753
 8754            let color = if is_phantom {
 8755                if collides_with_existing {
 8756                    Color::Custom(
 8757                        theme_colors
 8758                            .debugger_accent
 8759                            .blend(theme_colors.text.opacity(0.6)),
 8760                    )
 8761                } else {
 8762                    Color::Hint
 8763                }
 8764            } else if is_rejected {
 8765                Color::Disabled
 8766            } else {
 8767                Color::Debugger
 8768            };
 8769
 8770            (color, icon)
 8771        };
 8772
 8773        let breakpoint = Arc::from(breakpoint.clone());
 8774
 8775        let alt_as_text = gpui::Keystroke {
 8776            modifiers: Modifiers::secondary_key(),
 8777            ..Default::default()
 8778        };
 8779        let primary_action_text = if breakpoint.is_disabled() {
 8780            "Enable breakpoint"
 8781        } else if is_phantom && !collides_with_existing {
 8782            "Set breakpoint"
 8783        } else {
 8784            "Unset breakpoint"
 8785        };
 8786        let focus_handle = self.focus_handle.clone();
 8787
 8788        let meta = if is_rejected {
 8789            SharedString::from("No executable code is associated with this line.")
 8790        } else if collides_with_existing && !breakpoint.is_disabled() {
 8791            SharedString::from(format!(
 8792                "{alt_as_text}-click to disable,\nright-click for more options."
 8793            ))
 8794        } else {
 8795            SharedString::from("Right-click for more options.")
 8796        };
 8797        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8798            .icon_size(IconSize::XSmall)
 8799            .size(ui::ButtonSize::None)
 8800            .when(is_rejected, |this| {
 8801                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8802            })
 8803            .icon_color(color)
 8804            .style(ButtonStyle::Transparent)
 8805            .on_click(cx.listener({
 8806                move |editor, event: &ClickEvent, window, cx| {
 8807                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8808                        BreakpointEditAction::InvertState
 8809                    } else {
 8810                        BreakpointEditAction::Toggle
 8811                    };
 8812
 8813                    window.focus(&editor.focus_handle(cx), cx);
 8814                    editor.edit_breakpoint_at_anchor(
 8815                        position,
 8816                        breakpoint.as_ref().clone(),
 8817                        edit_action,
 8818                        cx,
 8819                    );
 8820                }
 8821            }))
 8822            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8823                editor.set_breakpoint_context_menu(
 8824                    row,
 8825                    Some(position),
 8826                    event.position(),
 8827                    window,
 8828                    cx,
 8829                );
 8830            }))
 8831            .tooltip(move |_window, cx| {
 8832                Tooltip::with_meta_in(
 8833                    primary_action_text,
 8834                    Some(&ToggleBreakpoint),
 8835                    meta.clone(),
 8836                    &focus_handle,
 8837                    cx,
 8838                )
 8839            })
 8840    }
 8841
 8842    fn build_tasks_context(
 8843        project: &Entity<Project>,
 8844        buffer: &Entity<Buffer>,
 8845        buffer_row: u32,
 8846        tasks: &Arc<RunnableTasks>,
 8847        cx: &mut Context<Self>,
 8848    ) -> Task<Option<task::TaskContext>> {
 8849        let position = Point::new(buffer_row, tasks.column);
 8850        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8851        let location = Location {
 8852            buffer: buffer.clone(),
 8853            range: range_start..range_start,
 8854        };
 8855        // Fill in the environmental variables from the tree-sitter captures
 8856        let mut captured_task_variables = TaskVariables::default();
 8857        for (capture_name, value) in tasks.extra_variables.clone() {
 8858            captured_task_variables.insert(
 8859                task::VariableName::Custom(capture_name.into()),
 8860                value.clone(),
 8861            );
 8862        }
 8863        project.update(cx, |project, cx| {
 8864            project.task_store().update(cx, |task_store, cx| {
 8865                task_store.task_context_for_location(captured_task_variables, location, cx)
 8866            })
 8867        })
 8868    }
 8869
 8870    pub fn spawn_nearest_task(
 8871        &mut self,
 8872        action: &SpawnNearestTask,
 8873        window: &mut Window,
 8874        cx: &mut Context<Self>,
 8875    ) {
 8876        let Some((workspace, _)) = self.workspace.clone() else {
 8877            return;
 8878        };
 8879        let Some(project) = self.project.clone() else {
 8880            return;
 8881        };
 8882
 8883        // Try to find a closest, enclosing node using tree-sitter that has a task
 8884        let Some((buffer, buffer_row, tasks)) = self
 8885            .find_enclosing_node_task(cx)
 8886            // Or find the task that's closest in row-distance.
 8887            .or_else(|| self.find_closest_task(cx))
 8888        else {
 8889            return;
 8890        };
 8891
 8892        let reveal_strategy = action.reveal;
 8893        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8894        cx.spawn_in(window, async move |_, cx| {
 8895            let context = task_context.await?;
 8896            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8897
 8898            let resolved = &mut resolved_task.resolved;
 8899            resolved.reveal = reveal_strategy;
 8900
 8901            workspace
 8902                .update_in(cx, |workspace, window, cx| {
 8903                    workspace.schedule_resolved_task(
 8904                        task_source_kind,
 8905                        resolved_task,
 8906                        false,
 8907                        window,
 8908                        cx,
 8909                    );
 8910                })
 8911                .ok()
 8912        })
 8913        .detach();
 8914    }
 8915
 8916    fn find_closest_task(
 8917        &mut self,
 8918        cx: &mut Context<Self>,
 8919    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8920        let cursor_row = self
 8921            .selections
 8922            .newest_adjusted(&self.display_snapshot(cx))
 8923            .head()
 8924            .row;
 8925
 8926        let ((buffer_id, row), tasks) = self
 8927            .tasks
 8928            .iter()
 8929            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8930
 8931        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8932        let tasks = Arc::new(tasks.to_owned());
 8933        Some((buffer, *row, tasks))
 8934    }
 8935
 8936    fn find_enclosing_node_task(
 8937        &mut self,
 8938        cx: &mut Context<Self>,
 8939    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8940        let snapshot = self.buffer.read(cx).snapshot(cx);
 8941        let offset = self
 8942            .selections
 8943            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8944            .head();
 8945        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8946        let offset = excerpt.map_offset_to_buffer(offset);
 8947        let buffer_id = excerpt.buffer().remote_id();
 8948
 8949        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8950        let mut cursor = layer.node().walk();
 8951
 8952        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8953            if cursor.node().end_byte() == offset.0 {
 8954                cursor.goto_next_sibling();
 8955            }
 8956        }
 8957
 8958        // Ascend to the smallest ancestor that contains the range and has a task.
 8959        loop {
 8960            let node = cursor.node();
 8961            let node_range = node.byte_range();
 8962            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8963
 8964            // Check if this node contains our offset
 8965            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8966                // If it contains offset, check for task
 8967                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8968                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8969                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8970                }
 8971            }
 8972
 8973            if !cursor.goto_parent() {
 8974                break;
 8975            }
 8976        }
 8977        None
 8978    }
 8979
 8980    fn render_run_indicator(
 8981        &self,
 8982        _style: &EditorStyle,
 8983        is_active: bool,
 8984        row: DisplayRow,
 8985        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8986        cx: &mut Context<Self>,
 8987    ) -> IconButton {
 8988        let color = Color::Muted;
 8989        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8990
 8991        IconButton::new(
 8992            ("run_indicator", row.0 as usize),
 8993            ui::IconName::PlayOutlined,
 8994        )
 8995        .shape(ui::IconButtonShape::Square)
 8996        .icon_size(IconSize::XSmall)
 8997        .icon_color(color)
 8998        .toggle_state(is_active)
 8999        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 9000            let quick_launch = match e {
 9001                ClickEvent::Keyboard(_) => true,
 9002                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 9003            };
 9004
 9005            window.focus(&editor.focus_handle(cx), cx);
 9006            editor.toggle_code_actions(
 9007                &ToggleCodeActions {
 9008                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 9009                    quick_launch,
 9010                },
 9011                window,
 9012                cx,
 9013            );
 9014        }))
 9015        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9016            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 9017        }))
 9018    }
 9019
 9020    pub fn context_menu_visible(&self) -> bool {
 9021        !self.edit_prediction_preview_is_active()
 9022            && self
 9023                .context_menu
 9024                .borrow()
 9025                .as_ref()
 9026                .is_some_and(|menu| menu.visible())
 9027    }
 9028
 9029    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9030        self.context_menu
 9031            .borrow()
 9032            .as_ref()
 9033            .map(|menu| menu.origin())
 9034    }
 9035
 9036    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9037        self.context_menu_options = Some(options);
 9038    }
 9039
 9040    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9041    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9042
 9043    fn render_edit_prediction_popover(
 9044        &mut self,
 9045        text_bounds: &Bounds<Pixels>,
 9046        content_origin: gpui::Point<Pixels>,
 9047        right_margin: Pixels,
 9048        editor_snapshot: &EditorSnapshot,
 9049        visible_row_range: Range<DisplayRow>,
 9050        scroll_top: ScrollOffset,
 9051        scroll_bottom: ScrollOffset,
 9052        line_layouts: &[LineWithInvisibles],
 9053        line_height: Pixels,
 9054        scroll_position: gpui::Point<ScrollOffset>,
 9055        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9056        newest_selection_head: Option<DisplayPoint>,
 9057        editor_width: Pixels,
 9058        style: &EditorStyle,
 9059        window: &mut Window,
 9060        cx: &mut App,
 9061    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9062        if self.mode().is_minimap() {
 9063            return None;
 9064        }
 9065        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9066
 9067        if self.edit_prediction_visible_in_cursor_popover(true) {
 9068            return None;
 9069        }
 9070
 9071        match &active_edit_prediction.completion {
 9072            EditPrediction::MoveWithin { target, .. } => {
 9073                let target_display_point = target.to_display_point(editor_snapshot);
 9074
 9075                if self.edit_prediction_requires_modifier() {
 9076                    if !self.edit_prediction_preview_is_active() {
 9077                        return None;
 9078                    }
 9079
 9080                    self.render_edit_prediction_modifier_jump_popover(
 9081                        text_bounds,
 9082                        content_origin,
 9083                        visible_row_range,
 9084                        line_layouts,
 9085                        line_height,
 9086                        scroll_pixel_position,
 9087                        newest_selection_head,
 9088                        target_display_point,
 9089                        window,
 9090                        cx,
 9091                    )
 9092                } else {
 9093                    self.render_edit_prediction_eager_jump_popover(
 9094                        text_bounds,
 9095                        content_origin,
 9096                        editor_snapshot,
 9097                        visible_row_range,
 9098                        scroll_top,
 9099                        scroll_bottom,
 9100                        line_height,
 9101                        scroll_pixel_position,
 9102                        target_display_point,
 9103                        editor_width,
 9104                        window,
 9105                        cx,
 9106                    )
 9107                }
 9108            }
 9109            EditPrediction::Edit {
 9110                display_mode: EditDisplayMode::Inline,
 9111                ..
 9112            } => None,
 9113            EditPrediction::Edit {
 9114                display_mode: EditDisplayMode::TabAccept,
 9115                edits,
 9116                ..
 9117            } => {
 9118                let range = &edits.first()?.0;
 9119                let target_display_point = range.end.to_display_point(editor_snapshot);
 9120
 9121                self.render_edit_prediction_end_of_line_popover(
 9122                    "Accept",
 9123                    editor_snapshot,
 9124                    visible_row_range,
 9125                    target_display_point,
 9126                    line_height,
 9127                    scroll_pixel_position,
 9128                    content_origin,
 9129                    editor_width,
 9130                    window,
 9131                    cx,
 9132                )
 9133            }
 9134            EditPrediction::Edit {
 9135                edits,
 9136                edit_preview,
 9137                display_mode: EditDisplayMode::DiffPopover,
 9138                snapshot,
 9139            } => self.render_edit_prediction_diff_popover(
 9140                text_bounds,
 9141                content_origin,
 9142                right_margin,
 9143                editor_snapshot,
 9144                visible_row_range,
 9145                line_layouts,
 9146                line_height,
 9147                scroll_position,
 9148                scroll_pixel_position,
 9149                newest_selection_head,
 9150                editor_width,
 9151                style,
 9152                edits,
 9153                edit_preview,
 9154                snapshot,
 9155                window,
 9156                cx,
 9157            ),
 9158            EditPrediction::MoveOutside { snapshot, .. } => {
 9159                let mut element = self
 9160                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9161                    .into_any();
 9162
 9163                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9164                let origin_x = text_bounds.size.width - size.width - px(30.);
 9165                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9166                element.prepaint_at(origin, window, cx);
 9167
 9168                Some((element, origin))
 9169            }
 9170        }
 9171    }
 9172
 9173    fn render_edit_prediction_modifier_jump_popover(
 9174        &mut self,
 9175        text_bounds: &Bounds<Pixels>,
 9176        content_origin: gpui::Point<Pixels>,
 9177        visible_row_range: Range<DisplayRow>,
 9178        line_layouts: &[LineWithInvisibles],
 9179        line_height: Pixels,
 9180        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9181        newest_selection_head: Option<DisplayPoint>,
 9182        target_display_point: DisplayPoint,
 9183        window: &mut Window,
 9184        cx: &mut App,
 9185    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9186        let scrolled_content_origin =
 9187            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9188
 9189        const SCROLL_PADDING_Y: Pixels = px(12.);
 9190
 9191        if target_display_point.row() < visible_row_range.start {
 9192            return self.render_edit_prediction_scroll_popover(
 9193                |_| SCROLL_PADDING_Y,
 9194                IconName::ArrowUp,
 9195                visible_row_range,
 9196                line_layouts,
 9197                newest_selection_head,
 9198                scrolled_content_origin,
 9199                window,
 9200                cx,
 9201            );
 9202        } else if target_display_point.row() >= visible_row_range.end {
 9203            return self.render_edit_prediction_scroll_popover(
 9204                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9205                IconName::ArrowDown,
 9206                visible_row_range,
 9207                line_layouts,
 9208                newest_selection_head,
 9209                scrolled_content_origin,
 9210                window,
 9211                cx,
 9212            );
 9213        }
 9214
 9215        const POLE_WIDTH: Pixels = px(2.);
 9216
 9217        let line_layout =
 9218            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9219        let target_column = target_display_point.column() as usize;
 9220
 9221        let target_x = line_layout.x_for_index(target_column);
 9222        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9223            - scroll_pixel_position.y;
 9224
 9225        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9226
 9227        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9228        border_color.l += 0.001;
 9229
 9230        let mut element = v_flex()
 9231            .items_end()
 9232            .when(flag_on_right, |el| el.items_start())
 9233            .child(if flag_on_right {
 9234                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9235                    .rounded_bl(px(0.))
 9236                    .rounded_tl(px(0.))
 9237                    .border_l_2()
 9238                    .border_color(border_color)
 9239            } else {
 9240                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9241                    .rounded_br(px(0.))
 9242                    .rounded_tr(px(0.))
 9243                    .border_r_2()
 9244                    .border_color(border_color)
 9245            })
 9246            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9247            .into_any();
 9248
 9249        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9250
 9251        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9252            - point(
 9253                if flag_on_right {
 9254                    POLE_WIDTH
 9255                } else {
 9256                    size.width - POLE_WIDTH
 9257                },
 9258                size.height - line_height,
 9259            );
 9260
 9261        origin.x = origin.x.max(content_origin.x);
 9262
 9263        element.prepaint_at(origin, window, cx);
 9264
 9265        Some((element, origin))
 9266    }
 9267
 9268    fn render_edit_prediction_scroll_popover(
 9269        &mut self,
 9270        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9271        scroll_icon: IconName,
 9272        visible_row_range: Range<DisplayRow>,
 9273        line_layouts: &[LineWithInvisibles],
 9274        newest_selection_head: Option<DisplayPoint>,
 9275        scrolled_content_origin: gpui::Point<Pixels>,
 9276        window: &mut Window,
 9277        cx: &mut App,
 9278    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9279        let mut element = self
 9280            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9281            .into_any();
 9282
 9283        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9284
 9285        let cursor = newest_selection_head?;
 9286        let cursor_row_layout =
 9287            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9288        let cursor_column = cursor.column() as usize;
 9289
 9290        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9291
 9292        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9293
 9294        element.prepaint_at(origin, window, cx);
 9295        Some((element, origin))
 9296    }
 9297
 9298    fn render_edit_prediction_eager_jump_popover(
 9299        &mut self,
 9300        text_bounds: &Bounds<Pixels>,
 9301        content_origin: gpui::Point<Pixels>,
 9302        editor_snapshot: &EditorSnapshot,
 9303        visible_row_range: Range<DisplayRow>,
 9304        scroll_top: ScrollOffset,
 9305        scroll_bottom: ScrollOffset,
 9306        line_height: Pixels,
 9307        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9308        target_display_point: DisplayPoint,
 9309        editor_width: Pixels,
 9310        window: &mut Window,
 9311        cx: &mut App,
 9312    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9313        if target_display_point.row().as_f64() < scroll_top {
 9314            let mut element = self
 9315                .render_edit_prediction_line_popover(
 9316                    "Jump to Edit",
 9317                    Some(IconName::ArrowUp),
 9318                    window,
 9319                    cx,
 9320                )
 9321                .into_any();
 9322
 9323            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9324            let offset = point(
 9325                (text_bounds.size.width - size.width) / 2.,
 9326                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9327            );
 9328
 9329            let origin = text_bounds.origin + offset;
 9330            element.prepaint_at(origin, window, cx);
 9331            Some((element, origin))
 9332        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9333            let mut element = self
 9334                .render_edit_prediction_line_popover(
 9335                    "Jump to Edit",
 9336                    Some(IconName::ArrowDown),
 9337                    window,
 9338                    cx,
 9339                )
 9340                .into_any();
 9341
 9342            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9343            let offset = point(
 9344                (text_bounds.size.width - size.width) / 2.,
 9345                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9346            );
 9347
 9348            let origin = text_bounds.origin + offset;
 9349            element.prepaint_at(origin, window, cx);
 9350            Some((element, origin))
 9351        } else {
 9352            self.render_edit_prediction_end_of_line_popover(
 9353                "Jump to Edit",
 9354                editor_snapshot,
 9355                visible_row_range,
 9356                target_display_point,
 9357                line_height,
 9358                scroll_pixel_position,
 9359                content_origin,
 9360                editor_width,
 9361                window,
 9362                cx,
 9363            )
 9364        }
 9365    }
 9366
 9367    fn render_edit_prediction_end_of_line_popover(
 9368        self: &mut Editor,
 9369        label: &'static str,
 9370        editor_snapshot: &EditorSnapshot,
 9371        visible_row_range: Range<DisplayRow>,
 9372        target_display_point: DisplayPoint,
 9373        line_height: Pixels,
 9374        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9375        content_origin: gpui::Point<Pixels>,
 9376        editor_width: Pixels,
 9377        window: &mut Window,
 9378        cx: &mut App,
 9379    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9380        let target_line_end = DisplayPoint::new(
 9381            target_display_point.row(),
 9382            editor_snapshot.line_len(target_display_point.row()),
 9383        );
 9384
 9385        let mut element = self
 9386            .render_edit_prediction_line_popover(label, None, window, cx)
 9387            .into_any();
 9388
 9389        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9390
 9391        let line_origin =
 9392            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9393
 9394        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9395        let mut origin = start_point
 9396            + line_origin
 9397            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9398        origin.x = origin.x.max(content_origin.x);
 9399
 9400        let max_x = content_origin.x + editor_width - size.width;
 9401
 9402        if origin.x > max_x {
 9403            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9404
 9405            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9406                origin.y += offset;
 9407                IconName::ArrowUp
 9408            } else {
 9409                origin.y -= offset;
 9410                IconName::ArrowDown
 9411            };
 9412
 9413            element = self
 9414                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9415                .into_any();
 9416
 9417            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9418
 9419            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9420        }
 9421
 9422        element.prepaint_at(origin, window, cx);
 9423        Some((element, origin))
 9424    }
 9425
 9426    fn render_edit_prediction_diff_popover(
 9427        self: &Editor,
 9428        text_bounds: &Bounds<Pixels>,
 9429        content_origin: gpui::Point<Pixels>,
 9430        right_margin: Pixels,
 9431        editor_snapshot: &EditorSnapshot,
 9432        visible_row_range: Range<DisplayRow>,
 9433        line_layouts: &[LineWithInvisibles],
 9434        line_height: Pixels,
 9435        scroll_position: gpui::Point<ScrollOffset>,
 9436        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9437        newest_selection_head: Option<DisplayPoint>,
 9438        editor_width: Pixels,
 9439        style: &EditorStyle,
 9440        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9441        edit_preview: &Option<language::EditPreview>,
 9442        snapshot: &language::BufferSnapshot,
 9443        window: &mut Window,
 9444        cx: &mut App,
 9445    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9446        let edit_start = edits
 9447            .first()
 9448            .unwrap()
 9449            .0
 9450            .start
 9451            .to_display_point(editor_snapshot);
 9452        let edit_end = edits
 9453            .last()
 9454            .unwrap()
 9455            .0
 9456            .end
 9457            .to_display_point(editor_snapshot);
 9458
 9459        let is_visible = visible_row_range.contains(&edit_start.row())
 9460            || visible_row_range.contains(&edit_end.row());
 9461        if !is_visible {
 9462            return None;
 9463        }
 9464
 9465        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9466            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9467        } else {
 9468            // Fallback for providers without edit_preview
 9469            crate::edit_prediction_fallback_text(edits, cx)
 9470        };
 9471
 9472        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9473        let line_count = highlighted_edits.text.lines().count();
 9474
 9475        const BORDER_WIDTH: Pixels = px(1.);
 9476
 9477        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9478        let has_keybind = keybind.is_some();
 9479
 9480        let mut element = h_flex()
 9481            .items_start()
 9482            .child(
 9483                h_flex()
 9484                    .bg(cx.theme().colors().editor_background)
 9485                    .border(BORDER_WIDTH)
 9486                    .shadow_xs()
 9487                    .border_color(cx.theme().colors().border)
 9488                    .rounded_l_lg()
 9489                    .when(line_count > 1, |el| el.rounded_br_lg())
 9490                    .pr_1()
 9491                    .child(styled_text),
 9492            )
 9493            .child(
 9494                h_flex()
 9495                    .h(line_height + BORDER_WIDTH * 2.)
 9496                    .px_1p5()
 9497                    .gap_1()
 9498                    // Workaround: For some reason, there's a gap if we don't do this
 9499                    .ml(-BORDER_WIDTH)
 9500                    .shadow(vec![gpui::BoxShadow {
 9501                        color: gpui::black().opacity(0.05),
 9502                        offset: point(px(1.), px(1.)),
 9503                        blur_radius: px(2.),
 9504                        spread_radius: px(0.),
 9505                    }])
 9506                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9507                    .border(BORDER_WIDTH)
 9508                    .border_color(cx.theme().colors().border)
 9509                    .rounded_r_lg()
 9510                    .id("edit_prediction_diff_popover_keybind")
 9511                    .when(!has_keybind, |el| {
 9512                        let status_colors = cx.theme().status();
 9513
 9514                        el.bg(status_colors.error_background)
 9515                            .border_color(status_colors.error.opacity(0.6))
 9516                            .child(Icon::new(IconName::Info).color(Color::Error))
 9517                            .cursor_default()
 9518                            .hoverable_tooltip(move |_window, cx| {
 9519                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9520                            })
 9521                    })
 9522                    .children(keybind),
 9523            )
 9524            .into_any();
 9525
 9526        let longest_row =
 9527            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9528        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9529            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9530        } else {
 9531            layout_line(
 9532                longest_row,
 9533                editor_snapshot,
 9534                style,
 9535                editor_width,
 9536                |_| false,
 9537                window,
 9538                cx,
 9539            )
 9540            .width
 9541        };
 9542
 9543        let viewport_bounds =
 9544            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9545                right: -right_margin,
 9546                ..Default::default()
 9547            });
 9548
 9549        let x_after_longest = Pixels::from(
 9550            ScrollPixelOffset::from(
 9551                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9552            ) - scroll_pixel_position.x,
 9553        );
 9554
 9555        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9556
 9557        // Fully visible if it can be displayed within the window (allow overlapping other
 9558        // panes). However, this is only allowed if the popover starts within text_bounds.
 9559        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9560            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9561
 9562        let mut origin = if can_position_to_the_right {
 9563            point(
 9564                x_after_longest,
 9565                text_bounds.origin.y
 9566                    + Pixels::from(
 9567                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9568                            - scroll_pixel_position.y,
 9569                    ),
 9570            )
 9571        } else {
 9572            let cursor_row = newest_selection_head.map(|head| head.row());
 9573            let above_edit = edit_start
 9574                .row()
 9575                .0
 9576                .checked_sub(line_count as u32)
 9577                .map(DisplayRow);
 9578            let below_edit = Some(edit_end.row() + 1);
 9579            let above_cursor =
 9580                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9581            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9582
 9583            // Place the edit popover adjacent to the edit if there is a location
 9584            // available that is onscreen and does not obscure the cursor. Otherwise,
 9585            // place it adjacent to the cursor.
 9586            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9587                .into_iter()
 9588                .flatten()
 9589                .find(|&start_row| {
 9590                    let end_row = start_row + line_count as u32;
 9591                    visible_row_range.contains(&start_row)
 9592                        && visible_row_range.contains(&end_row)
 9593                        && cursor_row
 9594                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9595                })?;
 9596
 9597            content_origin
 9598                + point(
 9599                    Pixels::from(-scroll_pixel_position.x),
 9600                    Pixels::from(
 9601                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9602                    ),
 9603                )
 9604        };
 9605
 9606        origin.x -= BORDER_WIDTH;
 9607
 9608        window.defer_draw(element, origin, 1);
 9609
 9610        // Do not return an element, since it will already be drawn due to defer_draw.
 9611        None
 9612    }
 9613
 9614    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9615        px(30.)
 9616    }
 9617
 9618    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9619        if self.read_only(cx) {
 9620            cx.theme().players().read_only()
 9621        } else {
 9622            self.style.as_ref().unwrap().local_player
 9623        }
 9624    }
 9625
 9626    fn render_edit_prediction_accept_keybind(
 9627        &self,
 9628        window: &mut Window,
 9629        cx: &mut App,
 9630    ) -> Option<AnyElement> {
 9631        let accept_binding =
 9632            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9633        let accept_keystroke = accept_binding.keystroke()?;
 9634
 9635        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9636
 9637        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9638            Color::Accent
 9639        } else {
 9640            Color::Muted
 9641        };
 9642
 9643        h_flex()
 9644            .px_0p5()
 9645            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9646            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9647            .text_size(TextSize::XSmall.rems(cx))
 9648            .child(h_flex().children(ui::render_modifiers(
 9649                accept_keystroke.modifiers(),
 9650                PlatformStyle::platform(),
 9651                Some(modifiers_color),
 9652                Some(IconSize::XSmall.rems().into()),
 9653                true,
 9654            )))
 9655            .when(is_platform_style_mac, |parent| {
 9656                parent.child(accept_keystroke.key().to_string())
 9657            })
 9658            .when(!is_platform_style_mac, |parent| {
 9659                parent.child(
 9660                    Key::new(
 9661                        util::capitalize(accept_keystroke.key()),
 9662                        Some(Color::Default),
 9663                    )
 9664                    .size(Some(IconSize::XSmall.rems().into())),
 9665                )
 9666            })
 9667            .into_any()
 9668            .into()
 9669    }
 9670
 9671    fn render_edit_prediction_line_popover(
 9672        &self,
 9673        label: impl Into<SharedString>,
 9674        icon: Option<IconName>,
 9675        window: &mut Window,
 9676        cx: &mut App,
 9677    ) -> Stateful<Div> {
 9678        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9679
 9680        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9681        let has_keybind = keybind.is_some();
 9682
 9683        h_flex()
 9684            .id("ep-line-popover")
 9685            .py_0p5()
 9686            .pl_1()
 9687            .pr(padding_right)
 9688            .gap_1()
 9689            .rounded_md()
 9690            .border_1()
 9691            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9692            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9693            .shadow_xs()
 9694            .when(!has_keybind, |el| {
 9695                let status_colors = cx.theme().status();
 9696
 9697                el.bg(status_colors.error_background)
 9698                    .border_color(status_colors.error.opacity(0.6))
 9699                    .pl_2()
 9700                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9701                    .cursor_default()
 9702                    .hoverable_tooltip(move |_window, cx| {
 9703                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9704                    })
 9705            })
 9706            .children(keybind)
 9707            .child(
 9708                Label::new(label)
 9709                    .size(LabelSize::Small)
 9710                    .when(!has_keybind, |el| {
 9711                        el.color(cx.theme().status().error.into()).strikethrough()
 9712                    }),
 9713            )
 9714            .when(!has_keybind, |el| {
 9715                el.child(
 9716                    h_flex().ml_1().child(
 9717                        Icon::new(IconName::Info)
 9718                            .size(IconSize::Small)
 9719                            .color(cx.theme().status().error.into()),
 9720                    ),
 9721                )
 9722            })
 9723            .when_some(icon, |element, icon| {
 9724                element.child(
 9725                    div()
 9726                        .mt(px(1.5))
 9727                        .child(Icon::new(icon).size(IconSize::Small)),
 9728                )
 9729            })
 9730    }
 9731
 9732    fn render_edit_prediction_jump_outside_popover(
 9733        &self,
 9734        snapshot: &BufferSnapshot,
 9735        window: &mut Window,
 9736        cx: &mut App,
 9737    ) -> Stateful<Div> {
 9738        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9739        let has_keybind = keybind.is_some();
 9740
 9741        let file_name = snapshot
 9742            .file()
 9743            .map(|file| SharedString::new(file.file_name(cx)))
 9744            .unwrap_or(SharedString::new_static("untitled"));
 9745
 9746        h_flex()
 9747            .id("ep-jump-outside-popover")
 9748            .py_1()
 9749            .px_2()
 9750            .gap_1()
 9751            .rounded_md()
 9752            .border_1()
 9753            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9754            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9755            .shadow_xs()
 9756            .when(!has_keybind, |el| {
 9757                let status_colors = cx.theme().status();
 9758
 9759                el.bg(status_colors.error_background)
 9760                    .border_color(status_colors.error.opacity(0.6))
 9761                    .pl_2()
 9762                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9763                    .cursor_default()
 9764                    .hoverable_tooltip(move |_window, cx| {
 9765                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9766                    })
 9767            })
 9768            .children(keybind)
 9769            .child(
 9770                Label::new(file_name)
 9771                    .size(LabelSize::Small)
 9772                    .buffer_font(cx)
 9773                    .when(!has_keybind, |el| {
 9774                        el.color(cx.theme().status().error.into()).strikethrough()
 9775                    }),
 9776            )
 9777            .when(!has_keybind, |el| {
 9778                el.child(
 9779                    h_flex().ml_1().child(
 9780                        Icon::new(IconName::Info)
 9781                            .size(IconSize::Small)
 9782                            .color(cx.theme().status().error.into()),
 9783                    ),
 9784                )
 9785            })
 9786            .child(
 9787                div()
 9788                    .mt(px(1.5))
 9789                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9790            )
 9791    }
 9792
 9793    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9794        let accent_color = cx.theme().colors().text_accent;
 9795        let editor_bg_color = cx.theme().colors().editor_background;
 9796        editor_bg_color.blend(accent_color.opacity(0.1))
 9797    }
 9798
 9799    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9800        let accent_color = cx.theme().colors().text_accent;
 9801        let editor_bg_color = cx.theme().colors().editor_background;
 9802        editor_bg_color.blend(accent_color.opacity(0.6))
 9803    }
 9804    fn get_prediction_provider_icon_name(
 9805        provider: &Option<RegisteredEditPredictionDelegate>,
 9806    ) -> IconName {
 9807        match provider {
 9808            Some(provider) => match provider.provider.name() {
 9809                "copilot" => IconName::Copilot,
 9810                "supermaven" => IconName::Supermaven,
 9811                _ => IconName::ZedPredict,
 9812            },
 9813            None => IconName::ZedPredict,
 9814        }
 9815    }
 9816
 9817    fn render_edit_prediction_cursor_popover(
 9818        &self,
 9819        min_width: Pixels,
 9820        max_width: Pixels,
 9821        cursor_point: Point,
 9822        style: &EditorStyle,
 9823        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9824        _window: &Window,
 9825        cx: &mut Context<Editor>,
 9826    ) -> Option<AnyElement> {
 9827        let provider = self.edit_prediction_provider.as_ref()?;
 9828        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9829
 9830        let is_refreshing = provider.provider.is_refreshing(cx);
 9831
 9832        fn pending_completion_container(icon: IconName) -> Div {
 9833            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9834        }
 9835
 9836        let completion = match &self.active_edit_prediction {
 9837            Some(prediction) => {
 9838                if !self.has_visible_completions_menu() {
 9839                    const RADIUS: Pixels = px(6.);
 9840                    const BORDER_WIDTH: Pixels = px(1.);
 9841
 9842                    return Some(
 9843                        h_flex()
 9844                            .elevation_2(cx)
 9845                            .border(BORDER_WIDTH)
 9846                            .border_color(cx.theme().colors().border)
 9847                            .when(accept_keystroke.is_none(), |el| {
 9848                                el.border_color(cx.theme().status().error)
 9849                            })
 9850                            .rounded(RADIUS)
 9851                            .rounded_tl(px(0.))
 9852                            .overflow_hidden()
 9853                            .child(div().px_1p5().child(match &prediction.completion {
 9854                                EditPrediction::MoveWithin { target, snapshot } => {
 9855                                    use text::ToPoint as _;
 9856                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9857                                    {
 9858                                        Icon::new(IconName::ZedPredictDown)
 9859                                    } else {
 9860                                        Icon::new(IconName::ZedPredictUp)
 9861                                    }
 9862                                }
 9863                                EditPrediction::MoveOutside { .. } => {
 9864                                    // TODO [zeta2] custom icon for external jump?
 9865                                    Icon::new(provider_icon)
 9866                                }
 9867                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9868                            }))
 9869                            .child(
 9870                                h_flex()
 9871                                    .gap_1()
 9872                                    .py_1()
 9873                                    .px_2()
 9874                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9875                                    .border_l_1()
 9876                                    .border_color(cx.theme().colors().border)
 9877                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9878                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9879                                        el.child(
 9880                                            Label::new("Hold")
 9881                                                .size(LabelSize::Small)
 9882                                                .when(accept_keystroke.is_none(), |el| {
 9883                                                    el.strikethrough()
 9884                                                })
 9885                                                .line_height_style(LineHeightStyle::UiLabel),
 9886                                        )
 9887                                    })
 9888                                    .id("edit_prediction_cursor_popover_keybind")
 9889                                    .when(accept_keystroke.is_none(), |el| {
 9890                                        let status_colors = cx.theme().status();
 9891
 9892                                        el.bg(status_colors.error_background)
 9893                                            .border_color(status_colors.error.opacity(0.6))
 9894                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9895                                            .cursor_default()
 9896                                            .hoverable_tooltip(move |_window, cx| {
 9897                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9898                                                    .into()
 9899                                            })
 9900                                    })
 9901                                    .when_some(
 9902                                        accept_keystroke.as_ref(),
 9903                                        |el, accept_keystroke| {
 9904                                            el.child(h_flex().children(ui::render_modifiers(
 9905                                                accept_keystroke.modifiers(),
 9906                                                PlatformStyle::platform(),
 9907                                                Some(Color::Default),
 9908                                                Some(IconSize::XSmall.rems().into()),
 9909                                                false,
 9910                                            )))
 9911                                        },
 9912                                    ),
 9913                            )
 9914                            .into_any(),
 9915                    );
 9916                }
 9917
 9918                self.render_edit_prediction_cursor_popover_preview(
 9919                    prediction,
 9920                    cursor_point,
 9921                    style,
 9922                    cx,
 9923                )?
 9924            }
 9925
 9926            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9927                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9928                    stale_completion,
 9929                    cursor_point,
 9930                    style,
 9931                    cx,
 9932                )?,
 9933
 9934                None => pending_completion_container(provider_icon)
 9935                    .child(Label::new("...").size(LabelSize::Small)),
 9936            },
 9937
 9938            None => pending_completion_container(provider_icon)
 9939                .child(Label::new("...").size(LabelSize::Small)),
 9940        };
 9941
 9942        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9943            completion
 9944                .with_animation(
 9945                    "loading-completion",
 9946                    Animation::new(Duration::from_secs(2))
 9947                        .repeat()
 9948                        .with_easing(pulsating_between(0.4, 0.8)),
 9949                    |label, delta| label.opacity(delta),
 9950                )
 9951                .into_any_element()
 9952        } else {
 9953            completion.into_any_element()
 9954        };
 9955
 9956        let has_completion = self.active_edit_prediction.is_some();
 9957
 9958        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9959        Some(
 9960            h_flex()
 9961                .min_w(min_width)
 9962                .max_w(max_width)
 9963                .flex_1()
 9964                .elevation_2(cx)
 9965                .border_color(cx.theme().colors().border)
 9966                .child(
 9967                    div()
 9968                        .flex_1()
 9969                        .py_1()
 9970                        .px_2()
 9971                        .overflow_hidden()
 9972                        .child(completion),
 9973                )
 9974                .when_some(accept_keystroke, |el, accept_keystroke| {
 9975                    if !accept_keystroke.modifiers().modified() {
 9976                        return el;
 9977                    }
 9978
 9979                    el.child(
 9980                        h_flex()
 9981                            .h_full()
 9982                            .border_l_1()
 9983                            .rounded_r_lg()
 9984                            .border_color(cx.theme().colors().border)
 9985                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9986                            .gap_1()
 9987                            .py_1()
 9988                            .px_2()
 9989                            .child(
 9990                                h_flex()
 9991                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9992                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9993                                    .child(h_flex().children(ui::render_modifiers(
 9994                                        accept_keystroke.modifiers(),
 9995                                        PlatformStyle::platform(),
 9996                                        Some(if !has_completion {
 9997                                            Color::Muted
 9998                                        } else {
 9999                                            Color::Default
10000                                        }),
10001                                        None,
10002                                        false,
10003                                    ))),
10004                            )
10005                            .child(Label::new("Preview").into_any_element())
10006                            .opacity(if has_completion { 1.0 } else { 0.4 }),
10007                    )
10008                })
10009                .into_any(),
10010        )
10011    }
10012
10013    fn render_edit_prediction_cursor_popover_preview(
10014        &self,
10015        completion: &EditPredictionState,
10016        cursor_point: Point,
10017        style: &EditorStyle,
10018        cx: &mut Context<Editor>,
10019    ) -> Option<Div> {
10020        use text::ToPoint as _;
10021
10022        fn render_relative_row_jump(
10023            prefix: impl Into<String>,
10024            current_row: u32,
10025            target_row: u32,
10026        ) -> Div {
10027            let (row_diff, arrow) = if target_row < current_row {
10028                (current_row - target_row, IconName::ArrowUp)
10029            } else {
10030                (target_row - current_row, IconName::ArrowDown)
10031            };
10032
10033            h_flex()
10034                .child(
10035                    Label::new(format!("{}{}", prefix.into(), row_diff))
10036                        .color(Color::Muted)
10037                        .size(LabelSize::Small),
10038                )
10039                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10040        }
10041
10042        let supports_jump = self
10043            .edit_prediction_provider
10044            .as_ref()
10045            .map(|provider| provider.provider.supports_jump_to_edit())
10046            .unwrap_or(true);
10047
10048        match &completion.completion {
10049            EditPrediction::MoveWithin {
10050                target, snapshot, ..
10051            } => {
10052                if !supports_jump {
10053                    return None;
10054                }
10055
10056                Some(
10057                    h_flex()
10058                        .px_2()
10059                        .gap_2()
10060                        .flex_1()
10061                        .child(
10062                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
10063                                Icon::new(IconName::ZedPredictDown)
10064                            } else {
10065                                Icon::new(IconName::ZedPredictUp)
10066                            },
10067                        )
10068                        .child(Label::new("Jump to Edit")),
10069                )
10070            }
10071            EditPrediction::MoveOutside { snapshot, .. } => {
10072                let file_name = snapshot
10073                    .file()
10074                    .map(|file| file.file_name(cx))
10075                    .unwrap_or("untitled");
10076                Some(
10077                    h_flex()
10078                        .px_2()
10079                        .gap_2()
10080                        .flex_1()
10081                        .child(Icon::new(IconName::ZedPredict))
10082                        .child(Label::new(format!("Jump to {file_name}"))),
10083                )
10084            }
10085            EditPrediction::Edit {
10086                edits,
10087                edit_preview,
10088                snapshot,
10089                display_mode: _,
10090            } => {
10091                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10092
10093                let (highlighted_edits, has_more_lines) =
10094                    if let Some(edit_preview) = edit_preview.as_ref() {
10095                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10096                            .first_line_preview()
10097                    } else {
10098                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10099                    };
10100
10101                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10102                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10103
10104                let preview = h_flex()
10105                    .gap_1()
10106                    .min_w_16()
10107                    .child(styled_text)
10108                    .when(has_more_lines, |parent| parent.child(""));
10109
10110                let left = if supports_jump && first_edit_row != cursor_point.row {
10111                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10112                        .into_any_element()
10113                } else {
10114                    let icon_name =
10115                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10116                    Icon::new(icon_name).into_any_element()
10117                };
10118
10119                Some(
10120                    h_flex()
10121                        .h_full()
10122                        .flex_1()
10123                        .gap_2()
10124                        .pr_1()
10125                        .overflow_x_hidden()
10126                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10127                        .child(left)
10128                        .child(preview),
10129                )
10130            }
10131        }
10132    }
10133
10134    pub fn render_context_menu(
10135        &mut self,
10136        max_height_in_lines: u32,
10137        window: &mut Window,
10138        cx: &mut Context<Editor>,
10139    ) -> Option<AnyElement> {
10140        let menu = self.context_menu.borrow();
10141        let menu = menu.as_ref()?;
10142        if !menu.visible() {
10143            return None;
10144        };
10145        self.style
10146            .as_ref()
10147            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10148    }
10149
10150    fn render_context_menu_aside(
10151        &mut self,
10152        max_size: Size<Pixels>,
10153        window: &mut Window,
10154        cx: &mut Context<Editor>,
10155    ) -> Option<AnyElement> {
10156        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10157            if menu.visible() {
10158                menu.render_aside(max_size, window, cx)
10159            } else {
10160                None
10161            }
10162        })
10163    }
10164
10165    fn hide_context_menu(
10166        &mut self,
10167        window: &mut Window,
10168        cx: &mut Context<Self>,
10169    ) -> Option<CodeContextMenu> {
10170        cx.notify();
10171        self.completion_tasks.clear();
10172        let context_menu = self.context_menu.borrow_mut().take();
10173        self.stale_edit_prediction_in_menu.take();
10174        self.update_visible_edit_prediction(window, cx);
10175        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10176            && let Some(completion_provider) = &self.completion_provider
10177        {
10178            completion_provider.selection_changed(None, window, cx);
10179        }
10180        context_menu
10181    }
10182
10183    fn show_snippet_choices(
10184        &mut self,
10185        choices: &Vec<String>,
10186        selection: Range<Anchor>,
10187        cx: &mut Context<Self>,
10188    ) {
10189        let Some((_, buffer, _)) = self
10190            .buffer()
10191            .read(cx)
10192            .excerpt_containing(selection.start, cx)
10193        else {
10194            return;
10195        };
10196        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10197        else {
10198            return;
10199        };
10200        if buffer != end_buffer {
10201            log::error!("expected anchor range to have matching buffer IDs");
10202            return;
10203        }
10204
10205        let id = post_inc(&mut self.next_completion_id);
10206        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10207        let mut context_menu = self.context_menu.borrow_mut();
10208        let old_menu = context_menu.take();
10209        *context_menu = Some(CodeContextMenu::Completions(
10210            CompletionsMenu::new_snippet_choices(
10211                id,
10212                true,
10213                choices,
10214                selection,
10215                buffer,
10216                old_menu.map(|menu| menu.primary_scroll_handle()),
10217                snippet_sort_order,
10218            ),
10219        ));
10220    }
10221
10222    pub fn insert_snippet(
10223        &mut self,
10224        insertion_ranges: &[Range<MultiBufferOffset>],
10225        snippet: Snippet,
10226        window: &mut Window,
10227        cx: &mut Context<Self>,
10228    ) -> Result<()> {
10229        struct Tabstop<T> {
10230            is_end_tabstop: bool,
10231            ranges: Vec<Range<T>>,
10232            choices: Option<Vec<String>>,
10233        }
10234
10235        let tabstops = self.buffer.update(cx, |buffer, cx| {
10236            let snippet_text: Arc<str> = snippet.text.clone().into();
10237            let edits = insertion_ranges
10238                .iter()
10239                .cloned()
10240                .map(|range| (range, snippet_text.clone()));
10241            let autoindent_mode = AutoindentMode::Block {
10242                original_indent_columns: Vec::new(),
10243            };
10244            buffer.edit(edits, Some(autoindent_mode), cx);
10245
10246            let snapshot = &*buffer.read(cx);
10247            let snippet = &snippet;
10248            snippet
10249                .tabstops
10250                .iter()
10251                .map(|tabstop| {
10252                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10253                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10254                    });
10255                    let mut tabstop_ranges = tabstop
10256                        .ranges
10257                        .iter()
10258                        .flat_map(|tabstop_range| {
10259                            let mut delta = 0_isize;
10260                            insertion_ranges.iter().map(move |insertion_range| {
10261                                let insertion_start = insertion_range.start + delta;
10262                                delta += snippet.text.len() as isize
10263                                    - (insertion_range.end - insertion_range.start) as isize;
10264
10265                                let start =
10266                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10267                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10268                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10269                            })
10270                        })
10271                        .collect::<Vec<_>>();
10272                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10273
10274                    Tabstop {
10275                        is_end_tabstop,
10276                        ranges: tabstop_ranges,
10277                        choices: tabstop.choices.clone(),
10278                    }
10279                })
10280                .collect::<Vec<_>>()
10281        });
10282        if let Some(tabstop) = tabstops.first() {
10283            self.change_selections(Default::default(), window, cx, |s| {
10284                // Reverse order so that the first range is the newest created selection.
10285                // Completions will use it and autoscroll will prioritize it.
10286                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10287            });
10288
10289            if let Some(choices) = &tabstop.choices
10290                && let Some(selection) = tabstop.ranges.first()
10291            {
10292                self.show_snippet_choices(choices, selection.clone(), cx)
10293            }
10294
10295            // If we're already at the last tabstop and it's at the end of the snippet,
10296            // we're done, we don't need to keep the state around.
10297            if !tabstop.is_end_tabstop {
10298                let choices = tabstops
10299                    .iter()
10300                    .map(|tabstop| tabstop.choices.clone())
10301                    .collect();
10302
10303                let ranges = tabstops
10304                    .into_iter()
10305                    .map(|tabstop| tabstop.ranges)
10306                    .collect::<Vec<_>>();
10307
10308                self.snippet_stack.push(SnippetState {
10309                    active_index: 0,
10310                    ranges,
10311                    choices,
10312                });
10313            }
10314
10315            // Check whether the just-entered snippet ends with an auto-closable bracket.
10316            if self.autoclose_regions.is_empty() {
10317                let snapshot = self.buffer.read(cx).snapshot(cx);
10318                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10319                    let selection_head = selection.head();
10320                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10321                        continue;
10322                    };
10323
10324                    let mut bracket_pair = None;
10325                    let max_lookup_length = scope
10326                        .brackets()
10327                        .map(|(pair, _)| {
10328                            pair.start
10329                                .as_str()
10330                                .chars()
10331                                .count()
10332                                .max(pair.end.as_str().chars().count())
10333                        })
10334                        .max();
10335                    if let Some(max_lookup_length) = max_lookup_length {
10336                        let next_text = snapshot
10337                            .chars_at(selection_head)
10338                            .take(max_lookup_length)
10339                            .collect::<String>();
10340                        let prev_text = snapshot
10341                            .reversed_chars_at(selection_head)
10342                            .take(max_lookup_length)
10343                            .collect::<String>();
10344
10345                        for (pair, enabled) in scope.brackets() {
10346                            if enabled
10347                                && pair.close
10348                                && prev_text.starts_with(pair.start.as_str())
10349                                && next_text.starts_with(pair.end.as_str())
10350                            {
10351                                bracket_pair = Some(pair.clone());
10352                                break;
10353                            }
10354                        }
10355                    }
10356
10357                    if let Some(pair) = bracket_pair {
10358                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10359                        let autoclose_enabled =
10360                            self.use_autoclose && snapshot_settings.use_autoclose;
10361                        if autoclose_enabled {
10362                            let start = snapshot.anchor_after(selection_head);
10363                            let end = snapshot.anchor_after(selection_head);
10364                            self.autoclose_regions.push(AutocloseRegion {
10365                                selection_id: selection.id,
10366                                range: start..end,
10367                                pair,
10368                            });
10369                        }
10370                    }
10371                }
10372            }
10373        }
10374        Ok(())
10375    }
10376
10377    pub fn move_to_next_snippet_tabstop(
10378        &mut self,
10379        window: &mut Window,
10380        cx: &mut Context<Self>,
10381    ) -> bool {
10382        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10383    }
10384
10385    pub fn move_to_prev_snippet_tabstop(
10386        &mut self,
10387        window: &mut Window,
10388        cx: &mut Context<Self>,
10389    ) -> bool {
10390        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10391    }
10392
10393    pub fn move_to_snippet_tabstop(
10394        &mut self,
10395        bias: Bias,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) -> bool {
10399        if let Some(mut snippet) = self.snippet_stack.pop() {
10400            match bias {
10401                Bias::Left => {
10402                    if snippet.active_index > 0 {
10403                        snippet.active_index -= 1;
10404                    } else {
10405                        self.snippet_stack.push(snippet);
10406                        return false;
10407                    }
10408                }
10409                Bias::Right => {
10410                    if snippet.active_index + 1 < snippet.ranges.len() {
10411                        snippet.active_index += 1;
10412                    } else {
10413                        self.snippet_stack.push(snippet);
10414                        return false;
10415                    }
10416                }
10417            }
10418            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10419                self.change_selections(Default::default(), window, cx, |s| {
10420                    // Reverse order so that the first range is the newest created selection.
10421                    // Completions will use it and autoscroll will prioritize it.
10422                    s.select_ranges(current_ranges.iter().rev().cloned())
10423                });
10424
10425                if let Some(choices) = &snippet.choices[snippet.active_index]
10426                    && let Some(selection) = current_ranges.first()
10427                {
10428                    self.show_snippet_choices(choices, selection.clone(), cx);
10429                }
10430
10431                // If snippet state is not at the last tabstop, push it back on the stack
10432                if snippet.active_index + 1 < snippet.ranges.len() {
10433                    self.snippet_stack.push(snippet);
10434                }
10435                return true;
10436            }
10437        }
10438
10439        false
10440    }
10441
10442    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10443        self.transact(window, cx, |this, window, cx| {
10444            this.select_all(&SelectAll, window, cx);
10445            this.insert("", window, cx);
10446        });
10447    }
10448
10449    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10450        if self.read_only(cx) {
10451            return;
10452        }
10453        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10454        self.transact(window, cx, |this, window, cx| {
10455            this.select_autoclose_pair(window, cx);
10456
10457            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10458
10459            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10460            if !this.linked_edit_ranges.is_empty() {
10461                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10462                let snapshot = this.buffer.read(cx).snapshot(cx);
10463
10464                for selection in selections.iter() {
10465                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10466                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10467                    if selection_start.buffer_id != selection_end.buffer_id {
10468                        continue;
10469                    }
10470                    if let Some(ranges) =
10471                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10472                    {
10473                        for (buffer, entries) in ranges {
10474                            linked_ranges.entry(buffer).or_default().extend(entries);
10475                        }
10476                    }
10477                }
10478            }
10479
10480            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10481            for selection in &mut selections {
10482                if selection.is_empty() {
10483                    let old_head = selection.head();
10484                    let mut new_head =
10485                        movement::left(&display_map, old_head.to_display_point(&display_map))
10486                            .to_point(&display_map);
10487                    if let Some((buffer, line_buffer_range)) = display_map
10488                        .buffer_snapshot()
10489                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10490                    {
10491                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10492                        let indent_len = match indent_size.kind {
10493                            IndentKind::Space => {
10494                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10495                            }
10496                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10497                        };
10498                        if old_head.column <= indent_size.len && old_head.column > 0 {
10499                            let indent_len = indent_len.get();
10500                            new_head = cmp::min(
10501                                new_head,
10502                                MultiBufferPoint::new(
10503                                    old_head.row,
10504                                    ((old_head.column - 1) / indent_len) * indent_len,
10505                                ),
10506                            );
10507                        }
10508                    }
10509
10510                    selection.set_head(new_head, SelectionGoal::None);
10511                }
10512            }
10513
10514            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10515            this.insert("", window, cx);
10516            let empty_str: Arc<str> = Arc::from("");
10517            for (buffer, edits) in linked_ranges {
10518                let snapshot = buffer.read(cx).snapshot();
10519                use text::ToPoint as TP;
10520
10521                let edits = edits
10522                    .into_iter()
10523                    .map(|range| {
10524                        let end_point = TP::to_point(&range.end, &snapshot);
10525                        let mut start_point = TP::to_point(&range.start, &snapshot);
10526
10527                        if end_point == start_point {
10528                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10529                                .saturating_sub(1);
10530                            start_point =
10531                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10532                        };
10533
10534                        (start_point..end_point, empty_str.clone())
10535                    })
10536                    .sorted_by_key(|(range, _)| range.start)
10537                    .collect::<Vec<_>>();
10538                buffer.update(cx, |this, cx| {
10539                    this.edit(edits, None, cx);
10540                })
10541            }
10542            this.refresh_edit_prediction(true, false, window, cx);
10543            refresh_linked_ranges(this, window, cx);
10544        });
10545    }
10546
10547    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10548        if self.read_only(cx) {
10549            return;
10550        }
10551        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10552        self.transact(window, cx, |this, window, cx| {
10553            this.change_selections(Default::default(), window, cx, |s| {
10554                s.move_with(|map, selection| {
10555                    if selection.is_empty() {
10556                        let cursor = movement::right(map, selection.head());
10557                        selection.end = cursor;
10558                        selection.reversed = true;
10559                        selection.goal = SelectionGoal::None;
10560                    }
10561                })
10562            });
10563            this.insert("", window, cx);
10564            this.refresh_edit_prediction(true, false, window, cx);
10565        });
10566    }
10567
10568    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10569        if self.mode.is_single_line() {
10570            cx.propagate();
10571            return;
10572        }
10573
10574        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10575        if self.move_to_prev_snippet_tabstop(window, cx) {
10576            return;
10577        }
10578        self.outdent(&Outdent, window, cx);
10579    }
10580
10581    pub fn next_snippet_tabstop(
10582        &mut self,
10583        _: &NextSnippetTabstop,
10584        window: &mut Window,
10585        cx: &mut Context<Self>,
10586    ) {
10587        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10588            cx.propagate();
10589            return;
10590        }
10591
10592        if self.move_to_next_snippet_tabstop(window, cx) {
10593            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10594            return;
10595        }
10596        cx.propagate();
10597    }
10598
10599    pub fn previous_snippet_tabstop(
10600        &mut self,
10601        _: &PreviousSnippetTabstop,
10602        window: &mut Window,
10603        cx: &mut Context<Self>,
10604    ) {
10605        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10606            cx.propagate();
10607            return;
10608        }
10609
10610        if self.move_to_prev_snippet_tabstop(window, cx) {
10611            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612            return;
10613        }
10614        cx.propagate();
10615    }
10616
10617    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10618        if self.mode.is_single_line() {
10619            cx.propagate();
10620            return;
10621        }
10622
10623        if self.move_to_next_snippet_tabstop(window, cx) {
10624            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10625            return;
10626        }
10627        if self.read_only(cx) {
10628            return;
10629        }
10630        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10631        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10632        let buffer = self.buffer.read(cx);
10633        let snapshot = buffer.snapshot(cx);
10634        let rows_iter = selections.iter().map(|s| s.head().row);
10635        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10636
10637        let has_some_cursor_in_whitespace = selections
10638            .iter()
10639            .filter(|selection| selection.is_empty())
10640            .any(|selection| {
10641                let cursor = selection.head();
10642                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10643                cursor.column < current_indent.len
10644            });
10645
10646        let mut edits = Vec::new();
10647        let mut prev_edited_row = 0;
10648        let mut row_delta = 0;
10649        for selection in &mut selections {
10650            if selection.start.row != prev_edited_row {
10651                row_delta = 0;
10652            }
10653            prev_edited_row = selection.end.row;
10654
10655            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10656            if selection.is_empty() {
10657                let cursor = selection.head();
10658                let settings = buffer.language_settings_at(cursor, cx);
10659                if settings.indent_list_on_tab {
10660                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10661                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10662                            row_delta = Self::indent_selection(
10663                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10664                            );
10665                            continue;
10666                        }
10667                    }
10668                }
10669            }
10670
10671            // If the selection is non-empty, then increase the indentation of the selected lines.
10672            if !selection.is_empty() {
10673                row_delta =
10674                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10675                continue;
10676            }
10677
10678            let cursor = selection.head();
10679            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10680            if let Some(suggested_indent) =
10681                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10682            {
10683                // Don't do anything if already at suggested indent
10684                // and there is any other cursor which is not
10685                if has_some_cursor_in_whitespace
10686                    && cursor.column == current_indent.len
10687                    && current_indent.len == suggested_indent.len
10688                {
10689                    continue;
10690                }
10691
10692                // Adjust line and move cursor to suggested indent
10693                // if cursor is not at suggested indent
10694                if cursor.column < suggested_indent.len
10695                    && cursor.column <= current_indent.len
10696                    && current_indent.len <= suggested_indent.len
10697                {
10698                    selection.start = Point::new(cursor.row, suggested_indent.len);
10699                    selection.end = selection.start;
10700                    if row_delta == 0 {
10701                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10702                            cursor.row,
10703                            current_indent,
10704                            suggested_indent,
10705                        ));
10706                        row_delta = suggested_indent.len - current_indent.len;
10707                    }
10708                    continue;
10709                }
10710
10711                // If current indent is more than suggested indent
10712                // only move cursor to current indent and skip indent
10713                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10714                    selection.start = Point::new(cursor.row, current_indent.len);
10715                    selection.end = selection.start;
10716                    continue;
10717                }
10718            }
10719
10720            // Otherwise, insert a hard or soft tab.
10721            let settings = buffer.language_settings_at(cursor, cx);
10722            let tab_size = if settings.hard_tabs {
10723                IndentSize::tab()
10724            } else {
10725                let tab_size = settings.tab_size.get();
10726                let indent_remainder = snapshot
10727                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10728                    .flat_map(str::chars)
10729                    .fold(row_delta % tab_size, |counter: u32, c| {
10730                        if c == '\t' {
10731                            0
10732                        } else {
10733                            (counter + 1) % tab_size
10734                        }
10735                    });
10736
10737                let chars_to_next_tab_stop = tab_size - indent_remainder;
10738                IndentSize::spaces(chars_to_next_tab_stop)
10739            };
10740            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10741            selection.end = selection.start;
10742            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10743            row_delta += tab_size.len;
10744        }
10745
10746        self.transact(window, cx, |this, window, cx| {
10747            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10748            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10749            this.refresh_edit_prediction(true, false, window, cx);
10750        });
10751    }
10752
10753    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10754        if self.read_only(cx) {
10755            return;
10756        }
10757        if self.mode.is_single_line() {
10758            cx.propagate();
10759            return;
10760        }
10761
10762        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10763        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10764        let mut prev_edited_row = 0;
10765        let mut row_delta = 0;
10766        let mut edits = Vec::new();
10767        let buffer = self.buffer.read(cx);
10768        let snapshot = buffer.snapshot(cx);
10769        for selection in &mut selections {
10770            if selection.start.row != prev_edited_row {
10771                row_delta = 0;
10772            }
10773            prev_edited_row = selection.end.row;
10774
10775            row_delta =
10776                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10777        }
10778
10779        self.transact(window, cx, |this, window, cx| {
10780            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10781            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10782        });
10783    }
10784
10785    fn indent_selection(
10786        buffer: &MultiBuffer,
10787        snapshot: &MultiBufferSnapshot,
10788        selection: &mut Selection<Point>,
10789        edits: &mut Vec<(Range<Point>, String)>,
10790        delta_for_start_row: u32,
10791        cx: &App,
10792    ) -> u32 {
10793        let settings = buffer.language_settings_at(selection.start, cx);
10794        let tab_size = settings.tab_size.get();
10795        let indent_kind = if settings.hard_tabs {
10796            IndentKind::Tab
10797        } else {
10798            IndentKind::Space
10799        };
10800        let mut start_row = selection.start.row;
10801        let mut end_row = selection.end.row + 1;
10802
10803        // If a selection ends at the beginning of a line, don't indent
10804        // that last line.
10805        if selection.end.column == 0 && selection.end.row > selection.start.row {
10806            end_row -= 1;
10807        }
10808
10809        // Avoid re-indenting a row that has already been indented by a
10810        // previous selection, but still update this selection's column
10811        // to reflect that indentation.
10812        if delta_for_start_row > 0 {
10813            start_row += 1;
10814            selection.start.column += delta_for_start_row;
10815            if selection.end.row == selection.start.row {
10816                selection.end.column += delta_for_start_row;
10817            }
10818        }
10819
10820        let mut delta_for_end_row = 0;
10821        let has_multiple_rows = start_row + 1 != end_row;
10822        for row in start_row..end_row {
10823            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10824            let indent_delta = match (current_indent.kind, indent_kind) {
10825                (IndentKind::Space, IndentKind::Space) => {
10826                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10827                    IndentSize::spaces(columns_to_next_tab_stop)
10828                }
10829                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10830                (_, IndentKind::Tab) => IndentSize::tab(),
10831            };
10832
10833            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10834                0
10835            } else {
10836                selection.start.column
10837            };
10838            let row_start = Point::new(row, start);
10839            edits.push((
10840                row_start..row_start,
10841                indent_delta.chars().collect::<String>(),
10842            ));
10843
10844            // Update this selection's endpoints to reflect the indentation.
10845            if row == selection.start.row {
10846                selection.start.column += indent_delta.len;
10847            }
10848            if row == selection.end.row {
10849                selection.end.column += indent_delta.len;
10850                delta_for_end_row = indent_delta.len;
10851            }
10852        }
10853
10854        if selection.start.row == selection.end.row {
10855            delta_for_start_row + delta_for_end_row
10856        } else {
10857            delta_for_end_row
10858        }
10859    }
10860
10861    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10862        if self.read_only(cx) {
10863            return;
10864        }
10865        if self.mode.is_single_line() {
10866            cx.propagate();
10867            return;
10868        }
10869
10870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10871        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10872        let selections = self.selections.all::<Point>(&display_map);
10873        let mut deletion_ranges = Vec::new();
10874        let mut last_outdent = None;
10875        {
10876            let buffer = self.buffer.read(cx);
10877            let snapshot = buffer.snapshot(cx);
10878            for selection in &selections {
10879                let settings = buffer.language_settings_at(selection.start, cx);
10880                let tab_size = settings.tab_size.get();
10881                let mut rows = selection.spanned_rows(false, &display_map);
10882
10883                // Avoid re-outdenting a row that has already been outdented by a
10884                // previous selection.
10885                if let Some(last_row) = last_outdent
10886                    && last_row == rows.start
10887                {
10888                    rows.start = rows.start.next_row();
10889                }
10890                let has_multiple_rows = rows.len() > 1;
10891                for row in rows.iter_rows() {
10892                    let indent_size = snapshot.indent_size_for_line(row);
10893                    if indent_size.len > 0 {
10894                        let deletion_len = match indent_size.kind {
10895                            IndentKind::Space => {
10896                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10897                                if columns_to_prev_tab_stop == 0 {
10898                                    tab_size
10899                                } else {
10900                                    columns_to_prev_tab_stop
10901                                }
10902                            }
10903                            IndentKind::Tab => 1,
10904                        };
10905                        let start = if has_multiple_rows
10906                            || deletion_len > selection.start.column
10907                            || indent_size.len < selection.start.column
10908                        {
10909                            0
10910                        } else {
10911                            selection.start.column - deletion_len
10912                        };
10913                        deletion_ranges.push(
10914                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10915                        );
10916                        last_outdent = Some(row);
10917                    }
10918                }
10919            }
10920        }
10921
10922        self.transact(window, cx, |this, window, cx| {
10923            this.buffer.update(cx, |buffer, cx| {
10924                let empty_str: Arc<str> = Arc::default();
10925                buffer.edit(
10926                    deletion_ranges
10927                        .into_iter()
10928                        .map(|range| (range, empty_str.clone())),
10929                    None,
10930                    cx,
10931                );
10932            });
10933            let selections = this
10934                .selections
10935                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10936            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10937        });
10938    }
10939
10940    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10941        if self.read_only(cx) {
10942            return;
10943        }
10944        if self.mode.is_single_line() {
10945            cx.propagate();
10946            return;
10947        }
10948
10949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10950        let selections = self
10951            .selections
10952            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10953            .into_iter()
10954            .map(|s| s.range());
10955
10956        self.transact(window, cx, |this, window, cx| {
10957            this.buffer.update(cx, |buffer, cx| {
10958                buffer.autoindent_ranges(selections, cx);
10959            });
10960            let selections = this
10961                .selections
10962                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10963            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10964        });
10965    }
10966
10967    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10969        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10970        let selections = self.selections.all::<Point>(&display_map);
10971
10972        let mut new_cursors = Vec::new();
10973        let mut edit_ranges = Vec::new();
10974        let mut selections = selections.iter().peekable();
10975        while let Some(selection) = selections.next() {
10976            let mut rows = selection.spanned_rows(false, &display_map);
10977
10978            // Accumulate contiguous regions of rows that we want to delete.
10979            while let Some(next_selection) = selections.peek() {
10980                let next_rows = next_selection.spanned_rows(false, &display_map);
10981                if next_rows.start <= rows.end {
10982                    rows.end = next_rows.end;
10983                    selections.next().unwrap();
10984                } else {
10985                    break;
10986                }
10987            }
10988
10989            let buffer = display_map.buffer_snapshot();
10990            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10991            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10992                // If there's a line after the range, delete the \n from the end of the row range
10993                (
10994                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10995                    rows.end,
10996                )
10997            } else {
10998                // If there isn't a line after the range, delete the \n from the line before the
10999                // start of the row range
11000                edit_start = edit_start.saturating_sub_usize(1);
11001                (buffer.len(), rows.start.previous_row())
11002            };
11003
11004            let text_layout_details = self.text_layout_details(window);
11005            let x = display_map.x_for_display_point(
11006                selection.head().to_display_point(&display_map),
11007                &text_layout_details,
11008            );
11009            let row = Point::new(target_row.0, 0)
11010                .to_display_point(&display_map)
11011                .row();
11012            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11013
11014            new_cursors.push((
11015                selection.id,
11016                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11017                SelectionGoal::None,
11018            ));
11019            edit_ranges.push(edit_start..edit_end);
11020        }
11021
11022        self.transact(window, cx, |this, window, cx| {
11023            let buffer = this.buffer.update(cx, |buffer, cx| {
11024                let empty_str: Arc<str> = Arc::default();
11025                buffer.edit(
11026                    edit_ranges
11027                        .into_iter()
11028                        .map(|range| (range, empty_str.clone())),
11029                    None,
11030                    cx,
11031                );
11032                buffer.snapshot(cx)
11033            });
11034            let new_selections = new_cursors
11035                .into_iter()
11036                .map(|(id, cursor, goal)| {
11037                    let cursor = cursor.to_point(&buffer);
11038                    Selection {
11039                        id,
11040                        start: cursor,
11041                        end: cursor,
11042                        reversed: false,
11043                        goal,
11044                    }
11045                })
11046                .collect();
11047
11048            this.change_selections(Default::default(), window, cx, |s| {
11049                s.select(new_selections);
11050            });
11051        });
11052    }
11053
11054    pub fn join_lines_impl(
11055        &mut self,
11056        insert_whitespace: bool,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        if self.read_only(cx) {
11061            return;
11062        }
11063        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11064        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11065            let start = MultiBufferRow(selection.start.row);
11066            // Treat single line selections as if they include the next line. Otherwise this action
11067            // would do nothing for single line selections individual cursors.
11068            let end = if selection.start.row == selection.end.row {
11069                MultiBufferRow(selection.start.row + 1)
11070            } else {
11071                MultiBufferRow(selection.end.row)
11072            };
11073
11074            if let Some(last_row_range) = row_ranges.last_mut()
11075                && start <= last_row_range.end
11076            {
11077                last_row_range.end = end;
11078                continue;
11079            }
11080            row_ranges.push(start..end);
11081        }
11082
11083        let snapshot = self.buffer.read(cx).snapshot(cx);
11084        let mut cursor_positions = Vec::new();
11085        for row_range in &row_ranges {
11086            let anchor = snapshot.anchor_before(Point::new(
11087                row_range.end.previous_row().0,
11088                snapshot.line_len(row_range.end.previous_row()),
11089            ));
11090            cursor_positions.push(anchor..anchor);
11091        }
11092
11093        self.transact(window, cx, |this, window, cx| {
11094            for row_range in row_ranges.into_iter().rev() {
11095                for row in row_range.iter_rows().rev() {
11096                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11097                    let next_line_row = row.next_row();
11098                    let indent = snapshot.indent_size_for_line(next_line_row);
11099                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
11100
11101                    let replace =
11102                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11103                            " "
11104                        } else {
11105                            ""
11106                        };
11107
11108                    this.buffer.update(cx, |buffer, cx| {
11109                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11110                    });
11111                }
11112            }
11113
11114            this.change_selections(Default::default(), window, cx, |s| {
11115                s.select_anchor_ranges(cursor_positions)
11116            });
11117        });
11118    }
11119
11120    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11122        self.join_lines_impl(true, window, cx);
11123    }
11124
11125    pub fn sort_lines_case_sensitive(
11126        &mut self,
11127        _: &SortLinesCaseSensitive,
11128        window: &mut Window,
11129        cx: &mut Context<Self>,
11130    ) {
11131        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11132    }
11133
11134    pub fn sort_lines_by_length(
11135        &mut self,
11136        _: &SortLinesByLength,
11137        window: &mut Window,
11138        cx: &mut Context<Self>,
11139    ) {
11140        self.manipulate_immutable_lines(window, cx, |lines| {
11141            lines.sort_by_key(|&line| line.chars().count())
11142        })
11143    }
11144
11145    pub fn sort_lines_case_insensitive(
11146        &mut self,
11147        _: &SortLinesCaseInsensitive,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150    ) {
11151        self.manipulate_immutable_lines(window, cx, |lines| {
11152            lines.sort_by_key(|line| line.to_lowercase())
11153        })
11154    }
11155
11156    pub fn unique_lines_case_insensitive(
11157        &mut self,
11158        _: &UniqueLinesCaseInsensitive,
11159        window: &mut Window,
11160        cx: &mut Context<Self>,
11161    ) {
11162        self.manipulate_immutable_lines(window, cx, |lines| {
11163            let mut seen = HashSet::default();
11164            lines.retain(|line| seen.insert(line.to_lowercase()));
11165        })
11166    }
11167
11168    pub fn unique_lines_case_sensitive(
11169        &mut self,
11170        _: &UniqueLinesCaseSensitive,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        self.manipulate_immutable_lines(window, cx, |lines| {
11175            let mut seen = HashSet::default();
11176            lines.retain(|line| seen.insert(*line));
11177        })
11178    }
11179
11180    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11181        let snapshot = self.buffer.read(cx).snapshot(cx);
11182        for selection in self.selections.disjoint_anchors_arc().iter() {
11183            if snapshot
11184                .language_at(selection.start)
11185                .and_then(|lang| lang.config().wrap_characters.as_ref())
11186                .is_some()
11187            {
11188                return true;
11189            }
11190        }
11191        false
11192    }
11193
11194    fn wrap_selections_in_tag(
11195        &mut self,
11196        _: &WrapSelectionsInTag,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11201
11202        let snapshot = self.buffer.read(cx).snapshot(cx);
11203
11204        let mut edits = Vec::new();
11205        let mut boundaries = Vec::new();
11206
11207        for selection in self
11208            .selections
11209            .all_adjusted(&self.display_snapshot(cx))
11210            .iter()
11211        {
11212            let Some(wrap_config) = snapshot
11213                .language_at(selection.start)
11214                .and_then(|lang| lang.config().wrap_characters.clone())
11215            else {
11216                continue;
11217            };
11218
11219            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11220            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11221
11222            let start_before = snapshot.anchor_before(selection.start);
11223            let end_after = snapshot.anchor_after(selection.end);
11224
11225            edits.push((start_before..start_before, open_tag));
11226            edits.push((end_after..end_after, close_tag));
11227
11228            boundaries.push((
11229                start_before,
11230                end_after,
11231                wrap_config.start_prefix.len(),
11232                wrap_config.end_suffix.len(),
11233            ));
11234        }
11235
11236        if edits.is_empty() {
11237            return;
11238        }
11239
11240        self.transact(window, cx, |this, window, cx| {
11241            let buffer = this.buffer.update(cx, |buffer, cx| {
11242                buffer.edit(edits, None, cx);
11243                buffer.snapshot(cx)
11244            });
11245
11246            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11247            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11248                boundaries.into_iter()
11249            {
11250                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11251                let close_offset = end_after
11252                    .to_offset(&buffer)
11253                    .saturating_sub_usize(end_suffix_len);
11254                new_selections.push(open_offset..open_offset);
11255                new_selections.push(close_offset..close_offset);
11256            }
11257
11258            this.change_selections(Default::default(), window, cx, |s| {
11259                s.select_ranges(new_selections);
11260            });
11261
11262            this.request_autoscroll(Autoscroll::fit(), cx);
11263        });
11264    }
11265
11266    pub fn toggle_read_only(
11267        &mut self,
11268        _: &workspace::ToggleReadOnlyFile,
11269        _: &mut Window,
11270        cx: &mut Context<Self>,
11271    ) {
11272        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11273            buffer.update(cx, |buffer, cx| {
11274                buffer.set_capability(
11275                    match buffer.capability() {
11276                        Capability::ReadWrite => Capability::Read,
11277                        Capability::Read => Capability::ReadWrite,
11278                        Capability::ReadOnly => Capability::ReadOnly,
11279                    },
11280                    cx,
11281                );
11282            })
11283        }
11284    }
11285
11286    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11287        let Some(project) = self.project.clone() else {
11288            return;
11289        };
11290        self.reload(project, window, cx)
11291            .detach_and_notify_err(window, cx);
11292    }
11293
11294    pub fn restore_file(
11295        &mut self,
11296        _: &::git::RestoreFile,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11301        let mut buffer_ids = HashSet::default();
11302        let snapshot = self.buffer().read(cx).snapshot(cx);
11303        for selection in self
11304            .selections
11305            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11306        {
11307            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11308        }
11309
11310        let buffer = self.buffer().read(cx);
11311        let ranges = buffer_ids
11312            .into_iter()
11313            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11314            .collect::<Vec<_>>();
11315
11316        self.restore_hunks_in_ranges(ranges, window, cx);
11317    }
11318
11319    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11321        let selections = self
11322            .selections
11323            .all(&self.display_snapshot(cx))
11324            .into_iter()
11325            .map(|s| s.range())
11326            .collect();
11327        self.restore_hunks_in_ranges(selections, window, cx);
11328    }
11329
11330    pub fn restore_hunks_in_ranges(
11331        &mut self,
11332        ranges: Vec<Range<Point>>,
11333        window: &mut Window,
11334        cx: &mut Context<Editor>,
11335    ) {
11336        let mut revert_changes = HashMap::default();
11337        let chunk_by = self
11338            .snapshot(window, cx)
11339            .hunks_for_ranges(ranges)
11340            .into_iter()
11341            .chunk_by(|hunk| hunk.buffer_id);
11342        for (buffer_id, hunks) in &chunk_by {
11343            let hunks = hunks.collect::<Vec<_>>();
11344            for hunk in &hunks {
11345                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11346            }
11347            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11348        }
11349        drop(chunk_by);
11350        if !revert_changes.is_empty() {
11351            self.transact(window, cx, |editor, window, cx| {
11352                editor.restore(revert_changes, window, cx);
11353            });
11354        }
11355    }
11356
11357    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11358        if let Some(status) = self
11359            .addons
11360            .iter()
11361            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11362        {
11363            return Some(status);
11364        }
11365        self.project
11366            .as_ref()?
11367            .read(cx)
11368            .status_for_buffer_id(buffer_id, cx)
11369    }
11370
11371    pub fn open_active_item_in_terminal(
11372        &mut self,
11373        _: &OpenInTerminal,
11374        window: &mut Window,
11375        cx: &mut Context<Self>,
11376    ) {
11377        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11378            let project_path = buffer.read(cx).project_path(cx)?;
11379            let project = self.project()?.read(cx);
11380            let entry = project.entry_for_path(&project_path, cx)?;
11381            let parent = match &entry.canonical_path {
11382                Some(canonical_path) => canonical_path.to_path_buf(),
11383                None => project.absolute_path(&project_path, cx)?,
11384            }
11385            .parent()?
11386            .to_path_buf();
11387            Some(parent)
11388        }) {
11389            window.dispatch_action(
11390                OpenTerminal {
11391                    working_directory,
11392                    local: false,
11393                }
11394                .boxed_clone(),
11395                cx,
11396            );
11397        }
11398    }
11399
11400    fn set_breakpoint_context_menu(
11401        &mut self,
11402        display_row: DisplayRow,
11403        position: Option<Anchor>,
11404        clicked_point: gpui::Point<Pixels>,
11405        window: &mut Window,
11406        cx: &mut Context<Self>,
11407    ) {
11408        let source = self
11409            .buffer
11410            .read(cx)
11411            .snapshot(cx)
11412            .anchor_before(Point::new(display_row.0, 0u32));
11413
11414        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11415
11416        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11417            self,
11418            source,
11419            clicked_point,
11420            context_menu,
11421            window,
11422            cx,
11423        );
11424    }
11425
11426    fn add_edit_breakpoint_block(
11427        &mut self,
11428        anchor: Anchor,
11429        breakpoint: &Breakpoint,
11430        edit_action: BreakpointPromptEditAction,
11431        window: &mut Window,
11432        cx: &mut Context<Self>,
11433    ) {
11434        let weak_editor = cx.weak_entity();
11435        let bp_prompt = cx.new(|cx| {
11436            BreakpointPromptEditor::new(
11437                weak_editor,
11438                anchor,
11439                breakpoint.clone(),
11440                edit_action,
11441                window,
11442                cx,
11443            )
11444        });
11445
11446        let height = bp_prompt.update(cx, |this, cx| {
11447            this.prompt
11448                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11449        });
11450        let cloned_prompt = bp_prompt.clone();
11451        let blocks = vec![BlockProperties {
11452            style: BlockStyle::Sticky,
11453            placement: BlockPlacement::Above(anchor),
11454            height: Some(height),
11455            render: Arc::new(move |cx| {
11456                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11457                cloned_prompt.clone().into_any_element()
11458            }),
11459            priority: 0,
11460        }];
11461
11462        let focus_handle = bp_prompt.focus_handle(cx);
11463        window.focus(&focus_handle, cx);
11464
11465        let block_ids = self.insert_blocks(blocks, None, cx);
11466        bp_prompt.update(cx, |prompt, _| {
11467            prompt.add_block_ids(block_ids);
11468        });
11469    }
11470
11471    pub(crate) fn breakpoint_at_row(
11472        &self,
11473        row: u32,
11474        window: &mut Window,
11475        cx: &mut Context<Self>,
11476    ) -> Option<(Anchor, Breakpoint)> {
11477        let snapshot = self.snapshot(window, cx);
11478        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11479
11480        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11481    }
11482
11483    pub(crate) fn breakpoint_at_anchor(
11484        &self,
11485        breakpoint_position: Anchor,
11486        snapshot: &EditorSnapshot,
11487        cx: &mut Context<Self>,
11488    ) -> Option<(Anchor, Breakpoint)> {
11489        let buffer = self
11490            .buffer
11491            .read(cx)
11492            .buffer_for_anchor(breakpoint_position, cx)?;
11493
11494        let enclosing_excerpt = breakpoint_position.excerpt_id;
11495        let buffer_snapshot = buffer.read(cx).snapshot();
11496
11497        let row = buffer_snapshot
11498            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11499            .row;
11500
11501        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11502        let anchor_end = snapshot
11503            .buffer_snapshot()
11504            .anchor_after(Point::new(row, line_len));
11505
11506        self.breakpoint_store
11507            .as_ref()?
11508            .read_with(cx, |breakpoint_store, cx| {
11509                breakpoint_store
11510                    .breakpoints(
11511                        &buffer,
11512                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11513                        &buffer_snapshot,
11514                        cx,
11515                    )
11516                    .next()
11517                    .and_then(|(bp, _)| {
11518                        let breakpoint_row = buffer_snapshot
11519                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11520                            .row;
11521
11522                        if breakpoint_row == row {
11523                            snapshot
11524                                .buffer_snapshot()
11525                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11526                                .map(|position| (position, bp.bp.clone()))
11527                        } else {
11528                            None
11529                        }
11530                    })
11531            })
11532    }
11533
11534    pub fn edit_log_breakpoint(
11535        &mut self,
11536        _: &EditLogBreakpoint,
11537        window: &mut Window,
11538        cx: &mut Context<Self>,
11539    ) {
11540        if self.breakpoint_store.is_none() {
11541            return;
11542        }
11543
11544        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11545            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11546                message: None,
11547                state: BreakpointState::Enabled,
11548                condition: None,
11549                hit_condition: None,
11550            });
11551
11552            self.add_edit_breakpoint_block(
11553                anchor,
11554                &breakpoint,
11555                BreakpointPromptEditAction::Log,
11556                window,
11557                cx,
11558            );
11559        }
11560    }
11561
11562    fn breakpoints_at_cursors(
11563        &self,
11564        window: &mut Window,
11565        cx: &mut Context<Self>,
11566    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11567        let snapshot = self.snapshot(window, cx);
11568        let cursors = self
11569            .selections
11570            .disjoint_anchors_arc()
11571            .iter()
11572            .map(|selection| {
11573                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11574
11575                let breakpoint_position = self
11576                    .breakpoint_at_row(cursor_position.row, window, cx)
11577                    .map(|bp| bp.0)
11578                    .unwrap_or_else(|| {
11579                        snapshot
11580                            .display_snapshot
11581                            .buffer_snapshot()
11582                            .anchor_after(Point::new(cursor_position.row, 0))
11583                    });
11584
11585                let breakpoint = self
11586                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11587                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11588
11589                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11590            })
11591            // 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.
11592            .collect::<HashMap<Anchor, _>>();
11593
11594        cursors.into_iter().collect()
11595    }
11596
11597    pub fn enable_breakpoint(
11598        &mut self,
11599        _: &crate::actions::EnableBreakpoint,
11600        window: &mut Window,
11601        cx: &mut Context<Self>,
11602    ) {
11603        if self.breakpoint_store.is_none() {
11604            return;
11605        }
11606
11607        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11608            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11609                continue;
11610            };
11611            self.edit_breakpoint_at_anchor(
11612                anchor,
11613                breakpoint,
11614                BreakpointEditAction::InvertState,
11615                cx,
11616            );
11617        }
11618    }
11619
11620    pub fn disable_breakpoint(
11621        &mut self,
11622        _: &crate::actions::DisableBreakpoint,
11623        window: &mut Window,
11624        cx: &mut Context<Self>,
11625    ) {
11626        if self.breakpoint_store.is_none() {
11627            return;
11628        }
11629
11630        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11631            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11632                continue;
11633            };
11634            self.edit_breakpoint_at_anchor(
11635                anchor,
11636                breakpoint,
11637                BreakpointEditAction::InvertState,
11638                cx,
11639            );
11640        }
11641    }
11642
11643    pub fn toggle_breakpoint(
11644        &mut self,
11645        _: &crate::actions::ToggleBreakpoint,
11646        window: &mut Window,
11647        cx: &mut Context<Self>,
11648    ) {
11649        if self.breakpoint_store.is_none() {
11650            return;
11651        }
11652
11653        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11654            if let Some(breakpoint) = breakpoint {
11655                self.edit_breakpoint_at_anchor(
11656                    anchor,
11657                    breakpoint,
11658                    BreakpointEditAction::Toggle,
11659                    cx,
11660                );
11661            } else {
11662                self.edit_breakpoint_at_anchor(
11663                    anchor,
11664                    Breakpoint::new_standard(),
11665                    BreakpointEditAction::Toggle,
11666                    cx,
11667                );
11668            }
11669        }
11670    }
11671
11672    pub fn edit_breakpoint_at_anchor(
11673        &mut self,
11674        breakpoint_position: Anchor,
11675        breakpoint: Breakpoint,
11676        edit_action: BreakpointEditAction,
11677        cx: &mut Context<Self>,
11678    ) {
11679        let Some(breakpoint_store) = &self.breakpoint_store else {
11680            return;
11681        };
11682
11683        let Some(buffer) = self
11684            .buffer
11685            .read(cx)
11686            .buffer_for_anchor(breakpoint_position, cx)
11687        else {
11688            return;
11689        };
11690
11691        breakpoint_store.update(cx, |breakpoint_store, cx| {
11692            breakpoint_store.toggle_breakpoint(
11693                buffer,
11694                BreakpointWithPosition {
11695                    position: breakpoint_position.text_anchor,
11696                    bp: breakpoint,
11697                },
11698                edit_action,
11699                cx,
11700            );
11701        });
11702
11703        cx.notify();
11704    }
11705
11706    #[cfg(any(test, feature = "test-support"))]
11707    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11708        self.breakpoint_store.clone()
11709    }
11710
11711    pub fn prepare_restore_change(
11712        &self,
11713        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11714        hunk: &MultiBufferDiffHunk,
11715        cx: &mut App,
11716    ) -> Option<()> {
11717        if hunk.is_created_file() {
11718            return None;
11719        }
11720        let buffer = self.buffer.read(cx);
11721        let diff = buffer.diff_for(hunk.buffer_id)?;
11722        let buffer = buffer.buffer(hunk.buffer_id)?;
11723        let buffer = buffer.read(cx);
11724        let original_text = diff
11725            .read(cx)
11726            .base_text(cx)
11727            .as_rope()
11728            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11729        let buffer_snapshot = buffer.snapshot();
11730        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11731        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11732            probe
11733                .0
11734                .start
11735                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11736                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11737        }) {
11738            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11739            Some(())
11740        } else {
11741            None
11742        }
11743    }
11744
11745    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11746        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11747    }
11748
11749    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11750        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11751    }
11752
11753    pub fn rotate_selections_forward(
11754        &mut self,
11755        _: &RotateSelectionsForward,
11756        window: &mut Window,
11757        cx: &mut Context<Self>,
11758    ) {
11759        self.rotate_selections(window, cx, false)
11760    }
11761
11762    pub fn rotate_selections_backward(
11763        &mut self,
11764        _: &RotateSelectionsBackward,
11765        window: &mut Window,
11766        cx: &mut Context<Self>,
11767    ) {
11768        self.rotate_selections(window, cx, true)
11769    }
11770
11771    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11773        let display_snapshot = self.display_snapshot(cx);
11774        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11775
11776        if selections.len() < 2 {
11777            return;
11778        }
11779
11780        let (edits, new_selections) = {
11781            let buffer = self.buffer.read(cx).read(cx);
11782            let has_selections = selections.iter().any(|s| !s.is_empty());
11783            if has_selections {
11784                let mut selected_texts: Vec<String> = selections
11785                    .iter()
11786                    .map(|selection| {
11787                        buffer
11788                            .text_for_range(selection.start..selection.end)
11789                            .collect()
11790                    })
11791                    .collect();
11792
11793                if reverse {
11794                    selected_texts.rotate_left(1);
11795                } else {
11796                    selected_texts.rotate_right(1);
11797                }
11798
11799                let mut offset_delta: i64 = 0;
11800                let mut new_selections = Vec::new();
11801                let edits: Vec<_> = selections
11802                    .iter()
11803                    .zip(selected_texts.iter())
11804                    .map(|(selection, new_text)| {
11805                        let old_len = (selection.end.0 - selection.start.0) as i64;
11806                        let new_len = new_text.len() as i64;
11807                        let adjusted_start =
11808                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11809                        let adjusted_end =
11810                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11811
11812                        new_selections.push(Selection {
11813                            id: selection.id,
11814                            start: adjusted_start,
11815                            end: adjusted_end,
11816                            reversed: selection.reversed,
11817                            goal: selection.goal,
11818                        });
11819
11820                        offset_delta += new_len - old_len;
11821                        (selection.start..selection.end, new_text.clone())
11822                    })
11823                    .collect();
11824                (edits, new_selections)
11825            } else {
11826                let mut all_rows: Vec<u32> = selections
11827                    .iter()
11828                    .map(|selection| buffer.offset_to_point(selection.start).row)
11829                    .collect();
11830                all_rows.sort_unstable();
11831                all_rows.dedup();
11832
11833                if all_rows.len() < 2 {
11834                    return;
11835                }
11836
11837                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11838                    .iter()
11839                    .map(|&row| {
11840                        let start = Point::new(row, 0);
11841                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11842                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11843                    })
11844                    .collect();
11845
11846                let mut line_texts: Vec<String> = line_ranges
11847                    .iter()
11848                    .map(|range| buffer.text_for_range(range.clone()).collect())
11849                    .collect();
11850
11851                if reverse {
11852                    line_texts.rotate_left(1);
11853                } else {
11854                    line_texts.rotate_right(1);
11855                }
11856
11857                let edits = line_ranges
11858                    .iter()
11859                    .zip(line_texts.iter())
11860                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11861                    .collect();
11862
11863                let num_rows = all_rows.len();
11864                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11865                    .iter()
11866                    .enumerate()
11867                    .map(|(i, &row)| (row, i))
11868                    .collect();
11869
11870                // Compute new line start offsets after rotation (handles CRLF)
11871                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11872                let first_line_start = line_ranges[0].start.0;
11873                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11874                for text in line_texts.iter().take(num_rows - 1) {
11875                    let prev_start = *new_line_starts.last().unwrap();
11876                    new_line_starts.push(prev_start + text.len() + newline_len);
11877                }
11878
11879                let new_selections = selections
11880                    .iter()
11881                    .map(|selection| {
11882                        let point = buffer.offset_to_point(selection.start);
11883                        let old_index = row_to_index[&point.row];
11884                        let new_index = if reverse {
11885                            (old_index + num_rows - 1) % num_rows
11886                        } else {
11887                            (old_index + 1) % num_rows
11888                        };
11889                        let new_offset =
11890                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11891                        Selection {
11892                            id: selection.id,
11893                            start: new_offset,
11894                            end: new_offset,
11895                            reversed: selection.reversed,
11896                            goal: selection.goal,
11897                        }
11898                    })
11899                    .collect();
11900
11901                (edits, new_selections)
11902            }
11903        };
11904
11905        self.transact(window, cx, |this, window, cx| {
11906            this.buffer.update(cx, |buffer, cx| {
11907                buffer.edit(edits, None, cx);
11908            });
11909            this.change_selections(Default::default(), window, cx, |s| {
11910                s.select(new_selections);
11911            });
11912        });
11913    }
11914
11915    fn manipulate_lines<M>(
11916        &mut self,
11917        window: &mut Window,
11918        cx: &mut Context<Self>,
11919        mut manipulate: M,
11920    ) where
11921        M: FnMut(&str) -> LineManipulationResult,
11922    {
11923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11924
11925        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11926        let buffer = self.buffer.read(cx).snapshot(cx);
11927
11928        let mut edits = Vec::new();
11929
11930        let selections = self.selections.all::<Point>(&display_map);
11931        let mut selections = selections.iter().peekable();
11932        let mut contiguous_row_selections = Vec::new();
11933        let mut new_selections = Vec::new();
11934        let mut added_lines = 0;
11935        let mut removed_lines = 0;
11936
11937        while let Some(selection) = selections.next() {
11938            let (start_row, end_row) = consume_contiguous_rows(
11939                &mut contiguous_row_selections,
11940                selection,
11941                &display_map,
11942                &mut selections,
11943            );
11944
11945            let start_point = Point::new(start_row.0, 0);
11946            let end_point = Point::new(
11947                end_row.previous_row().0,
11948                buffer.line_len(end_row.previous_row()),
11949            );
11950            let text = buffer
11951                .text_for_range(start_point..end_point)
11952                .collect::<String>();
11953
11954            let LineManipulationResult {
11955                new_text,
11956                line_count_before,
11957                line_count_after,
11958            } = manipulate(&text);
11959
11960            edits.push((start_point..end_point, new_text));
11961
11962            // Selections must change based on added and removed line count
11963            let start_row =
11964                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11965            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11966            new_selections.push(Selection {
11967                id: selection.id,
11968                start: start_row,
11969                end: end_row,
11970                goal: SelectionGoal::None,
11971                reversed: selection.reversed,
11972            });
11973
11974            if line_count_after > line_count_before {
11975                added_lines += line_count_after - line_count_before;
11976            } else if line_count_before > line_count_after {
11977                removed_lines += line_count_before - line_count_after;
11978            }
11979        }
11980
11981        self.transact(window, cx, |this, window, cx| {
11982            let buffer = this.buffer.update(cx, |buffer, cx| {
11983                buffer.edit(edits, None, cx);
11984                buffer.snapshot(cx)
11985            });
11986
11987            // Recalculate offsets on newly edited buffer
11988            let new_selections = new_selections
11989                .iter()
11990                .map(|s| {
11991                    let start_point = Point::new(s.start.0, 0);
11992                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11993                    Selection {
11994                        id: s.id,
11995                        start: buffer.point_to_offset(start_point),
11996                        end: buffer.point_to_offset(end_point),
11997                        goal: s.goal,
11998                        reversed: s.reversed,
11999                    }
12000                })
12001                .collect();
12002
12003            this.change_selections(Default::default(), window, cx, |s| {
12004                s.select(new_selections);
12005            });
12006
12007            this.request_autoscroll(Autoscroll::fit(), cx);
12008        });
12009    }
12010
12011    fn manipulate_immutable_lines<Fn>(
12012        &mut self,
12013        window: &mut Window,
12014        cx: &mut Context<Self>,
12015        mut callback: Fn,
12016    ) where
12017        Fn: FnMut(&mut Vec<&str>),
12018    {
12019        self.manipulate_lines(window, cx, |text| {
12020            let mut lines: Vec<&str> = text.split('\n').collect();
12021            let line_count_before = lines.len();
12022
12023            callback(&mut lines);
12024
12025            LineManipulationResult {
12026                new_text: lines.join("\n"),
12027                line_count_before,
12028                line_count_after: lines.len(),
12029            }
12030        });
12031    }
12032
12033    fn manipulate_mutable_lines<Fn>(
12034        &mut self,
12035        window: &mut Window,
12036        cx: &mut Context<Self>,
12037        mut callback: Fn,
12038    ) where
12039        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12040    {
12041        self.manipulate_lines(window, cx, |text| {
12042            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12043            let line_count_before = lines.len();
12044
12045            callback(&mut lines);
12046
12047            LineManipulationResult {
12048                new_text: lines.join("\n"),
12049                line_count_before,
12050                line_count_after: lines.len(),
12051            }
12052        });
12053    }
12054
12055    pub fn convert_indentation_to_spaces(
12056        &mut self,
12057        _: &ConvertIndentationToSpaces,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) {
12061        let settings = self.buffer.read(cx).language_settings(cx);
12062        let tab_size = settings.tab_size.get() as usize;
12063
12064        self.manipulate_mutable_lines(window, cx, |lines| {
12065            // Allocates a reasonably sized scratch buffer once for the whole loop
12066            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12067            // Avoids recomputing spaces that could be inserted many times
12068            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12069                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12070                .collect();
12071
12072            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12073                let mut chars = line.as_ref().chars();
12074                let mut col = 0;
12075                let mut changed = false;
12076
12077                for ch in chars.by_ref() {
12078                    match ch {
12079                        ' ' => {
12080                            reindented_line.push(' ');
12081                            col += 1;
12082                        }
12083                        '\t' => {
12084                            // \t are converted to spaces depending on the current column
12085                            let spaces_len = tab_size - (col % tab_size);
12086                            reindented_line.extend(&space_cache[spaces_len - 1]);
12087                            col += spaces_len;
12088                            changed = true;
12089                        }
12090                        _ => {
12091                            // If we dont append before break, the character is consumed
12092                            reindented_line.push(ch);
12093                            break;
12094                        }
12095                    }
12096                }
12097
12098                if !changed {
12099                    reindented_line.clear();
12100                    continue;
12101                }
12102                // Append the rest of the line and replace old reference with new one
12103                reindented_line.extend(chars);
12104                *line = Cow::Owned(reindented_line.clone());
12105                reindented_line.clear();
12106            }
12107        });
12108    }
12109
12110    pub fn convert_indentation_to_tabs(
12111        &mut self,
12112        _: &ConvertIndentationToTabs,
12113        window: &mut Window,
12114        cx: &mut Context<Self>,
12115    ) {
12116        let settings = self.buffer.read(cx).language_settings(cx);
12117        let tab_size = settings.tab_size.get() as usize;
12118
12119        self.manipulate_mutable_lines(window, cx, |lines| {
12120            // Allocates a reasonably sized buffer once for the whole loop
12121            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12122            // Avoids recomputing spaces that could be inserted many times
12123            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12124                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12125                .collect();
12126
12127            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12128                let mut chars = line.chars();
12129                let mut spaces_count = 0;
12130                let mut first_non_indent_char = None;
12131                let mut changed = false;
12132
12133                for ch in chars.by_ref() {
12134                    match ch {
12135                        ' ' => {
12136                            // Keep track of spaces. Append \t when we reach tab_size
12137                            spaces_count += 1;
12138                            changed = true;
12139                            if spaces_count == tab_size {
12140                                reindented_line.push('\t');
12141                                spaces_count = 0;
12142                            }
12143                        }
12144                        '\t' => {
12145                            reindented_line.push('\t');
12146                            spaces_count = 0;
12147                        }
12148                        _ => {
12149                            // Dont append it yet, we might have remaining spaces
12150                            first_non_indent_char = Some(ch);
12151                            break;
12152                        }
12153                    }
12154                }
12155
12156                if !changed {
12157                    reindented_line.clear();
12158                    continue;
12159                }
12160                // Remaining spaces that didn't make a full tab stop
12161                if spaces_count > 0 {
12162                    reindented_line.extend(&space_cache[spaces_count - 1]);
12163                }
12164                // If we consume an extra character that was not indentation, add it back
12165                if let Some(extra_char) = first_non_indent_char {
12166                    reindented_line.push(extra_char);
12167                }
12168                // Append the rest of the line and replace old reference with new one
12169                reindented_line.extend(chars);
12170                *line = Cow::Owned(reindented_line.clone());
12171                reindented_line.clear();
12172            }
12173        });
12174    }
12175
12176    pub fn convert_to_upper_case(
12177        &mut self,
12178        _: &ConvertToUpperCase,
12179        window: &mut Window,
12180        cx: &mut Context<Self>,
12181    ) {
12182        self.manipulate_text(window, cx, |text| text.to_uppercase())
12183    }
12184
12185    pub fn convert_to_lower_case(
12186        &mut self,
12187        _: &ConvertToLowerCase,
12188        window: &mut Window,
12189        cx: &mut Context<Self>,
12190    ) {
12191        self.manipulate_text(window, cx, |text| text.to_lowercase())
12192    }
12193
12194    pub fn convert_to_title_case(
12195        &mut self,
12196        _: &ConvertToTitleCase,
12197        window: &mut Window,
12198        cx: &mut Context<Self>,
12199    ) {
12200        self.manipulate_text(window, cx, |text| {
12201            text.split('\n')
12202                .map(|line| line.to_case(Case::Title))
12203                .join("\n")
12204        })
12205    }
12206
12207    pub fn convert_to_snake_case(
12208        &mut self,
12209        _: &ConvertToSnakeCase,
12210        window: &mut Window,
12211        cx: &mut Context<Self>,
12212    ) {
12213        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12214    }
12215
12216    pub fn convert_to_kebab_case(
12217        &mut self,
12218        _: &ConvertToKebabCase,
12219        window: &mut Window,
12220        cx: &mut Context<Self>,
12221    ) {
12222        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12223    }
12224
12225    pub fn convert_to_upper_camel_case(
12226        &mut self,
12227        _: &ConvertToUpperCamelCase,
12228        window: &mut Window,
12229        cx: &mut Context<Self>,
12230    ) {
12231        self.manipulate_text(window, cx, |text| {
12232            text.split('\n')
12233                .map(|line| line.to_case(Case::UpperCamel))
12234                .join("\n")
12235        })
12236    }
12237
12238    pub fn convert_to_lower_camel_case(
12239        &mut self,
12240        _: &ConvertToLowerCamelCase,
12241        window: &mut Window,
12242        cx: &mut Context<Self>,
12243    ) {
12244        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12245    }
12246
12247    pub fn convert_to_opposite_case(
12248        &mut self,
12249        _: &ConvertToOppositeCase,
12250        window: &mut Window,
12251        cx: &mut Context<Self>,
12252    ) {
12253        self.manipulate_text(window, cx, |text| {
12254            text.chars()
12255                .fold(String::with_capacity(text.len()), |mut t, c| {
12256                    if c.is_uppercase() {
12257                        t.extend(c.to_lowercase());
12258                    } else {
12259                        t.extend(c.to_uppercase());
12260                    }
12261                    t
12262                })
12263        })
12264    }
12265
12266    pub fn convert_to_sentence_case(
12267        &mut self,
12268        _: &ConvertToSentenceCase,
12269        window: &mut Window,
12270        cx: &mut Context<Self>,
12271    ) {
12272        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12273    }
12274
12275    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12276        self.manipulate_text(window, cx, |text| {
12277            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12278            if has_upper_case_characters {
12279                text.to_lowercase()
12280            } else {
12281                text.to_uppercase()
12282            }
12283        })
12284    }
12285
12286    pub fn convert_to_rot13(
12287        &mut self,
12288        _: &ConvertToRot13,
12289        window: &mut Window,
12290        cx: &mut Context<Self>,
12291    ) {
12292        self.manipulate_text(window, cx, |text| {
12293            text.chars()
12294                .map(|c| match c {
12295                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12296                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12297                    _ => c,
12298                })
12299                .collect()
12300        })
12301    }
12302
12303    pub fn convert_to_rot47(
12304        &mut self,
12305        _: &ConvertToRot47,
12306        window: &mut Window,
12307        cx: &mut Context<Self>,
12308    ) {
12309        self.manipulate_text(window, cx, |text| {
12310            text.chars()
12311                .map(|c| {
12312                    let code_point = c as u32;
12313                    if code_point >= 33 && code_point <= 126 {
12314                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12315                    }
12316                    c
12317                })
12318                .collect()
12319        })
12320    }
12321
12322    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12323    where
12324        Fn: FnMut(&str) -> String,
12325    {
12326        let buffer = self.buffer.read(cx).snapshot(cx);
12327
12328        let mut new_selections = Vec::new();
12329        let mut edits = Vec::new();
12330        let mut selection_adjustment = 0isize;
12331
12332        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12333            let selection_is_empty = selection.is_empty();
12334
12335            let (start, end) = if selection_is_empty {
12336                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12337                (word_range.start, word_range.end)
12338            } else {
12339                (
12340                    buffer.point_to_offset(selection.start),
12341                    buffer.point_to_offset(selection.end),
12342                )
12343            };
12344
12345            let text = buffer.text_for_range(start..end).collect::<String>();
12346            let old_length = text.len() as isize;
12347            let text = callback(&text);
12348
12349            new_selections.push(Selection {
12350                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12351                end: MultiBufferOffset(
12352                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12353                ),
12354                goal: SelectionGoal::None,
12355                id: selection.id,
12356                reversed: selection.reversed,
12357            });
12358
12359            selection_adjustment += old_length - text.len() as isize;
12360
12361            edits.push((start..end, text));
12362        }
12363
12364        self.transact(window, cx, |this, window, cx| {
12365            this.buffer.update(cx, |buffer, cx| {
12366                buffer.edit(edits, None, cx);
12367            });
12368
12369            this.change_selections(Default::default(), window, cx, |s| {
12370                s.select(new_selections);
12371            });
12372
12373            this.request_autoscroll(Autoscroll::fit(), cx);
12374        });
12375    }
12376
12377    pub fn move_selection_on_drop(
12378        &mut self,
12379        selection: &Selection<Anchor>,
12380        target: DisplayPoint,
12381        is_cut: bool,
12382        window: &mut Window,
12383        cx: &mut Context<Self>,
12384    ) {
12385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12386        let buffer = display_map.buffer_snapshot();
12387        let mut edits = Vec::new();
12388        let insert_point = display_map
12389            .clip_point(target, Bias::Left)
12390            .to_point(&display_map);
12391        let text = buffer
12392            .text_for_range(selection.start..selection.end)
12393            .collect::<String>();
12394        if is_cut {
12395            edits.push(((selection.start..selection.end), String::new()));
12396        }
12397        let insert_anchor = buffer.anchor_before(insert_point);
12398        edits.push(((insert_anchor..insert_anchor), text));
12399        let last_edit_start = insert_anchor.bias_left(buffer);
12400        let last_edit_end = insert_anchor.bias_right(buffer);
12401        self.transact(window, cx, |this, window, cx| {
12402            this.buffer.update(cx, |buffer, cx| {
12403                buffer.edit(edits, None, cx);
12404            });
12405            this.change_selections(Default::default(), window, cx, |s| {
12406                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12407            });
12408        });
12409    }
12410
12411    pub fn clear_selection_drag_state(&mut self) {
12412        self.selection_drag_state = SelectionDragState::None;
12413    }
12414
12415    pub fn duplicate(
12416        &mut self,
12417        upwards: bool,
12418        whole_lines: bool,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12423
12424        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12425        let buffer = display_map.buffer_snapshot();
12426        let selections = self.selections.all::<Point>(&display_map);
12427
12428        let mut edits = Vec::new();
12429        let mut selections_iter = selections.iter().peekable();
12430        while let Some(selection) = selections_iter.next() {
12431            let mut rows = selection.spanned_rows(false, &display_map);
12432            // duplicate line-wise
12433            if whole_lines || selection.start == selection.end {
12434                // Avoid duplicating the same lines twice.
12435                while let Some(next_selection) = selections_iter.peek() {
12436                    let next_rows = next_selection.spanned_rows(false, &display_map);
12437                    if next_rows.start < rows.end {
12438                        rows.end = next_rows.end;
12439                        selections_iter.next().unwrap();
12440                    } else {
12441                        break;
12442                    }
12443                }
12444
12445                // Copy the text from the selected row region and splice it either at the start
12446                // or end of the region.
12447                let start = Point::new(rows.start.0, 0);
12448                let end = Point::new(
12449                    rows.end.previous_row().0,
12450                    buffer.line_len(rows.end.previous_row()),
12451                );
12452
12453                let mut text = buffer.text_for_range(start..end).collect::<String>();
12454
12455                let insert_location = if upwards {
12456                    // When duplicating upward, we need to insert before the current line.
12457                    // If we're on the last line and it doesn't end with a newline,
12458                    // we need to add a newline before the duplicated content.
12459                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12460                        && buffer.max_point().column > 0
12461                        && !text.ends_with('\n');
12462
12463                    if needs_leading_newline {
12464                        text.insert(0, '\n');
12465                        end
12466                    } else {
12467                        text.push('\n');
12468                        Point::new(rows.start.0, 0)
12469                    }
12470                } else {
12471                    text.push('\n');
12472                    start
12473                };
12474                edits.push((insert_location..insert_location, text));
12475            } else {
12476                // duplicate character-wise
12477                let start = selection.start;
12478                let end = selection.end;
12479                let text = buffer.text_for_range(start..end).collect::<String>();
12480                edits.push((selection.end..selection.end, text));
12481            }
12482        }
12483
12484        self.transact(window, cx, |this, window, cx| {
12485            this.buffer.update(cx, |buffer, cx| {
12486                buffer.edit(edits, None, cx);
12487            });
12488
12489            // When duplicating upward with whole lines, move the cursor to the duplicated line
12490            if upwards && whole_lines {
12491                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12492
12493                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12494                    let mut new_ranges = Vec::new();
12495                    let selections = s.all::<Point>(&display_map);
12496                    let mut selections_iter = selections.iter().peekable();
12497
12498                    while let Some(first_selection) = selections_iter.next() {
12499                        // Group contiguous selections together to find the total row span
12500                        let mut group_selections = vec![first_selection];
12501                        let mut rows = first_selection.spanned_rows(false, &display_map);
12502
12503                        while let Some(next_selection) = selections_iter.peek() {
12504                            let next_rows = next_selection.spanned_rows(false, &display_map);
12505                            if next_rows.start < rows.end {
12506                                rows.end = next_rows.end;
12507                                group_selections.push(selections_iter.next().unwrap());
12508                            } else {
12509                                break;
12510                            }
12511                        }
12512
12513                        let row_count = rows.end.0 - rows.start.0;
12514
12515                        // Move all selections in this group up by the total number of duplicated rows
12516                        for selection in group_selections {
12517                            let new_start = Point::new(
12518                                selection.start.row.saturating_sub(row_count),
12519                                selection.start.column,
12520                            );
12521
12522                            let new_end = Point::new(
12523                                selection.end.row.saturating_sub(row_count),
12524                                selection.end.column,
12525                            );
12526
12527                            new_ranges.push(new_start..new_end);
12528                        }
12529                    }
12530
12531                    s.select_ranges(new_ranges);
12532                });
12533            }
12534
12535            this.request_autoscroll(Autoscroll::fit(), cx);
12536        });
12537    }
12538
12539    pub fn duplicate_line_up(
12540        &mut self,
12541        _: &DuplicateLineUp,
12542        window: &mut Window,
12543        cx: &mut Context<Self>,
12544    ) {
12545        self.duplicate(true, true, window, cx);
12546    }
12547
12548    pub fn duplicate_line_down(
12549        &mut self,
12550        _: &DuplicateLineDown,
12551        window: &mut Window,
12552        cx: &mut Context<Self>,
12553    ) {
12554        self.duplicate(false, true, window, cx);
12555    }
12556
12557    pub fn duplicate_selection(
12558        &mut self,
12559        _: &DuplicateSelection,
12560        window: &mut Window,
12561        cx: &mut Context<Self>,
12562    ) {
12563        self.duplicate(false, false, window, cx);
12564    }
12565
12566    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12568        if self.mode.is_single_line() {
12569            cx.propagate();
12570            return;
12571        }
12572
12573        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12574        let buffer = self.buffer.read(cx).snapshot(cx);
12575
12576        let mut edits = Vec::new();
12577        let mut unfold_ranges = Vec::new();
12578        let mut refold_creases = Vec::new();
12579
12580        let selections = self.selections.all::<Point>(&display_map);
12581        let mut selections = selections.iter().peekable();
12582        let mut contiguous_row_selections = Vec::new();
12583        let mut new_selections = Vec::new();
12584
12585        while let Some(selection) = selections.next() {
12586            // Find all the selections that span a contiguous row range
12587            let (start_row, end_row) = consume_contiguous_rows(
12588                &mut contiguous_row_selections,
12589                selection,
12590                &display_map,
12591                &mut selections,
12592            );
12593
12594            // Move the text spanned by the row range to be before the line preceding the row range
12595            if start_row.0 > 0 {
12596                let range_to_move = Point::new(
12597                    start_row.previous_row().0,
12598                    buffer.line_len(start_row.previous_row()),
12599                )
12600                    ..Point::new(
12601                        end_row.previous_row().0,
12602                        buffer.line_len(end_row.previous_row()),
12603                    );
12604                let insertion_point = display_map
12605                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12606                    .0;
12607
12608                // Don't move lines across excerpts
12609                if buffer
12610                    .excerpt_containing(insertion_point..range_to_move.end)
12611                    .is_some()
12612                {
12613                    let text = buffer
12614                        .text_for_range(range_to_move.clone())
12615                        .flat_map(|s| s.chars())
12616                        .skip(1)
12617                        .chain(['\n'])
12618                        .collect::<String>();
12619
12620                    edits.push((
12621                        buffer.anchor_after(range_to_move.start)
12622                            ..buffer.anchor_before(range_to_move.end),
12623                        String::new(),
12624                    ));
12625                    let insertion_anchor = buffer.anchor_after(insertion_point);
12626                    edits.push((insertion_anchor..insertion_anchor, text));
12627
12628                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12629
12630                    // Move selections up
12631                    new_selections.extend(contiguous_row_selections.drain(..).map(
12632                        |mut selection| {
12633                            selection.start.row -= row_delta;
12634                            selection.end.row -= row_delta;
12635                            selection
12636                        },
12637                    ));
12638
12639                    // Move folds up
12640                    unfold_ranges.push(range_to_move.clone());
12641                    for fold in display_map.folds_in_range(
12642                        buffer.anchor_before(range_to_move.start)
12643                            ..buffer.anchor_after(range_to_move.end),
12644                    ) {
12645                        let mut start = fold.range.start.to_point(&buffer);
12646                        let mut end = fold.range.end.to_point(&buffer);
12647                        start.row -= row_delta;
12648                        end.row -= row_delta;
12649                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12650                    }
12651                }
12652            }
12653
12654            // If we didn't move line(s), preserve the existing selections
12655            new_selections.append(&mut contiguous_row_selections);
12656        }
12657
12658        self.transact(window, cx, |this, window, cx| {
12659            this.unfold_ranges(&unfold_ranges, true, true, cx);
12660            this.buffer.update(cx, |buffer, cx| {
12661                for (range, text) in edits {
12662                    buffer.edit([(range, text)], None, cx);
12663                }
12664            });
12665            this.fold_creases(refold_creases, true, window, cx);
12666            this.change_selections(Default::default(), window, cx, |s| {
12667                s.select(new_selections);
12668            })
12669        });
12670    }
12671
12672    pub fn move_line_down(
12673        &mut self,
12674        _: &MoveLineDown,
12675        window: &mut Window,
12676        cx: &mut Context<Self>,
12677    ) {
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12679        if self.mode.is_single_line() {
12680            cx.propagate();
12681            return;
12682        }
12683
12684        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12685        let buffer = self.buffer.read(cx).snapshot(cx);
12686
12687        let mut edits = Vec::new();
12688        let mut unfold_ranges = Vec::new();
12689        let mut refold_creases = Vec::new();
12690
12691        let selections = self.selections.all::<Point>(&display_map);
12692        let mut selections = selections.iter().peekable();
12693        let mut contiguous_row_selections = Vec::new();
12694        let mut new_selections = Vec::new();
12695
12696        while let Some(selection) = selections.next() {
12697            // Find all the selections that span a contiguous row range
12698            let (start_row, end_row) = consume_contiguous_rows(
12699                &mut contiguous_row_selections,
12700                selection,
12701                &display_map,
12702                &mut selections,
12703            );
12704
12705            // Move the text spanned by the row range to be after the last line of the row range
12706            if end_row.0 <= buffer.max_point().row {
12707                let range_to_move =
12708                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12709                let insertion_point = display_map
12710                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12711                    .0;
12712
12713                // Don't move lines across excerpt boundaries
12714                if buffer
12715                    .excerpt_containing(range_to_move.start..insertion_point)
12716                    .is_some()
12717                {
12718                    let mut text = String::from("\n");
12719                    text.extend(buffer.text_for_range(range_to_move.clone()));
12720                    text.pop(); // Drop trailing newline
12721                    edits.push((
12722                        buffer.anchor_after(range_to_move.start)
12723                            ..buffer.anchor_before(range_to_move.end),
12724                        String::new(),
12725                    ));
12726                    let insertion_anchor = buffer.anchor_after(insertion_point);
12727                    edits.push((insertion_anchor..insertion_anchor, text));
12728
12729                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12730
12731                    // Move selections down
12732                    new_selections.extend(contiguous_row_selections.drain(..).map(
12733                        |mut selection| {
12734                            selection.start.row += row_delta;
12735                            selection.end.row += row_delta;
12736                            selection
12737                        },
12738                    ));
12739
12740                    // Move folds down
12741                    unfold_ranges.push(range_to_move.clone());
12742                    for fold in display_map.folds_in_range(
12743                        buffer.anchor_before(range_to_move.start)
12744                            ..buffer.anchor_after(range_to_move.end),
12745                    ) {
12746                        let mut start = fold.range.start.to_point(&buffer);
12747                        let mut end = fold.range.end.to_point(&buffer);
12748                        start.row += row_delta;
12749                        end.row += row_delta;
12750                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12751                    }
12752                }
12753            }
12754
12755            // If we didn't move line(s), preserve the existing selections
12756            new_selections.append(&mut contiguous_row_selections);
12757        }
12758
12759        self.transact(window, cx, |this, window, cx| {
12760            this.unfold_ranges(&unfold_ranges, true, true, cx);
12761            this.buffer.update(cx, |buffer, cx| {
12762                for (range, text) in edits {
12763                    buffer.edit([(range, text)], None, cx);
12764                }
12765            });
12766            this.fold_creases(refold_creases, true, window, cx);
12767            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12768        });
12769    }
12770
12771    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12773        let text_layout_details = &self.text_layout_details(window);
12774        self.transact(window, cx, |this, window, cx| {
12775            let edits = this.change_selections(Default::default(), window, cx, |s| {
12776                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12777                s.move_with(|display_map, selection| {
12778                    if !selection.is_empty() {
12779                        return;
12780                    }
12781
12782                    let mut head = selection.head();
12783                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12784                    if head.column() == display_map.line_len(head.row()) {
12785                        transpose_offset = display_map
12786                            .buffer_snapshot()
12787                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12788                    }
12789
12790                    if transpose_offset == MultiBufferOffset(0) {
12791                        return;
12792                    }
12793
12794                    *head.column_mut() += 1;
12795                    head = display_map.clip_point(head, Bias::Right);
12796                    let goal = SelectionGoal::HorizontalPosition(
12797                        display_map
12798                            .x_for_display_point(head, text_layout_details)
12799                            .into(),
12800                    );
12801                    selection.collapse_to(head, goal);
12802
12803                    let transpose_start = display_map
12804                        .buffer_snapshot()
12805                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12806                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12807                        let transpose_end = display_map
12808                            .buffer_snapshot()
12809                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12810                        if let Some(ch) = display_map
12811                            .buffer_snapshot()
12812                            .chars_at(transpose_start)
12813                            .next()
12814                        {
12815                            edits.push((transpose_start..transpose_offset, String::new()));
12816                            edits.push((transpose_end..transpose_end, ch.to_string()));
12817                        }
12818                    }
12819                });
12820                edits
12821            });
12822            this.buffer
12823                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12824            let selections = this
12825                .selections
12826                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12827            this.change_selections(Default::default(), window, cx, |s| {
12828                s.select(selections);
12829            });
12830        });
12831    }
12832
12833    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12835        if self.mode.is_single_line() {
12836            cx.propagate();
12837            return;
12838        }
12839
12840        self.rewrap_impl(RewrapOptions::default(), cx)
12841    }
12842
12843    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12844        let buffer = self.buffer.read(cx).snapshot(cx);
12845        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12846
12847        #[derive(Clone, Debug, PartialEq)]
12848        enum CommentFormat {
12849            /// single line comment, with prefix for line
12850            Line(String),
12851            /// single line within a block comment, with prefix for line
12852            BlockLine(String),
12853            /// a single line of a block comment that includes the initial delimiter
12854            BlockCommentWithStart(BlockCommentConfig),
12855            /// a single line of a block comment that includes the ending delimiter
12856            BlockCommentWithEnd(BlockCommentConfig),
12857        }
12858
12859        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12860        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12861            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12862                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12863                .peekable();
12864
12865            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12866                row
12867            } else {
12868                return Vec::new();
12869            };
12870
12871            let language_settings = buffer.language_settings_at(selection.head(), cx);
12872            let language_scope = buffer.language_scope_at(selection.head());
12873
12874            let indent_and_prefix_for_row =
12875                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12876                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12877                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12878                        &language_scope
12879                    {
12880                        let indent_end = Point::new(row, indent.len);
12881                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12882                        let line_text_after_indent = buffer
12883                            .text_for_range(indent_end..line_end)
12884                            .collect::<String>();
12885
12886                        let is_within_comment_override = buffer
12887                            .language_scope_at(indent_end)
12888                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12889                        let comment_delimiters = if is_within_comment_override {
12890                            // we are within a comment syntax node, but we don't
12891                            // yet know what kind of comment: block, doc or line
12892                            match (
12893                                language_scope.documentation_comment(),
12894                                language_scope.block_comment(),
12895                            ) {
12896                                (Some(config), _) | (_, Some(config))
12897                                    if buffer.contains_str_at(indent_end, &config.start) =>
12898                                {
12899                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12900                                }
12901                                (Some(config), _) | (_, Some(config))
12902                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12903                                {
12904                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12905                                }
12906                                (Some(config), _) | (_, Some(config))
12907                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12908                                {
12909                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12910                                }
12911                                (_, _) => language_scope
12912                                    .line_comment_prefixes()
12913                                    .iter()
12914                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12915                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12916                            }
12917                        } else {
12918                            // we not in an overridden comment node, but we may
12919                            // be within a non-overridden line comment node
12920                            language_scope
12921                                .line_comment_prefixes()
12922                                .iter()
12923                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12924                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12925                        };
12926
12927                        let rewrap_prefix = language_scope
12928                            .rewrap_prefixes()
12929                            .iter()
12930                            .find_map(|prefix_regex| {
12931                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12932                                    if mat.start() == 0 {
12933                                        Some(mat.as_str().to_string())
12934                                    } else {
12935                                        None
12936                                    }
12937                                })
12938                            })
12939                            .flatten();
12940                        (comment_delimiters, rewrap_prefix)
12941                    } else {
12942                        (None, None)
12943                    };
12944                    (indent, comment_prefix, rewrap_prefix)
12945                };
12946
12947            let mut ranges = Vec::new();
12948            let from_empty_selection = selection.is_empty();
12949
12950            let mut current_range_start = first_row;
12951            let mut prev_row = first_row;
12952            let (
12953                mut current_range_indent,
12954                mut current_range_comment_delimiters,
12955                mut current_range_rewrap_prefix,
12956            ) = indent_and_prefix_for_row(first_row);
12957
12958            for row in non_blank_rows_iter.skip(1) {
12959                let has_paragraph_break = row > prev_row + 1;
12960
12961                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12962                    indent_and_prefix_for_row(row);
12963
12964                let has_indent_change = row_indent != current_range_indent;
12965                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12966
12967                let has_boundary_change = has_comment_change
12968                    || row_rewrap_prefix.is_some()
12969                    || (has_indent_change && current_range_comment_delimiters.is_some());
12970
12971                if has_paragraph_break || has_boundary_change {
12972                    ranges.push((
12973                        language_settings.clone(),
12974                        Point::new(current_range_start, 0)
12975                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12976                        current_range_indent,
12977                        current_range_comment_delimiters.clone(),
12978                        current_range_rewrap_prefix.clone(),
12979                        from_empty_selection,
12980                    ));
12981                    current_range_start = row;
12982                    current_range_indent = row_indent;
12983                    current_range_comment_delimiters = row_comment_delimiters;
12984                    current_range_rewrap_prefix = row_rewrap_prefix;
12985                }
12986                prev_row = row;
12987            }
12988
12989            ranges.push((
12990                language_settings.clone(),
12991                Point::new(current_range_start, 0)
12992                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12993                current_range_indent,
12994                current_range_comment_delimiters,
12995                current_range_rewrap_prefix,
12996                from_empty_selection,
12997            ));
12998
12999            ranges
13000        });
13001
13002        let mut edits = Vec::new();
13003        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13004
13005        for (
13006            language_settings,
13007            wrap_range,
13008            mut indent_size,
13009            comment_prefix,
13010            rewrap_prefix,
13011            from_empty_selection,
13012        ) in wrap_ranges
13013        {
13014            let mut start_row = wrap_range.start.row;
13015            let mut end_row = wrap_range.end.row;
13016
13017            // Skip selections that overlap with a range that has already been rewrapped.
13018            let selection_range = start_row..end_row;
13019            if rewrapped_row_ranges
13020                .iter()
13021                .any(|range| range.overlaps(&selection_range))
13022            {
13023                continue;
13024            }
13025
13026            let tab_size = language_settings.tab_size;
13027
13028            let (line_prefix, inside_comment) = match &comment_prefix {
13029                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13030                    (Some(prefix.as_str()), true)
13031                }
13032                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13033                    (Some(prefix.as_ref()), true)
13034                }
13035                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13036                    start: _,
13037                    end: _,
13038                    prefix,
13039                    tab_size,
13040                })) => {
13041                    indent_size.len += tab_size;
13042                    (Some(prefix.as_ref()), true)
13043                }
13044                None => (None, false),
13045            };
13046            let indent_prefix = indent_size.chars().collect::<String>();
13047            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13048
13049            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13050                RewrapBehavior::InComments => inside_comment,
13051                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13052                RewrapBehavior::Anywhere => true,
13053            };
13054
13055            let should_rewrap = options.override_language_settings
13056                || allow_rewrap_based_on_language
13057                || self.hard_wrap.is_some();
13058            if !should_rewrap {
13059                continue;
13060            }
13061
13062            if from_empty_selection {
13063                'expand_upwards: while start_row > 0 {
13064                    let prev_row = start_row - 1;
13065                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13066                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13067                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13068                    {
13069                        start_row = prev_row;
13070                    } else {
13071                        break 'expand_upwards;
13072                    }
13073                }
13074
13075                'expand_downwards: while end_row < buffer.max_point().row {
13076                    let next_row = end_row + 1;
13077                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13078                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13079                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13080                    {
13081                        end_row = next_row;
13082                    } else {
13083                        break 'expand_downwards;
13084                    }
13085                }
13086            }
13087
13088            let start = Point::new(start_row, 0);
13089            let start_offset = ToOffset::to_offset(&start, &buffer);
13090            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13091            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13092            let mut first_line_delimiter = None;
13093            let mut last_line_delimiter = None;
13094            let Some(lines_without_prefixes) = selection_text
13095                .lines()
13096                .enumerate()
13097                .map(|(ix, line)| {
13098                    let line_trimmed = line.trim_start();
13099                    if rewrap_prefix.is_some() && ix > 0 {
13100                        Ok(line_trimmed)
13101                    } else if let Some(
13102                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13103                            start,
13104                            prefix,
13105                            end,
13106                            tab_size,
13107                        })
13108                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13109                            start,
13110                            prefix,
13111                            end,
13112                            tab_size,
13113                        }),
13114                    ) = &comment_prefix
13115                    {
13116                        let line_trimmed = line_trimmed
13117                            .strip_prefix(start.as_ref())
13118                            .map(|s| {
13119                                let mut indent_size = indent_size;
13120                                indent_size.len -= tab_size;
13121                                let indent_prefix: String = indent_size.chars().collect();
13122                                first_line_delimiter = Some((indent_prefix, start));
13123                                s.trim_start()
13124                            })
13125                            .unwrap_or(line_trimmed);
13126                        let line_trimmed = line_trimmed
13127                            .strip_suffix(end.as_ref())
13128                            .map(|s| {
13129                                last_line_delimiter = Some(end);
13130                                s.trim_end()
13131                            })
13132                            .unwrap_or(line_trimmed);
13133                        let line_trimmed = line_trimmed
13134                            .strip_prefix(prefix.as_ref())
13135                            .unwrap_or(line_trimmed);
13136                        Ok(line_trimmed)
13137                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13138                        line_trimmed.strip_prefix(prefix).with_context(|| {
13139                            format!("line did not start with prefix {prefix:?}: {line:?}")
13140                        })
13141                    } else {
13142                        line_trimmed
13143                            .strip_prefix(&line_prefix.trim_start())
13144                            .with_context(|| {
13145                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13146                            })
13147                    }
13148                })
13149                .collect::<Result<Vec<_>, _>>()
13150                .log_err()
13151            else {
13152                continue;
13153            };
13154
13155            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13156                buffer
13157                    .language_settings_at(Point::new(start_row, 0), cx)
13158                    .preferred_line_length as usize
13159            });
13160
13161            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13162                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13163            } else {
13164                line_prefix.clone()
13165            };
13166
13167            let wrapped_text = {
13168                let mut wrapped_text = wrap_with_prefix(
13169                    line_prefix,
13170                    subsequent_lines_prefix,
13171                    lines_without_prefixes.join("\n"),
13172                    wrap_column,
13173                    tab_size,
13174                    options.preserve_existing_whitespace,
13175                );
13176
13177                if let Some((indent, delimiter)) = first_line_delimiter {
13178                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13179                }
13180                if let Some(last_line) = last_line_delimiter {
13181                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13182                }
13183
13184                wrapped_text
13185            };
13186
13187            // TODO: should always use char-based diff while still supporting cursor behavior that
13188            // matches vim.
13189            let mut diff_options = DiffOptions::default();
13190            if options.override_language_settings {
13191                diff_options.max_word_diff_len = 0;
13192                diff_options.max_word_diff_line_count = 0;
13193            } else {
13194                diff_options.max_word_diff_len = usize::MAX;
13195                diff_options.max_word_diff_line_count = usize::MAX;
13196            }
13197
13198            for (old_range, new_text) in
13199                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13200            {
13201                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13202                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13203                edits.push((edit_start..edit_end, new_text));
13204            }
13205
13206            rewrapped_row_ranges.push(start_row..=end_row);
13207        }
13208
13209        self.buffer
13210            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13211    }
13212
13213    pub fn cut_common(
13214        &mut self,
13215        cut_no_selection_line: bool,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) -> ClipboardItem {
13219        let mut text = String::new();
13220        let buffer = self.buffer.read(cx).snapshot(cx);
13221        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13222        let mut clipboard_selections = Vec::with_capacity(selections.len());
13223        {
13224            let max_point = buffer.max_point();
13225            let mut is_first = true;
13226            let mut prev_selection_was_entire_line = false;
13227            for selection in &mut selections {
13228                let is_entire_line =
13229                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13230                if is_entire_line {
13231                    selection.start = Point::new(selection.start.row, 0);
13232                    if !selection.is_empty() && selection.end.column == 0 {
13233                        selection.end = cmp::min(max_point, selection.end);
13234                    } else {
13235                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13236                    }
13237                    selection.goal = SelectionGoal::None;
13238                }
13239                if is_first {
13240                    is_first = false;
13241                } else if !prev_selection_was_entire_line {
13242                    text += "\n";
13243                }
13244                prev_selection_was_entire_line = is_entire_line;
13245                let mut len = 0;
13246                for chunk in buffer.text_for_range(selection.start..selection.end) {
13247                    text.push_str(chunk);
13248                    len += chunk.len();
13249                }
13250
13251                clipboard_selections.push(ClipboardSelection::for_buffer(
13252                    len,
13253                    is_entire_line,
13254                    selection.range(),
13255                    &buffer,
13256                    self.project.as_ref(),
13257                    cx,
13258                ));
13259            }
13260        }
13261
13262        self.transact(window, cx, |this, window, cx| {
13263            this.change_selections(Default::default(), window, cx, |s| {
13264                s.select(selections);
13265            });
13266            this.insert("", window, cx);
13267        });
13268        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13269    }
13270
13271    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13273        let item = self.cut_common(true, window, cx);
13274        cx.write_to_clipboard(item);
13275    }
13276
13277    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13278        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13279        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13280            s.move_with(|snapshot, sel| {
13281                if sel.is_empty() {
13282                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13283                }
13284                if sel.is_empty() {
13285                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13286                }
13287            });
13288        });
13289        let item = self.cut_common(false, window, cx);
13290        cx.set_global(KillRing(item))
13291    }
13292
13293    pub fn kill_ring_yank(
13294        &mut self,
13295        _: &KillRingYank,
13296        window: &mut Window,
13297        cx: &mut Context<Self>,
13298    ) {
13299        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13300        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13301            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13302                (kill_ring.text().to_string(), kill_ring.metadata_json())
13303            } else {
13304                return;
13305            }
13306        } else {
13307            return;
13308        };
13309        self.do_paste(&text, metadata, false, window, cx);
13310    }
13311
13312    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13313        self.do_copy(true, cx);
13314    }
13315
13316    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13317        self.do_copy(false, cx);
13318    }
13319
13320    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13321        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13322        let buffer = self.buffer.read(cx).read(cx);
13323        let mut text = String::new();
13324
13325        let mut clipboard_selections = Vec::with_capacity(selections.len());
13326        {
13327            let max_point = buffer.max_point();
13328            let mut is_first = true;
13329            let mut prev_selection_was_entire_line = false;
13330            for selection in &selections {
13331                let mut start = selection.start;
13332                let mut end = selection.end;
13333                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13334                let mut add_trailing_newline = false;
13335                if is_entire_line {
13336                    start = Point::new(start.row, 0);
13337                    let next_line_start = Point::new(end.row + 1, 0);
13338                    if next_line_start <= max_point {
13339                        end = next_line_start;
13340                    } else {
13341                        // We're on the last line without a trailing newline.
13342                        // Copy to the end of the line and add a newline afterwards.
13343                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13344                        add_trailing_newline = true;
13345                    }
13346                }
13347
13348                let mut trimmed_selections = Vec::new();
13349                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13350                    let row = MultiBufferRow(start.row);
13351                    let first_indent = buffer.indent_size_for_line(row);
13352                    if first_indent.len == 0 || start.column > first_indent.len {
13353                        trimmed_selections.push(start..end);
13354                    } else {
13355                        trimmed_selections.push(
13356                            Point::new(row.0, first_indent.len)
13357                                ..Point::new(row.0, buffer.line_len(row)),
13358                        );
13359                        for row in start.row + 1..=end.row {
13360                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13361                            if row == end.row {
13362                                line_len = end.column;
13363                            }
13364                            if line_len == 0 {
13365                                trimmed_selections
13366                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13367                                continue;
13368                            }
13369                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13370                            if row_indent_size.len >= first_indent.len {
13371                                trimmed_selections.push(
13372                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13373                                );
13374                            } else {
13375                                trimmed_selections.clear();
13376                                trimmed_selections.push(start..end);
13377                                break;
13378                            }
13379                        }
13380                    }
13381                } else {
13382                    trimmed_selections.push(start..end);
13383                }
13384
13385                let is_multiline_trim = trimmed_selections.len() > 1;
13386                for trimmed_range in trimmed_selections {
13387                    if is_first {
13388                        is_first = false;
13389                    } else if is_multiline_trim || !prev_selection_was_entire_line {
13390                        text += "\n";
13391                    }
13392                    prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13393                    let mut len = 0;
13394                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13395                        text.push_str(chunk);
13396                        len += chunk.len();
13397                    }
13398                    if add_trailing_newline {
13399                        text.push('\n');
13400                        len += 1;
13401                    }
13402                    clipboard_selections.push(ClipboardSelection::for_buffer(
13403                        len,
13404                        is_entire_line,
13405                        trimmed_range,
13406                        &buffer,
13407                        self.project.as_ref(),
13408                        cx,
13409                    ));
13410                }
13411            }
13412        }
13413
13414        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13415            text,
13416            clipboard_selections,
13417        ));
13418    }
13419
13420    pub fn do_paste(
13421        &mut self,
13422        text: &String,
13423        clipboard_selections: Option<Vec<ClipboardSelection>>,
13424        handle_entire_lines: bool,
13425        window: &mut Window,
13426        cx: &mut Context<Self>,
13427    ) {
13428        if self.read_only(cx) {
13429            return;
13430        }
13431
13432        let clipboard_text = Cow::Borrowed(text.as_str());
13433
13434        self.transact(window, cx, |this, window, cx| {
13435            let had_active_edit_prediction = this.has_active_edit_prediction();
13436            let display_map = this.display_snapshot(cx);
13437            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13438            let cursor_offset = this
13439                .selections
13440                .last::<MultiBufferOffset>(&display_map)
13441                .head();
13442
13443            if let Some(mut clipboard_selections) = clipboard_selections {
13444                let all_selections_were_entire_line =
13445                    clipboard_selections.iter().all(|s| s.is_entire_line);
13446                let first_selection_indent_column =
13447                    clipboard_selections.first().map(|s| s.first_line_indent);
13448                if clipboard_selections.len() != old_selections.len() {
13449                    clipboard_selections.drain(..);
13450                }
13451                let mut auto_indent_on_paste = true;
13452
13453                this.buffer.update(cx, |buffer, cx| {
13454                    let snapshot = buffer.read(cx);
13455                    auto_indent_on_paste = snapshot
13456                        .language_settings_at(cursor_offset, cx)
13457                        .auto_indent_on_paste;
13458
13459                    let mut start_offset = 0;
13460                    let mut edits = Vec::new();
13461                    let mut original_indent_columns = Vec::new();
13462                    for (ix, selection) in old_selections.iter().enumerate() {
13463                        let to_insert;
13464                        let entire_line;
13465                        let original_indent_column;
13466                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13467                            let end_offset = start_offset + clipboard_selection.len;
13468                            to_insert = &clipboard_text[start_offset..end_offset];
13469                            entire_line = clipboard_selection.is_entire_line;
13470                            start_offset = if entire_line {
13471                                end_offset
13472                            } else {
13473                                end_offset + 1
13474                            };
13475                            original_indent_column = Some(clipboard_selection.first_line_indent);
13476                        } else {
13477                            to_insert = &*clipboard_text;
13478                            entire_line = all_selections_were_entire_line;
13479                            original_indent_column = first_selection_indent_column
13480                        }
13481
13482                        let (range, to_insert) =
13483                            if selection.is_empty() && handle_entire_lines && entire_line {
13484                                // If the corresponding selection was empty when this slice of the
13485                                // clipboard text was written, then the entire line containing the
13486                                // selection was copied. If this selection is also currently empty,
13487                                // then paste the line before the current line of the buffer.
13488                                let column = selection.start.to_point(&snapshot).column as usize;
13489                                let line_start = selection.start - column;
13490                                (line_start..line_start, Cow::Borrowed(to_insert))
13491                            } else {
13492                                let language = snapshot.language_at(selection.head());
13493                                let range = selection.range();
13494                                if let Some(language) = language
13495                                    && language.name() == "Markdown".into()
13496                                {
13497                                    edit_for_markdown_paste(
13498                                        &snapshot,
13499                                        range,
13500                                        to_insert,
13501                                        url::Url::parse(to_insert).ok(),
13502                                    )
13503                                } else {
13504                                    (range, Cow::Borrowed(to_insert))
13505                                }
13506                            };
13507
13508                        edits.push((range, to_insert));
13509                        original_indent_columns.push(original_indent_column);
13510                    }
13511                    drop(snapshot);
13512
13513                    buffer.edit(
13514                        edits,
13515                        if auto_indent_on_paste {
13516                            Some(AutoindentMode::Block {
13517                                original_indent_columns,
13518                            })
13519                        } else {
13520                            None
13521                        },
13522                        cx,
13523                    );
13524                });
13525
13526                let selections = this
13527                    .selections
13528                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13529                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13530            } else {
13531                let url = url::Url::parse(&clipboard_text).ok();
13532
13533                let auto_indent_mode = if !clipboard_text.is_empty() {
13534                    Some(AutoindentMode::Block {
13535                        original_indent_columns: Vec::new(),
13536                    })
13537                } else {
13538                    None
13539                };
13540
13541                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13542                    let snapshot = buffer.snapshot(cx);
13543
13544                    let anchors = old_selections
13545                        .iter()
13546                        .map(|s| {
13547                            let anchor = snapshot.anchor_after(s.head());
13548                            s.map(|_| anchor)
13549                        })
13550                        .collect::<Vec<_>>();
13551
13552                    let mut edits = Vec::new();
13553
13554                    for selection in old_selections.iter() {
13555                        let language = snapshot.language_at(selection.head());
13556                        let range = selection.range();
13557
13558                        let (edit_range, edit_text) = if let Some(language) = language
13559                            && language.name() == "Markdown".into()
13560                        {
13561                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13562                        } else {
13563                            (range, clipboard_text.clone())
13564                        };
13565
13566                        edits.push((edit_range, edit_text));
13567                    }
13568
13569                    drop(snapshot);
13570                    buffer.edit(edits, auto_indent_mode, cx);
13571
13572                    anchors
13573                });
13574
13575                this.change_selections(Default::default(), window, cx, |s| {
13576                    s.select_anchors(selection_anchors);
13577                });
13578            }
13579
13580            //   🤔                 |    ..     | show_in_menu |
13581            // | ..                  |   true        true
13582            // | had_edit_prediction |   false       true
13583
13584            let trigger_in_words =
13585                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13586
13587            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13588        });
13589    }
13590
13591    pub fn diff_clipboard_with_selection(
13592        &mut self,
13593        _: &DiffClipboardWithSelection,
13594        window: &mut Window,
13595        cx: &mut Context<Self>,
13596    ) {
13597        let selections = self
13598            .selections
13599            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13600
13601        if selections.is_empty() {
13602            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13603            return;
13604        };
13605
13606        let clipboard_text = match cx.read_from_clipboard() {
13607            Some(item) => match item.entries().first() {
13608                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13609                _ => None,
13610            },
13611            None => None,
13612        };
13613
13614        let Some(clipboard_text) = clipboard_text else {
13615            log::warn!("Clipboard doesn't contain text.");
13616            return;
13617        };
13618
13619        window.dispatch_action(
13620            Box::new(DiffClipboardWithSelectionData {
13621                clipboard_text,
13622                editor: cx.entity(),
13623            }),
13624            cx,
13625        );
13626    }
13627
13628    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13630        if let Some(item) = cx.read_from_clipboard() {
13631            let entries = item.entries();
13632
13633            match entries.first() {
13634                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13635                // of all the pasted entries.
13636                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13637                    .do_paste(
13638                        clipboard_string.text(),
13639                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13640                        true,
13641                        window,
13642                        cx,
13643                    ),
13644                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13645            }
13646        }
13647    }
13648
13649    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13650        if self.read_only(cx) {
13651            return;
13652        }
13653
13654        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13655
13656        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13657            if let Some((selections, _)) =
13658                self.selection_history.transaction(transaction_id).cloned()
13659            {
13660                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13661                    s.select_anchors(selections.to_vec());
13662                });
13663            } else {
13664                log::error!(
13665                    "No entry in selection_history found for undo. \
13666                     This may correspond to a bug where undo does not update the selection. \
13667                     If this is occurring, please add details to \
13668                     https://github.com/zed-industries/zed/issues/22692"
13669                );
13670            }
13671            self.request_autoscroll(Autoscroll::fit(), cx);
13672            self.unmark_text(window, cx);
13673            self.refresh_edit_prediction(true, false, window, cx);
13674            cx.emit(EditorEvent::Edited { transaction_id });
13675            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13676        }
13677    }
13678
13679    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13680        if self.read_only(cx) {
13681            return;
13682        }
13683
13684        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13685
13686        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13687            if let Some((_, Some(selections))) =
13688                self.selection_history.transaction(transaction_id).cloned()
13689            {
13690                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13691                    s.select_anchors(selections.to_vec());
13692                });
13693            } else {
13694                log::error!(
13695                    "No entry in selection_history found for redo. \
13696                     This may correspond to a bug where undo does not update the selection. \
13697                     If this is occurring, please add details to \
13698                     https://github.com/zed-industries/zed/issues/22692"
13699                );
13700            }
13701            self.request_autoscroll(Autoscroll::fit(), cx);
13702            self.unmark_text(window, cx);
13703            self.refresh_edit_prediction(true, false, window, cx);
13704            cx.emit(EditorEvent::Edited { transaction_id });
13705        }
13706    }
13707
13708    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13709        self.buffer
13710            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13711    }
13712
13713    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13714        self.buffer
13715            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13716    }
13717
13718    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13719        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13720        self.change_selections(Default::default(), window, cx, |s| {
13721            s.move_with(|map, selection| {
13722                let cursor = if selection.is_empty() {
13723                    movement::left(map, selection.start)
13724                } else {
13725                    selection.start
13726                };
13727                selection.collapse_to(cursor, SelectionGoal::None);
13728            });
13729        })
13730    }
13731
13732    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13734        self.change_selections(Default::default(), window, cx, |s| {
13735            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13736        })
13737    }
13738
13739    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13741        self.change_selections(Default::default(), window, cx, |s| {
13742            s.move_with(|map, selection| {
13743                let cursor = if selection.is_empty() {
13744                    movement::right(map, selection.end)
13745                } else {
13746                    selection.end
13747                };
13748                selection.collapse_to(cursor, SelectionGoal::None)
13749            });
13750        })
13751    }
13752
13753    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13755        self.change_selections(Default::default(), window, cx, |s| {
13756            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13757        });
13758    }
13759
13760    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13761        if self.take_rename(true, window, cx).is_some() {
13762            return;
13763        }
13764
13765        if self.mode.is_single_line() {
13766            cx.propagate();
13767            return;
13768        }
13769
13770        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13771
13772        let text_layout_details = &self.text_layout_details(window);
13773        let selection_count = self.selections.count();
13774        let first_selection = self.selections.first_anchor();
13775
13776        self.change_selections(Default::default(), window, cx, |s| {
13777            s.move_with(|map, selection| {
13778                if !selection.is_empty() {
13779                    selection.goal = SelectionGoal::None;
13780                }
13781                let (cursor, goal) = movement::up(
13782                    map,
13783                    selection.start,
13784                    selection.goal,
13785                    false,
13786                    text_layout_details,
13787                );
13788                selection.collapse_to(cursor, goal);
13789            });
13790        });
13791
13792        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13793        {
13794            cx.propagate();
13795        }
13796    }
13797
13798    pub fn move_up_by_lines(
13799        &mut self,
13800        action: &MoveUpByLines,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        if self.take_rename(true, window, cx).is_some() {
13805            return;
13806        }
13807
13808        if self.mode.is_single_line() {
13809            cx.propagate();
13810            return;
13811        }
13812
13813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13814
13815        let text_layout_details = &self.text_layout_details(window);
13816
13817        self.change_selections(Default::default(), window, cx, |s| {
13818            s.move_with(|map, selection| {
13819                if !selection.is_empty() {
13820                    selection.goal = SelectionGoal::None;
13821                }
13822                let (cursor, goal) = movement::up_by_rows(
13823                    map,
13824                    selection.start,
13825                    action.lines,
13826                    selection.goal,
13827                    false,
13828                    text_layout_details,
13829                );
13830                selection.collapse_to(cursor, goal);
13831            });
13832        })
13833    }
13834
13835    pub fn move_down_by_lines(
13836        &mut self,
13837        action: &MoveDownByLines,
13838        window: &mut Window,
13839        cx: &mut Context<Self>,
13840    ) {
13841        if self.take_rename(true, window, cx).is_some() {
13842            return;
13843        }
13844
13845        if self.mode.is_single_line() {
13846            cx.propagate();
13847            return;
13848        }
13849
13850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13851
13852        let text_layout_details = &self.text_layout_details(window);
13853
13854        self.change_selections(Default::default(), window, cx, |s| {
13855            s.move_with(|map, selection| {
13856                if !selection.is_empty() {
13857                    selection.goal = SelectionGoal::None;
13858                }
13859                let (cursor, goal) = movement::down_by_rows(
13860                    map,
13861                    selection.start,
13862                    action.lines,
13863                    selection.goal,
13864                    false,
13865                    text_layout_details,
13866                );
13867                selection.collapse_to(cursor, goal);
13868            });
13869        })
13870    }
13871
13872    pub fn select_down_by_lines(
13873        &mut self,
13874        action: &SelectDownByLines,
13875        window: &mut Window,
13876        cx: &mut Context<Self>,
13877    ) {
13878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13879        let text_layout_details = &self.text_layout_details(window);
13880        self.change_selections(Default::default(), window, cx, |s| {
13881            s.move_heads_with(|map, head, goal| {
13882                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13883            })
13884        })
13885    }
13886
13887    pub fn select_up_by_lines(
13888        &mut self,
13889        action: &SelectUpByLines,
13890        window: &mut Window,
13891        cx: &mut Context<Self>,
13892    ) {
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        let text_layout_details = &self.text_layout_details(window);
13895        self.change_selections(Default::default(), window, cx, |s| {
13896            s.move_heads_with(|map, head, goal| {
13897                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13898            })
13899        })
13900    }
13901
13902    pub fn select_page_up(
13903        &mut self,
13904        _: &SelectPageUp,
13905        window: &mut Window,
13906        cx: &mut Context<Self>,
13907    ) {
13908        let Some(row_count) = self.visible_row_count() else {
13909            return;
13910        };
13911
13912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13913
13914        let text_layout_details = &self.text_layout_details(window);
13915
13916        self.change_selections(Default::default(), window, cx, |s| {
13917            s.move_heads_with(|map, head, goal| {
13918                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13919            })
13920        })
13921    }
13922
13923    pub fn move_page_up(
13924        &mut self,
13925        action: &MovePageUp,
13926        window: &mut Window,
13927        cx: &mut Context<Self>,
13928    ) {
13929        if self.take_rename(true, window, cx).is_some() {
13930            return;
13931        }
13932
13933        if self
13934            .context_menu
13935            .borrow_mut()
13936            .as_mut()
13937            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13938            .unwrap_or(false)
13939        {
13940            return;
13941        }
13942
13943        if matches!(self.mode, EditorMode::SingleLine) {
13944            cx.propagate();
13945            return;
13946        }
13947
13948        let Some(row_count) = self.visible_row_count() else {
13949            return;
13950        };
13951
13952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13953
13954        let effects = if action.center_cursor {
13955            SelectionEffects::scroll(Autoscroll::center())
13956        } else {
13957            SelectionEffects::default()
13958        };
13959
13960        let text_layout_details = &self.text_layout_details(window);
13961
13962        self.change_selections(effects, window, cx, |s| {
13963            s.move_with(|map, selection| {
13964                if !selection.is_empty() {
13965                    selection.goal = SelectionGoal::None;
13966                }
13967                let (cursor, goal) = movement::up_by_rows(
13968                    map,
13969                    selection.end,
13970                    row_count,
13971                    selection.goal,
13972                    false,
13973                    text_layout_details,
13974                );
13975                selection.collapse_to(cursor, goal);
13976            });
13977        });
13978    }
13979
13980    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13982        let text_layout_details = &self.text_layout_details(window);
13983        self.change_selections(Default::default(), window, cx, |s| {
13984            s.move_heads_with(|map, head, goal| {
13985                movement::up(map, head, goal, false, text_layout_details)
13986            })
13987        })
13988    }
13989
13990    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13991        self.take_rename(true, window, cx);
13992
13993        if self.mode.is_single_line() {
13994            cx.propagate();
13995            return;
13996        }
13997
13998        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13999
14000        let text_layout_details = &self.text_layout_details(window);
14001        let selection_count = self.selections.count();
14002        let first_selection = self.selections.first_anchor();
14003
14004        self.change_selections(Default::default(), window, cx, |s| {
14005            s.move_with(|map, selection| {
14006                if !selection.is_empty() {
14007                    selection.goal = SelectionGoal::None;
14008                }
14009                let (cursor, goal) = movement::down(
14010                    map,
14011                    selection.end,
14012                    selection.goal,
14013                    false,
14014                    text_layout_details,
14015                );
14016                selection.collapse_to(cursor, goal);
14017            });
14018        });
14019
14020        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14021        {
14022            cx.propagate();
14023        }
14024    }
14025
14026    pub fn select_page_down(
14027        &mut self,
14028        _: &SelectPageDown,
14029        window: &mut Window,
14030        cx: &mut Context<Self>,
14031    ) {
14032        let Some(row_count) = self.visible_row_count() else {
14033            return;
14034        };
14035
14036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14037
14038        let text_layout_details = &self.text_layout_details(window);
14039
14040        self.change_selections(Default::default(), window, cx, |s| {
14041            s.move_heads_with(|map, head, goal| {
14042                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14043            })
14044        })
14045    }
14046
14047    pub fn move_page_down(
14048        &mut self,
14049        action: &MovePageDown,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        if self.take_rename(true, window, cx).is_some() {
14054            return;
14055        }
14056
14057        if self
14058            .context_menu
14059            .borrow_mut()
14060            .as_mut()
14061            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14062            .unwrap_or(false)
14063        {
14064            return;
14065        }
14066
14067        if matches!(self.mode, EditorMode::SingleLine) {
14068            cx.propagate();
14069            return;
14070        }
14071
14072        let Some(row_count) = self.visible_row_count() else {
14073            return;
14074        };
14075
14076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14077
14078        let effects = if action.center_cursor {
14079            SelectionEffects::scroll(Autoscroll::center())
14080        } else {
14081            SelectionEffects::default()
14082        };
14083
14084        let text_layout_details = &self.text_layout_details(window);
14085        self.change_selections(effects, window, cx, |s| {
14086            s.move_with(|map, selection| {
14087                if !selection.is_empty() {
14088                    selection.goal = SelectionGoal::None;
14089                }
14090                let (cursor, goal) = movement::down_by_rows(
14091                    map,
14092                    selection.end,
14093                    row_count,
14094                    selection.goal,
14095                    false,
14096                    text_layout_details,
14097                );
14098                selection.collapse_to(cursor, goal);
14099            });
14100        });
14101    }
14102
14103    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14105        let text_layout_details = &self.text_layout_details(window);
14106        self.change_selections(Default::default(), window, cx, |s| {
14107            s.move_heads_with(|map, head, goal| {
14108                movement::down(map, head, goal, false, text_layout_details)
14109            })
14110        });
14111    }
14112
14113    pub fn context_menu_first(
14114        &mut self,
14115        _: &ContextMenuFirst,
14116        window: &mut Window,
14117        cx: &mut Context<Self>,
14118    ) {
14119        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14120            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14121        }
14122    }
14123
14124    pub fn context_menu_prev(
14125        &mut self,
14126        _: &ContextMenuPrevious,
14127        window: &mut Window,
14128        cx: &mut Context<Self>,
14129    ) {
14130        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14131            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14132        }
14133    }
14134
14135    pub fn context_menu_next(
14136        &mut self,
14137        _: &ContextMenuNext,
14138        window: &mut Window,
14139        cx: &mut Context<Self>,
14140    ) {
14141        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14142            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14143        }
14144    }
14145
14146    pub fn context_menu_last(
14147        &mut self,
14148        _: &ContextMenuLast,
14149        window: &mut Window,
14150        cx: &mut Context<Self>,
14151    ) {
14152        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14153            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14154        }
14155    }
14156
14157    pub fn signature_help_prev(
14158        &mut self,
14159        _: &SignatureHelpPrevious,
14160        _: &mut Window,
14161        cx: &mut Context<Self>,
14162    ) {
14163        if let Some(popover) = self.signature_help_state.popover_mut() {
14164            if popover.current_signature == 0 {
14165                popover.current_signature = popover.signatures.len() - 1;
14166            } else {
14167                popover.current_signature -= 1;
14168            }
14169            cx.notify();
14170        }
14171    }
14172
14173    pub fn signature_help_next(
14174        &mut self,
14175        _: &SignatureHelpNext,
14176        _: &mut Window,
14177        cx: &mut Context<Self>,
14178    ) {
14179        if let Some(popover) = self.signature_help_state.popover_mut() {
14180            if popover.current_signature + 1 == popover.signatures.len() {
14181                popover.current_signature = 0;
14182            } else {
14183                popover.current_signature += 1;
14184            }
14185            cx.notify();
14186        }
14187    }
14188
14189    pub fn move_to_previous_word_start(
14190        &mut self,
14191        _: &MoveToPreviousWordStart,
14192        window: &mut Window,
14193        cx: &mut Context<Self>,
14194    ) {
14195        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14196        self.change_selections(Default::default(), window, cx, |s| {
14197            s.move_cursors_with(|map, head, _| {
14198                (
14199                    movement::previous_word_start(map, head),
14200                    SelectionGoal::None,
14201                )
14202            });
14203        })
14204    }
14205
14206    pub fn move_to_previous_subword_start(
14207        &mut self,
14208        _: &MoveToPreviousSubwordStart,
14209        window: &mut Window,
14210        cx: &mut Context<Self>,
14211    ) {
14212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14213        self.change_selections(Default::default(), window, cx, |s| {
14214            s.move_cursors_with(|map, head, _| {
14215                (
14216                    movement::previous_subword_start(map, head),
14217                    SelectionGoal::None,
14218                )
14219            });
14220        })
14221    }
14222
14223    pub fn select_to_previous_word_start(
14224        &mut self,
14225        _: &SelectToPreviousWordStart,
14226        window: &mut Window,
14227        cx: &mut Context<Self>,
14228    ) {
14229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14230        self.change_selections(Default::default(), window, cx, |s| {
14231            s.move_heads_with(|map, head, _| {
14232                (
14233                    movement::previous_word_start(map, head),
14234                    SelectionGoal::None,
14235                )
14236            });
14237        })
14238    }
14239
14240    pub fn select_to_previous_subword_start(
14241        &mut self,
14242        _: &SelectToPreviousSubwordStart,
14243        window: &mut Window,
14244        cx: &mut Context<Self>,
14245    ) {
14246        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14247        self.change_selections(Default::default(), window, cx, |s| {
14248            s.move_heads_with(|map, head, _| {
14249                (
14250                    movement::previous_subword_start(map, head),
14251                    SelectionGoal::None,
14252                )
14253            });
14254        })
14255    }
14256
14257    pub fn delete_to_previous_word_start(
14258        &mut self,
14259        action: &DeleteToPreviousWordStart,
14260        window: &mut Window,
14261        cx: &mut Context<Self>,
14262    ) {
14263        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14264        self.transact(window, cx, |this, window, cx| {
14265            this.select_autoclose_pair(window, cx);
14266            this.change_selections(Default::default(), window, cx, |s| {
14267                s.move_with(|map, selection| {
14268                    if selection.is_empty() {
14269                        let mut cursor = if action.ignore_newlines {
14270                            movement::previous_word_start(map, selection.head())
14271                        } else {
14272                            movement::previous_word_start_or_newline(map, selection.head())
14273                        };
14274                        cursor = movement::adjust_greedy_deletion(
14275                            map,
14276                            selection.head(),
14277                            cursor,
14278                            action.ignore_brackets,
14279                        );
14280                        selection.set_head(cursor, SelectionGoal::None);
14281                    }
14282                });
14283            });
14284            this.insert("", window, cx);
14285        });
14286    }
14287
14288    pub fn delete_to_previous_subword_start(
14289        &mut self,
14290        action: &DeleteToPreviousSubwordStart,
14291        window: &mut Window,
14292        cx: &mut Context<Self>,
14293    ) {
14294        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14295        self.transact(window, cx, |this, window, cx| {
14296            this.select_autoclose_pair(window, cx);
14297            this.change_selections(Default::default(), window, cx, |s| {
14298                s.move_with(|map, selection| {
14299                    if selection.is_empty() {
14300                        let mut cursor = if action.ignore_newlines {
14301                            movement::previous_subword_start(map, selection.head())
14302                        } else {
14303                            movement::previous_subword_start_or_newline(map, selection.head())
14304                        };
14305                        cursor = movement::adjust_greedy_deletion(
14306                            map,
14307                            selection.head(),
14308                            cursor,
14309                            action.ignore_brackets,
14310                        );
14311                        selection.set_head(cursor, SelectionGoal::None);
14312                    }
14313                });
14314            });
14315            this.insert("", window, cx);
14316        });
14317    }
14318
14319    pub fn move_to_next_word_end(
14320        &mut self,
14321        _: &MoveToNextWordEnd,
14322        window: &mut Window,
14323        cx: &mut Context<Self>,
14324    ) {
14325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14326        self.change_selections(Default::default(), window, cx, |s| {
14327            s.move_cursors_with(|map, head, _| {
14328                (movement::next_word_end(map, head), SelectionGoal::None)
14329            });
14330        })
14331    }
14332
14333    pub fn move_to_next_subword_end(
14334        &mut self,
14335        _: &MoveToNextSubwordEnd,
14336        window: &mut Window,
14337        cx: &mut Context<Self>,
14338    ) {
14339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14340        self.change_selections(Default::default(), window, cx, |s| {
14341            s.move_cursors_with(|map, head, _| {
14342                (movement::next_subword_end(map, head), SelectionGoal::None)
14343            });
14344        })
14345    }
14346
14347    pub fn select_to_next_word_end(
14348        &mut self,
14349        _: &SelectToNextWordEnd,
14350        window: &mut Window,
14351        cx: &mut Context<Self>,
14352    ) {
14353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14354        self.change_selections(Default::default(), window, cx, |s| {
14355            s.move_heads_with(|map, head, _| {
14356                (movement::next_word_end(map, head), SelectionGoal::None)
14357            });
14358        })
14359    }
14360
14361    pub fn select_to_next_subword_end(
14362        &mut self,
14363        _: &SelectToNextSubwordEnd,
14364        window: &mut Window,
14365        cx: &mut Context<Self>,
14366    ) {
14367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14368        self.change_selections(Default::default(), window, cx, |s| {
14369            s.move_heads_with(|map, head, _| {
14370                (movement::next_subword_end(map, head), SelectionGoal::None)
14371            });
14372        })
14373    }
14374
14375    pub fn delete_to_next_word_end(
14376        &mut self,
14377        action: &DeleteToNextWordEnd,
14378        window: &mut Window,
14379        cx: &mut Context<Self>,
14380    ) {
14381        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14382        self.transact(window, cx, |this, window, cx| {
14383            this.change_selections(Default::default(), window, cx, |s| {
14384                s.move_with(|map, selection| {
14385                    if selection.is_empty() {
14386                        let mut cursor = if action.ignore_newlines {
14387                            movement::next_word_end(map, selection.head())
14388                        } else {
14389                            movement::next_word_end_or_newline(map, selection.head())
14390                        };
14391                        cursor = movement::adjust_greedy_deletion(
14392                            map,
14393                            selection.head(),
14394                            cursor,
14395                            action.ignore_brackets,
14396                        );
14397                        selection.set_head(cursor, SelectionGoal::None);
14398                    }
14399                });
14400            });
14401            this.insert("", window, cx);
14402        });
14403    }
14404
14405    pub fn delete_to_next_subword_end(
14406        &mut self,
14407        action: &DeleteToNextSubwordEnd,
14408        window: &mut Window,
14409        cx: &mut Context<Self>,
14410    ) {
14411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14412        self.transact(window, cx, |this, window, cx| {
14413            this.change_selections(Default::default(), window, cx, |s| {
14414                s.move_with(|map, selection| {
14415                    if selection.is_empty() {
14416                        let mut cursor = if action.ignore_newlines {
14417                            movement::next_subword_end(map, selection.head())
14418                        } else {
14419                            movement::next_subword_end_or_newline(map, selection.head())
14420                        };
14421                        cursor = movement::adjust_greedy_deletion(
14422                            map,
14423                            selection.head(),
14424                            cursor,
14425                            action.ignore_brackets,
14426                        );
14427                        selection.set_head(cursor, SelectionGoal::None);
14428                    }
14429                });
14430            });
14431            this.insert("", window, cx);
14432        });
14433    }
14434
14435    pub fn move_to_beginning_of_line(
14436        &mut self,
14437        action: &MoveToBeginningOfLine,
14438        window: &mut Window,
14439        cx: &mut Context<Self>,
14440    ) {
14441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14442        self.change_selections(Default::default(), window, cx, |s| {
14443            s.move_cursors_with(|map, head, _| {
14444                (
14445                    movement::indented_line_beginning(
14446                        map,
14447                        head,
14448                        action.stop_at_soft_wraps,
14449                        action.stop_at_indent,
14450                    ),
14451                    SelectionGoal::None,
14452                )
14453            });
14454        })
14455    }
14456
14457    pub fn select_to_beginning_of_line(
14458        &mut self,
14459        action: &SelectToBeginningOfLine,
14460        window: &mut Window,
14461        cx: &mut Context<Self>,
14462    ) {
14463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14464        self.change_selections(Default::default(), window, cx, |s| {
14465            s.move_heads_with(|map, head, _| {
14466                (
14467                    movement::indented_line_beginning(
14468                        map,
14469                        head,
14470                        action.stop_at_soft_wraps,
14471                        action.stop_at_indent,
14472                    ),
14473                    SelectionGoal::None,
14474                )
14475            });
14476        });
14477    }
14478
14479    pub fn delete_to_beginning_of_line(
14480        &mut self,
14481        action: &DeleteToBeginningOfLine,
14482        window: &mut Window,
14483        cx: &mut Context<Self>,
14484    ) {
14485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14486        self.transact(window, cx, |this, window, cx| {
14487            this.change_selections(Default::default(), window, cx, |s| {
14488                s.move_with(|_, selection| {
14489                    selection.reversed = true;
14490                });
14491            });
14492
14493            this.select_to_beginning_of_line(
14494                &SelectToBeginningOfLine {
14495                    stop_at_soft_wraps: false,
14496                    stop_at_indent: action.stop_at_indent,
14497                },
14498                window,
14499                cx,
14500            );
14501            this.backspace(&Backspace, window, cx);
14502        });
14503    }
14504
14505    pub fn move_to_end_of_line(
14506        &mut self,
14507        action: &MoveToEndOfLine,
14508        window: &mut Window,
14509        cx: &mut Context<Self>,
14510    ) {
14511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14512        self.change_selections(Default::default(), window, cx, |s| {
14513            s.move_cursors_with(|map, head, _| {
14514                (
14515                    movement::line_end(map, head, action.stop_at_soft_wraps),
14516                    SelectionGoal::None,
14517                )
14518            });
14519        })
14520    }
14521
14522    pub fn select_to_end_of_line(
14523        &mut self,
14524        action: &SelectToEndOfLine,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) {
14528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14529        self.change_selections(Default::default(), window, cx, |s| {
14530            s.move_heads_with(|map, head, _| {
14531                (
14532                    movement::line_end(map, head, action.stop_at_soft_wraps),
14533                    SelectionGoal::None,
14534                )
14535            });
14536        })
14537    }
14538
14539    pub fn delete_to_end_of_line(
14540        &mut self,
14541        _: &DeleteToEndOfLine,
14542        window: &mut Window,
14543        cx: &mut Context<Self>,
14544    ) {
14545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14546        self.transact(window, cx, |this, window, cx| {
14547            this.select_to_end_of_line(
14548                &SelectToEndOfLine {
14549                    stop_at_soft_wraps: false,
14550                },
14551                window,
14552                cx,
14553            );
14554            this.delete(&Delete, window, cx);
14555        });
14556    }
14557
14558    pub fn cut_to_end_of_line(
14559        &mut self,
14560        action: &CutToEndOfLine,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14565        self.transact(window, cx, |this, window, cx| {
14566            this.select_to_end_of_line(
14567                &SelectToEndOfLine {
14568                    stop_at_soft_wraps: false,
14569                },
14570                window,
14571                cx,
14572            );
14573            if !action.stop_at_newlines {
14574                this.change_selections(Default::default(), window, cx, |s| {
14575                    s.move_with(|_, sel| {
14576                        if sel.is_empty() {
14577                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14578                        }
14579                    });
14580                });
14581            }
14582            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14583            let item = this.cut_common(false, window, cx);
14584            cx.write_to_clipboard(item);
14585        });
14586    }
14587
14588    pub fn move_to_start_of_paragraph(
14589        &mut self,
14590        _: &MoveToStartOfParagraph,
14591        window: &mut Window,
14592        cx: &mut Context<Self>,
14593    ) {
14594        if matches!(self.mode, EditorMode::SingleLine) {
14595            cx.propagate();
14596            return;
14597        }
14598        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14599        self.change_selections(Default::default(), window, cx, |s| {
14600            s.move_with(|map, selection| {
14601                selection.collapse_to(
14602                    movement::start_of_paragraph(map, selection.head(), 1),
14603                    SelectionGoal::None,
14604                )
14605            });
14606        })
14607    }
14608
14609    pub fn move_to_end_of_paragraph(
14610        &mut self,
14611        _: &MoveToEndOfParagraph,
14612        window: &mut Window,
14613        cx: &mut Context<Self>,
14614    ) {
14615        if matches!(self.mode, EditorMode::SingleLine) {
14616            cx.propagate();
14617            return;
14618        }
14619        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14620        self.change_selections(Default::default(), window, cx, |s| {
14621            s.move_with(|map, selection| {
14622                selection.collapse_to(
14623                    movement::end_of_paragraph(map, selection.head(), 1),
14624                    SelectionGoal::None,
14625                )
14626            });
14627        })
14628    }
14629
14630    pub fn select_to_start_of_paragraph(
14631        &mut self,
14632        _: &SelectToStartOfParagraph,
14633        window: &mut Window,
14634        cx: &mut Context<Self>,
14635    ) {
14636        if matches!(self.mode, EditorMode::SingleLine) {
14637            cx.propagate();
14638            return;
14639        }
14640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14641        self.change_selections(Default::default(), window, cx, |s| {
14642            s.move_heads_with(|map, head, _| {
14643                (
14644                    movement::start_of_paragraph(map, head, 1),
14645                    SelectionGoal::None,
14646                )
14647            });
14648        })
14649    }
14650
14651    pub fn select_to_end_of_paragraph(
14652        &mut self,
14653        _: &SelectToEndOfParagraph,
14654        window: &mut Window,
14655        cx: &mut Context<Self>,
14656    ) {
14657        if matches!(self.mode, EditorMode::SingleLine) {
14658            cx.propagate();
14659            return;
14660        }
14661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14662        self.change_selections(Default::default(), window, cx, |s| {
14663            s.move_heads_with(|map, head, _| {
14664                (
14665                    movement::end_of_paragraph(map, head, 1),
14666                    SelectionGoal::None,
14667                )
14668            });
14669        })
14670    }
14671
14672    pub fn move_to_start_of_excerpt(
14673        &mut self,
14674        _: &MoveToStartOfExcerpt,
14675        window: &mut Window,
14676        cx: &mut Context<Self>,
14677    ) {
14678        if matches!(self.mode, EditorMode::SingleLine) {
14679            cx.propagate();
14680            return;
14681        }
14682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14683        self.change_selections(Default::default(), window, cx, |s| {
14684            s.move_with(|map, selection| {
14685                selection.collapse_to(
14686                    movement::start_of_excerpt(
14687                        map,
14688                        selection.head(),
14689                        workspace::searchable::Direction::Prev,
14690                    ),
14691                    SelectionGoal::None,
14692                )
14693            });
14694        })
14695    }
14696
14697    pub fn move_to_start_of_next_excerpt(
14698        &mut self,
14699        _: &MoveToStartOfNextExcerpt,
14700        window: &mut Window,
14701        cx: &mut Context<Self>,
14702    ) {
14703        if matches!(self.mode, EditorMode::SingleLine) {
14704            cx.propagate();
14705            return;
14706        }
14707
14708        self.change_selections(Default::default(), window, cx, |s| {
14709            s.move_with(|map, selection| {
14710                selection.collapse_to(
14711                    movement::start_of_excerpt(
14712                        map,
14713                        selection.head(),
14714                        workspace::searchable::Direction::Next,
14715                    ),
14716                    SelectionGoal::None,
14717                )
14718            });
14719        })
14720    }
14721
14722    pub fn move_to_end_of_excerpt(
14723        &mut self,
14724        _: &MoveToEndOfExcerpt,
14725        window: &mut Window,
14726        cx: &mut Context<Self>,
14727    ) {
14728        if matches!(self.mode, EditorMode::SingleLine) {
14729            cx.propagate();
14730            return;
14731        }
14732        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14733        self.change_selections(Default::default(), window, cx, |s| {
14734            s.move_with(|map, selection| {
14735                selection.collapse_to(
14736                    movement::end_of_excerpt(
14737                        map,
14738                        selection.head(),
14739                        workspace::searchable::Direction::Next,
14740                    ),
14741                    SelectionGoal::None,
14742                )
14743            });
14744        })
14745    }
14746
14747    pub fn move_to_end_of_previous_excerpt(
14748        &mut self,
14749        _: &MoveToEndOfPreviousExcerpt,
14750        window: &mut Window,
14751        cx: &mut Context<Self>,
14752    ) {
14753        if matches!(self.mode, EditorMode::SingleLine) {
14754            cx.propagate();
14755            return;
14756        }
14757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14758        self.change_selections(Default::default(), window, cx, |s| {
14759            s.move_with(|map, selection| {
14760                selection.collapse_to(
14761                    movement::end_of_excerpt(
14762                        map,
14763                        selection.head(),
14764                        workspace::searchable::Direction::Prev,
14765                    ),
14766                    SelectionGoal::None,
14767                )
14768            });
14769        })
14770    }
14771
14772    pub fn select_to_start_of_excerpt(
14773        &mut self,
14774        _: &SelectToStartOfExcerpt,
14775        window: &mut Window,
14776        cx: &mut Context<Self>,
14777    ) {
14778        if matches!(self.mode, EditorMode::SingleLine) {
14779            cx.propagate();
14780            return;
14781        }
14782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14783        self.change_selections(Default::default(), window, cx, |s| {
14784            s.move_heads_with(|map, head, _| {
14785                (
14786                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14787                    SelectionGoal::None,
14788                )
14789            });
14790        })
14791    }
14792
14793    pub fn select_to_start_of_next_excerpt(
14794        &mut self,
14795        _: &SelectToStartOfNextExcerpt,
14796        window: &mut Window,
14797        cx: &mut Context<Self>,
14798    ) {
14799        if matches!(self.mode, EditorMode::SingleLine) {
14800            cx.propagate();
14801            return;
14802        }
14803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14804        self.change_selections(Default::default(), window, cx, |s| {
14805            s.move_heads_with(|map, head, _| {
14806                (
14807                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14808                    SelectionGoal::None,
14809                )
14810            });
14811        })
14812    }
14813
14814    pub fn select_to_end_of_excerpt(
14815        &mut self,
14816        _: &SelectToEndOfExcerpt,
14817        window: &mut Window,
14818        cx: &mut Context<Self>,
14819    ) {
14820        if matches!(self.mode, EditorMode::SingleLine) {
14821            cx.propagate();
14822            return;
14823        }
14824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14825        self.change_selections(Default::default(), window, cx, |s| {
14826            s.move_heads_with(|map, head, _| {
14827                (
14828                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14829                    SelectionGoal::None,
14830                )
14831            });
14832        })
14833    }
14834
14835    pub fn select_to_end_of_previous_excerpt(
14836        &mut self,
14837        _: &SelectToEndOfPreviousExcerpt,
14838        window: &mut Window,
14839        cx: &mut Context<Self>,
14840    ) {
14841        if matches!(self.mode, EditorMode::SingleLine) {
14842            cx.propagate();
14843            return;
14844        }
14845        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14846        self.change_selections(Default::default(), window, cx, |s| {
14847            s.move_heads_with(|map, head, _| {
14848                (
14849                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14850                    SelectionGoal::None,
14851                )
14852            });
14853        })
14854    }
14855
14856    pub fn move_to_beginning(
14857        &mut self,
14858        _: &MoveToBeginning,
14859        window: &mut Window,
14860        cx: &mut Context<Self>,
14861    ) {
14862        if matches!(self.mode, EditorMode::SingleLine) {
14863            cx.propagate();
14864            return;
14865        }
14866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14867        self.change_selections(Default::default(), window, cx, |s| {
14868            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14869        });
14870    }
14871
14872    pub fn select_to_beginning(
14873        &mut self,
14874        _: &SelectToBeginning,
14875        window: &mut Window,
14876        cx: &mut Context<Self>,
14877    ) {
14878        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14879        selection.set_head(Point::zero(), SelectionGoal::None);
14880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14881        self.change_selections(Default::default(), window, cx, |s| {
14882            s.select(vec![selection]);
14883        });
14884    }
14885
14886    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14887        if matches!(self.mode, EditorMode::SingleLine) {
14888            cx.propagate();
14889            return;
14890        }
14891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14892        let cursor = self.buffer.read(cx).read(cx).len();
14893        self.change_selections(Default::default(), window, cx, |s| {
14894            s.select_ranges(vec![cursor..cursor])
14895        });
14896    }
14897
14898    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14899        self.nav_history = nav_history;
14900    }
14901
14902    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14903        self.nav_history.as_ref()
14904    }
14905
14906    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14907        self.push_to_nav_history(
14908            self.selections.newest_anchor().head(),
14909            None,
14910            false,
14911            true,
14912            cx,
14913        );
14914    }
14915
14916    fn navigation_data(&self, cursor_anchor: Anchor, cx: &App) -> NavigationData {
14917        let buffer = self.buffer.read(cx).read(cx);
14918        let cursor_position = cursor_anchor.to_point(&buffer);
14919        let scroll_anchor = self.scroll_manager.anchor();
14920        let scroll_top_row = scroll_anchor.top_row(&buffer);
14921        drop(buffer);
14922
14923        NavigationData {
14924            cursor_anchor,
14925            cursor_position,
14926            scroll_anchor,
14927            scroll_top_row,
14928        }
14929    }
14930
14931    fn navigation_entry(&self, cursor_anchor: Anchor, cx: &App) -> Option<NavigationEntry> {
14932        let Some(history) = self.nav_history.clone() else {
14933            return None;
14934        };
14935        let data = self.navigation_data(cursor_anchor, cx);
14936        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
14937    }
14938
14939    fn push_to_nav_history(
14940        &mut self,
14941        cursor_anchor: Anchor,
14942        new_position: Option<Point>,
14943        is_deactivate: bool,
14944        always: bool,
14945        cx: &mut Context<Self>,
14946    ) {
14947        let data = self.navigation_data(cursor_anchor, cx);
14948        if let Some(nav_history) = self.nav_history.as_mut() {
14949            if let Some(new_position) = new_position {
14950                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
14951                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14952                    return;
14953                }
14954            }
14955
14956            nav_history.push(Some(data), cx);
14957            cx.emit(EditorEvent::PushedToNavHistory {
14958                anchor: cursor_anchor,
14959                is_deactivate,
14960            })
14961        }
14962    }
14963
14964    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14966        let buffer = self.buffer.read(cx).snapshot(cx);
14967        let mut selection = self
14968            .selections
14969            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14970        selection.set_head(buffer.len(), SelectionGoal::None);
14971        self.change_selections(Default::default(), window, cx, |s| {
14972            s.select(vec![selection]);
14973        });
14974    }
14975
14976    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14978        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14979            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14980        });
14981    }
14982
14983    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14986        let mut selections = self.selections.all::<Point>(&display_map);
14987        let max_point = display_map.buffer_snapshot().max_point();
14988        for selection in &mut selections {
14989            let rows = selection.spanned_rows(true, &display_map);
14990            selection.start = Point::new(rows.start.0, 0);
14991            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14992            selection.reversed = false;
14993        }
14994        self.change_selections(Default::default(), window, cx, |s| {
14995            s.select(selections);
14996        });
14997    }
14998
14999    pub fn split_selection_into_lines(
15000        &mut self,
15001        action: &SplitSelectionIntoLines,
15002        window: &mut Window,
15003        cx: &mut Context<Self>,
15004    ) {
15005        let selections = self
15006            .selections
15007            .all::<Point>(&self.display_snapshot(cx))
15008            .into_iter()
15009            .map(|selection| selection.start..selection.end)
15010            .collect::<Vec<_>>();
15011        self.unfold_ranges(&selections, true, true, cx);
15012
15013        let mut new_selection_ranges = Vec::new();
15014        {
15015            let buffer = self.buffer.read(cx).read(cx);
15016            for selection in selections {
15017                for row in selection.start.row..selection.end.row {
15018                    let line_start = Point::new(row, 0);
15019                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15020
15021                    if action.keep_selections {
15022                        // Keep the selection range for each line
15023                        let selection_start = if row == selection.start.row {
15024                            selection.start
15025                        } else {
15026                            line_start
15027                        };
15028                        new_selection_ranges.push(selection_start..line_end);
15029                    } else {
15030                        // Collapse to cursor at end of line
15031                        new_selection_ranges.push(line_end..line_end);
15032                    }
15033                }
15034
15035                let is_multiline_selection = selection.start.row != selection.end.row;
15036                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15037                // so this action feels more ergonomic when paired with other selection operations
15038                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15039                if !should_skip_last {
15040                    if action.keep_selections {
15041                        if is_multiline_selection {
15042                            let line_start = Point::new(selection.end.row, 0);
15043                            new_selection_ranges.push(line_start..selection.end);
15044                        } else {
15045                            new_selection_ranges.push(selection.start..selection.end);
15046                        }
15047                    } else {
15048                        new_selection_ranges.push(selection.end..selection.end);
15049                    }
15050                }
15051            }
15052        }
15053        self.change_selections(Default::default(), window, cx, |s| {
15054            s.select_ranges(new_selection_ranges);
15055        });
15056    }
15057
15058    pub fn add_selection_above(
15059        &mut self,
15060        action: &AddSelectionAbove,
15061        window: &mut Window,
15062        cx: &mut Context<Self>,
15063    ) {
15064        self.add_selection(true, action.skip_soft_wrap, window, cx);
15065    }
15066
15067    pub fn add_selection_below(
15068        &mut self,
15069        action: &AddSelectionBelow,
15070        window: &mut Window,
15071        cx: &mut Context<Self>,
15072    ) {
15073        self.add_selection(false, action.skip_soft_wrap, window, cx);
15074    }
15075
15076    fn add_selection(
15077        &mut self,
15078        above: bool,
15079        skip_soft_wrap: bool,
15080        window: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) {
15083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15084
15085        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15086        let all_selections = self.selections.all::<Point>(&display_map);
15087        let text_layout_details = self.text_layout_details(window);
15088
15089        let (mut columnar_selections, new_selections_to_columnarize) = {
15090            if let Some(state) = self.add_selections_state.as_ref() {
15091                let columnar_selection_ids: HashSet<_> = state
15092                    .groups
15093                    .iter()
15094                    .flat_map(|group| group.stack.iter())
15095                    .copied()
15096                    .collect();
15097
15098                all_selections
15099                    .into_iter()
15100                    .partition(|s| columnar_selection_ids.contains(&s.id))
15101            } else {
15102                (Vec::new(), all_selections)
15103            }
15104        };
15105
15106        let mut state = self
15107            .add_selections_state
15108            .take()
15109            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15110
15111        for selection in new_selections_to_columnarize {
15112            let range = selection.display_range(&display_map).sorted();
15113            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15114            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15115            let positions = start_x.min(end_x)..start_x.max(end_x);
15116            let mut stack = Vec::new();
15117            for row in range.start.row().0..=range.end.row().0 {
15118                if let Some(selection) = self.selections.build_columnar_selection(
15119                    &display_map,
15120                    DisplayRow(row),
15121                    &positions,
15122                    selection.reversed,
15123                    &text_layout_details,
15124                ) {
15125                    stack.push(selection.id);
15126                    columnar_selections.push(selection);
15127                }
15128            }
15129            if !stack.is_empty() {
15130                if above {
15131                    stack.reverse();
15132                }
15133                state.groups.push(AddSelectionsGroup { above, stack });
15134            }
15135        }
15136
15137        let mut final_selections = Vec::new();
15138        let end_row = if above {
15139            DisplayRow(0)
15140        } else {
15141            display_map.max_point().row()
15142        };
15143
15144        // When `skip_soft_wrap` is true, we use buffer columns instead of pixel
15145        // positions to place new selections, so we need to keep track of the
15146        // column range of the oldest selection in each group, because
15147        // intermediate selections may have been clamped to shorter lines.
15148        // selections may have been clamped to shorter lines.
15149        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15150            let mut map = HashMap::default();
15151            for group in state.groups.iter() {
15152                if let Some(oldest_id) = group.stack.first() {
15153                    if let Some(oldest_selection) =
15154                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15155                    {
15156                        let start_col = oldest_selection.start.column;
15157                        let end_col = oldest_selection.end.column;
15158                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15159                        for id in &group.stack {
15160                            map.insert(*id, goal_columns.clone());
15161                        }
15162                    }
15163                }
15164            }
15165            map
15166        } else {
15167            HashMap::default()
15168        };
15169
15170        let mut last_added_item_per_group = HashMap::default();
15171        for group in state.groups.iter_mut() {
15172            if let Some(last_id) = group.stack.last() {
15173                last_added_item_per_group.insert(*last_id, group);
15174            }
15175        }
15176
15177        for selection in columnar_selections {
15178            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15179                if above == group.above {
15180                    let range = selection.display_range(&display_map).sorted();
15181                    debug_assert_eq!(range.start.row(), range.end.row());
15182                    let row = range.start.row();
15183                    let positions =
15184                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15185                            Pixels::from(start)..Pixels::from(end)
15186                        } else {
15187                            let start_x =
15188                                display_map.x_for_display_point(range.start, &text_layout_details);
15189                            let end_x =
15190                                display_map.x_for_display_point(range.end, &text_layout_details);
15191                            start_x.min(end_x)..start_x.max(end_x)
15192                        };
15193
15194                    let maybe_new_selection = if skip_soft_wrap {
15195                        let goal_columns = goal_columns_by_selection_id
15196                            .remove(&selection.id)
15197                            .unwrap_or_else(|| {
15198                                let start_col = selection.start.column;
15199                                let end_col = selection.end.column;
15200                                start_col.min(end_col)..start_col.max(end_col)
15201                            });
15202                        self.selections.find_next_columnar_selection_by_buffer_row(
15203                            &display_map,
15204                            row,
15205                            end_row,
15206                            above,
15207                            &goal_columns,
15208                            selection.reversed,
15209                            &text_layout_details,
15210                        )
15211                    } else {
15212                        self.selections.find_next_columnar_selection_by_display_row(
15213                            &display_map,
15214                            row,
15215                            end_row,
15216                            above,
15217                            &positions,
15218                            selection.reversed,
15219                            &text_layout_details,
15220                        )
15221                    };
15222
15223                    if let Some(new_selection) = maybe_new_selection {
15224                        group.stack.push(new_selection.id);
15225                        if above {
15226                            final_selections.push(new_selection);
15227                            final_selections.push(selection);
15228                        } else {
15229                            final_selections.push(selection);
15230                            final_selections.push(new_selection);
15231                        }
15232                    } else {
15233                        final_selections.push(selection);
15234                    }
15235                } else {
15236                    group.stack.pop();
15237                }
15238            } else {
15239                final_selections.push(selection);
15240            }
15241        }
15242
15243        self.change_selections(Default::default(), window, cx, |s| {
15244            s.select(final_selections);
15245        });
15246
15247        let final_selection_ids: HashSet<_> = self
15248            .selections
15249            .all::<Point>(&display_map)
15250            .iter()
15251            .map(|s| s.id)
15252            .collect();
15253        state.groups.retain_mut(|group| {
15254            // selections might get merged above so we remove invalid items from stacks
15255            group.stack.retain(|id| final_selection_ids.contains(id));
15256
15257            // single selection in stack can be treated as initial state
15258            group.stack.len() > 1
15259        });
15260
15261        if !state.groups.is_empty() {
15262            self.add_selections_state = Some(state);
15263        }
15264    }
15265
15266    pub fn insert_snippet_at_selections(
15267        &mut self,
15268        action: &InsertSnippet,
15269        window: &mut Window,
15270        cx: &mut Context<Self>,
15271    ) {
15272        self.try_insert_snippet_at_selections(action, window, cx)
15273            .log_err();
15274    }
15275
15276    fn try_insert_snippet_at_selections(
15277        &mut self,
15278        action: &InsertSnippet,
15279        window: &mut Window,
15280        cx: &mut Context<Self>,
15281    ) -> Result<()> {
15282        let insertion_ranges = self
15283            .selections
15284            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15285            .into_iter()
15286            .map(|selection| selection.range())
15287            .collect_vec();
15288
15289        let snippet = if let Some(snippet_body) = &action.snippet {
15290            if action.language.is_none() && action.name.is_none() {
15291                Snippet::parse(snippet_body)?
15292            } else {
15293                bail!("`snippet` is mutually exclusive with `language` and `name`")
15294            }
15295        } else if let Some(name) = &action.name {
15296            let project = self.project().context("no project")?;
15297            let snippet_store = project.read(cx).snippets().read(cx);
15298            let snippet = snippet_store
15299                .snippets_for(action.language.clone(), cx)
15300                .into_iter()
15301                .find(|snippet| snippet.name == *name)
15302                .context("snippet not found")?;
15303            Snippet::parse(&snippet.body)?
15304        } else {
15305            // todo(andrew): open modal to select snippet
15306            bail!("`name` or `snippet` is required")
15307        };
15308
15309        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15310    }
15311
15312    fn select_match_ranges(
15313        &mut self,
15314        range: Range<MultiBufferOffset>,
15315        reversed: bool,
15316        replace_newest: bool,
15317        auto_scroll: Option<Autoscroll>,
15318        window: &mut Window,
15319        cx: &mut Context<Editor>,
15320    ) {
15321        self.unfold_ranges(
15322            std::slice::from_ref(&range),
15323            false,
15324            auto_scroll.is_some(),
15325            cx,
15326        );
15327        let effects = if let Some(scroll) = auto_scroll {
15328            SelectionEffects::scroll(scroll)
15329        } else {
15330            SelectionEffects::no_scroll()
15331        };
15332        self.change_selections(effects, window, cx, |s| {
15333            if replace_newest {
15334                s.delete(s.newest_anchor().id);
15335            }
15336            if reversed {
15337                s.insert_range(range.end..range.start);
15338            } else {
15339                s.insert_range(range);
15340            }
15341        });
15342    }
15343
15344    pub fn select_next_match_internal(
15345        &mut self,
15346        display_map: &DisplaySnapshot,
15347        replace_newest: bool,
15348        autoscroll: Option<Autoscroll>,
15349        window: &mut Window,
15350        cx: &mut Context<Self>,
15351    ) -> Result<()> {
15352        let buffer = display_map.buffer_snapshot();
15353        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15354        if let Some(mut select_next_state) = self.select_next_state.take() {
15355            let query = &select_next_state.query;
15356            if !select_next_state.done {
15357                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15358                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15359                let mut next_selected_range = None;
15360
15361                let bytes_after_last_selection =
15362                    buffer.bytes_in_range(last_selection.end..buffer.len());
15363                let bytes_before_first_selection =
15364                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15365                let query_matches = query
15366                    .stream_find_iter(bytes_after_last_selection)
15367                    .map(|result| (last_selection.end, result))
15368                    .chain(
15369                        query
15370                            .stream_find_iter(bytes_before_first_selection)
15371                            .map(|result| (MultiBufferOffset(0), result)),
15372                    );
15373
15374                for (start_offset, query_match) in query_matches {
15375                    let query_match = query_match.unwrap(); // can only fail due to I/O
15376                    let offset_range =
15377                        start_offset + query_match.start()..start_offset + query_match.end();
15378
15379                    if !select_next_state.wordwise
15380                        || (!buffer.is_inside_word(offset_range.start, None)
15381                            && !buffer.is_inside_word(offset_range.end, None))
15382                    {
15383                        let idx = selections
15384                            .partition_point(|selection| selection.end <= offset_range.start);
15385                        let overlaps = selections
15386                            .get(idx)
15387                            .map_or(false, |selection| selection.start < offset_range.end);
15388
15389                        if !overlaps {
15390                            next_selected_range = Some(offset_range);
15391                            break;
15392                        }
15393                    }
15394                }
15395
15396                if let Some(next_selected_range) = next_selected_range {
15397                    self.select_match_ranges(
15398                        next_selected_range,
15399                        last_selection.reversed,
15400                        replace_newest,
15401                        autoscroll,
15402                        window,
15403                        cx,
15404                    );
15405                } else {
15406                    select_next_state.done = true;
15407                }
15408            }
15409
15410            self.select_next_state = Some(select_next_state);
15411        } else {
15412            let mut only_carets = true;
15413            let mut same_text_selected = true;
15414            let mut selected_text = None;
15415
15416            let mut selections_iter = selections.iter().peekable();
15417            while let Some(selection) = selections_iter.next() {
15418                if selection.start != selection.end {
15419                    only_carets = false;
15420                }
15421
15422                if same_text_selected {
15423                    if selected_text.is_none() {
15424                        selected_text =
15425                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15426                    }
15427
15428                    if let Some(next_selection) = selections_iter.peek() {
15429                        if next_selection.len() == selection.len() {
15430                            let next_selected_text = buffer
15431                                .text_for_range(next_selection.range())
15432                                .collect::<String>();
15433                            if Some(next_selected_text) != selected_text {
15434                                same_text_selected = false;
15435                                selected_text = None;
15436                            }
15437                        } else {
15438                            same_text_selected = false;
15439                            selected_text = None;
15440                        }
15441                    }
15442                }
15443            }
15444
15445            if only_carets {
15446                for selection in &mut selections {
15447                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15448                    selection.start = word_range.start;
15449                    selection.end = word_range.end;
15450                    selection.goal = SelectionGoal::None;
15451                    selection.reversed = false;
15452                    self.select_match_ranges(
15453                        selection.start..selection.end,
15454                        selection.reversed,
15455                        replace_newest,
15456                        autoscroll,
15457                        window,
15458                        cx,
15459                    );
15460                }
15461
15462                if selections.len() == 1 {
15463                    let selection = selections
15464                        .last()
15465                        .expect("ensured that there's only one selection");
15466                    let query = buffer
15467                        .text_for_range(selection.start..selection.end)
15468                        .collect::<String>();
15469                    let is_empty = query.is_empty();
15470                    let select_state = SelectNextState {
15471                        query: self.build_query(&[query], cx)?,
15472                        wordwise: true,
15473                        done: is_empty,
15474                    };
15475                    self.select_next_state = Some(select_state);
15476                } else {
15477                    self.select_next_state = None;
15478                }
15479            } else if let Some(selected_text) = selected_text {
15480                self.select_next_state = Some(SelectNextState {
15481                    query: self.build_query(&[selected_text], cx)?,
15482                    wordwise: false,
15483                    done: false,
15484                });
15485                self.select_next_match_internal(
15486                    display_map,
15487                    replace_newest,
15488                    autoscroll,
15489                    window,
15490                    cx,
15491                )?;
15492            }
15493        }
15494        Ok(())
15495    }
15496
15497    pub fn select_all_matches(
15498        &mut self,
15499        _action: &SelectAllMatches,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) -> Result<()> {
15503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15504
15505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15506
15507        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15508        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15509        else {
15510            return Ok(());
15511        };
15512
15513        let mut new_selections = Vec::new();
15514
15515        let reversed = self
15516            .selections
15517            .oldest::<MultiBufferOffset>(&display_map)
15518            .reversed;
15519        let buffer = display_map.buffer_snapshot();
15520        let query_matches = select_next_state
15521            .query
15522            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15523
15524        for query_match in query_matches.into_iter() {
15525            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15526            let offset_range = if reversed {
15527                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15528            } else {
15529                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15530            };
15531
15532            if !select_next_state.wordwise
15533                || (!buffer.is_inside_word(offset_range.start, None)
15534                    && !buffer.is_inside_word(offset_range.end, None))
15535            {
15536                new_selections.push(offset_range.start..offset_range.end);
15537            }
15538        }
15539
15540        select_next_state.done = true;
15541
15542        if new_selections.is_empty() {
15543            log::error!("bug: new_selections is empty in select_all_matches");
15544            return Ok(());
15545        }
15546
15547        self.unfold_ranges(&new_selections, false, false, cx);
15548        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15549            selections.select_ranges(new_selections)
15550        });
15551
15552        Ok(())
15553    }
15554
15555    pub fn select_next(
15556        &mut self,
15557        action: &SelectNext,
15558        window: &mut Window,
15559        cx: &mut Context<Self>,
15560    ) -> Result<()> {
15561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15563        self.select_next_match_internal(
15564            &display_map,
15565            action.replace_newest,
15566            Some(Autoscroll::newest()),
15567            window,
15568            cx,
15569        )
15570    }
15571
15572    pub fn select_previous(
15573        &mut self,
15574        action: &SelectPrevious,
15575        window: &mut Window,
15576        cx: &mut Context<Self>,
15577    ) -> Result<()> {
15578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15579        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15580        let buffer = display_map.buffer_snapshot();
15581        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15582        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15583            let query = &select_prev_state.query;
15584            if !select_prev_state.done {
15585                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15586                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15587                let mut next_selected_range = None;
15588                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15589                let bytes_before_last_selection =
15590                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15591                let bytes_after_first_selection =
15592                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15593                let query_matches = query
15594                    .stream_find_iter(bytes_before_last_selection)
15595                    .map(|result| (last_selection.start, result))
15596                    .chain(
15597                        query
15598                            .stream_find_iter(bytes_after_first_selection)
15599                            .map(|result| (buffer.len(), result)),
15600                    );
15601                for (end_offset, query_match) in query_matches {
15602                    let query_match = query_match.unwrap(); // can only fail due to I/O
15603                    let offset_range =
15604                        end_offset - query_match.end()..end_offset - query_match.start();
15605
15606                    if !select_prev_state.wordwise
15607                        || (!buffer.is_inside_word(offset_range.start, None)
15608                            && !buffer.is_inside_word(offset_range.end, None))
15609                    {
15610                        next_selected_range = Some(offset_range);
15611                        break;
15612                    }
15613                }
15614
15615                if let Some(next_selected_range) = next_selected_range {
15616                    self.select_match_ranges(
15617                        next_selected_range,
15618                        last_selection.reversed,
15619                        action.replace_newest,
15620                        Some(Autoscroll::newest()),
15621                        window,
15622                        cx,
15623                    );
15624                } else {
15625                    select_prev_state.done = true;
15626                }
15627            }
15628
15629            self.select_prev_state = Some(select_prev_state);
15630        } else {
15631            let mut only_carets = true;
15632            let mut same_text_selected = true;
15633            let mut selected_text = None;
15634
15635            let mut selections_iter = selections.iter().peekable();
15636            while let Some(selection) = selections_iter.next() {
15637                if selection.start != selection.end {
15638                    only_carets = false;
15639                }
15640
15641                if same_text_selected {
15642                    if selected_text.is_none() {
15643                        selected_text =
15644                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15645                    }
15646
15647                    if let Some(next_selection) = selections_iter.peek() {
15648                        if next_selection.len() == selection.len() {
15649                            let next_selected_text = buffer
15650                                .text_for_range(next_selection.range())
15651                                .collect::<String>();
15652                            if Some(next_selected_text) != selected_text {
15653                                same_text_selected = false;
15654                                selected_text = None;
15655                            }
15656                        } else {
15657                            same_text_selected = false;
15658                            selected_text = None;
15659                        }
15660                    }
15661                }
15662            }
15663
15664            if only_carets {
15665                for selection in &mut selections {
15666                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15667                    selection.start = word_range.start;
15668                    selection.end = word_range.end;
15669                    selection.goal = SelectionGoal::None;
15670                    selection.reversed = false;
15671                    self.select_match_ranges(
15672                        selection.start..selection.end,
15673                        selection.reversed,
15674                        action.replace_newest,
15675                        Some(Autoscroll::newest()),
15676                        window,
15677                        cx,
15678                    );
15679                }
15680                if selections.len() == 1 {
15681                    let selection = selections
15682                        .last()
15683                        .expect("ensured that there's only one selection");
15684                    let query = buffer
15685                        .text_for_range(selection.start..selection.end)
15686                        .collect::<String>();
15687                    let is_empty = query.is_empty();
15688                    let select_state = SelectNextState {
15689                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15690                        wordwise: true,
15691                        done: is_empty,
15692                    };
15693                    self.select_prev_state = Some(select_state);
15694                } else {
15695                    self.select_prev_state = None;
15696                }
15697            } else if let Some(selected_text) = selected_text {
15698                self.select_prev_state = Some(SelectNextState {
15699                    query: self
15700                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15701                    wordwise: false,
15702                    done: false,
15703                });
15704                self.select_previous(action, window, cx)?;
15705            }
15706        }
15707        Ok(())
15708    }
15709
15710    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15711    /// setting the case sensitivity based on the global
15712    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15713    /// editor's settings.
15714    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15715    where
15716        I: IntoIterator<Item = P>,
15717        P: AsRef<[u8]>,
15718    {
15719        let case_sensitive = self
15720            .select_next_is_case_sensitive
15721            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15722
15723        let mut builder = AhoCorasickBuilder::new();
15724        builder.ascii_case_insensitive(!case_sensitive);
15725        builder.build(patterns)
15726    }
15727
15728    pub fn find_next_match(
15729        &mut self,
15730        _: &FindNextMatch,
15731        window: &mut Window,
15732        cx: &mut Context<Self>,
15733    ) -> Result<()> {
15734        let selections = self.selections.disjoint_anchors_arc();
15735        match selections.first() {
15736            Some(first) if selections.len() >= 2 => {
15737                self.change_selections(Default::default(), window, cx, |s| {
15738                    s.select_ranges([first.range()]);
15739                });
15740            }
15741            _ => self.select_next(
15742                &SelectNext {
15743                    replace_newest: true,
15744                },
15745                window,
15746                cx,
15747            )?,
15748        }
15749        Ok(())
15750    }
15751
15752    pub fn find_previous_match(
15753        &mut self,
15754        _: &FindPreviousMatch,
15755        window: &mut Window,
15756        cx: &mut Context<Self>,
15757    ) -> Result<()> {
15758        let selections = self.selections.disjoint_anchors_arc();
15759        match selections.last() {
15760            Some(last) if selections.len() >= 2 => {
15761                self.change_selections(Default::default(), window, cx, |s| {
15762                    s.select_ranges([last.range()]);
15763                });
15764            }
15765            _ => self.select_previous(
15766                &SelectPrevious {
15767                    replace_newest: true,
15768                },
15769                window,
15770                cx,
15771            )?,
15772        }
15773        Ok(())
15774    }
15775
15776    pub fn toggle_comments(
15777        &mut self,
15778        action: &ToggleComments,
15779        window: &mut Window,
15780        cx: &mut Context<Self>,
15781    ) {
15782        if self.read_only(cx) {
15783            return;
15784        }
15785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15786        let text_layout_details = &self.text_layout_details(window);
15787        self.transact(window, cx, |this, window, cx| {
15788            let mut selections = this
15789                .selections
15790                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15791            let mut edits = Vec::new();
15792            let mut selection_edit_ranges = Vec::new();
15793            let mut last_toggled_row = None;
15794            let snapshot = this.buffer.read(cx).read(cx);
15795            let empty_str: Arc<str> = Arc::default();
15796            let mut suffixes_inserted = Vec::new();
15797            let ignore_indent = action.ignore_indent;
15798
15799            fn comment_prefix_range(
15800                snapshot: &MultiBufferSnapshot,
15801                row: MultiBufferRow,
15802                comment_prefix: &str,
15803                comment_prefix_whitespace: &str,
15804                ignore_indent: bool,
15805            ) -> Range<Point> {
15806                let indent_size = if ignore_indent {
15807                    0
15808                } else {
15809                    snapshot.indent_size_for_line(row).len
15810                };
15811
15812                let start = Point::new(row.0, indent_size);
15813
15814                let mut line_bytes = snapshot
15815                    .bytes_in_range(start..snapshot.max_point())
15816                    .flatten()
15817                    .copied();
15818
15819                // If this line currently begins with the line comment prefix, then record
15820                // the range containing the prefix.
15821                if line_bytes
15822                    .by_ref()
15823                    .take(comment_prefix.len())
15824                    .eq(comment_prefix.bytes())
15825                {
15826                    // Include any whitespace that matches the comment prefix.
15827                    let matching_whitespace_len = line_bytes
15828                        .zip(comment_prefix_whitespace.bytes())
15829                        .take_while(|(a, b)| a == b)
15830                        .count() as u32;
15831                    let end = Point::new(
15832                        start.row,
15833                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15834                    );
15835                    start..end
15836                } else {
15837                    start..start
15838                }
15839            }
15840
15841            fn comment_suffix_range(
15842                snapshot: &MultiBufferSnapshot,
15843                row: MultiBufferRow,
15844                comment_suffix: &str,
15845                comment_suffix_has_leading_space: bool,
15846            ) -> Range<Point> {
15847                let end = Point::new(row.0, snapshot.line_len(row));
15848                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15849
15850                let mut line_end_bytes = snapshot
15851                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15852                    .flatten()
15853                    .copied();
15854
15855                let leading_space_len = if suffix_start_column > 0
15856                    && line_end_bytes.next() == Some(b' ')
15857                    && comment_suffix_has_leading_space
15858                {
15859                    1
15860                } else {
15861                    0
15862                };
15863
15864                // If this line currently begins with the line comment prefix, then record
15865                // the range containing the prefix.
15866                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15867                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15868                    start..end
15869                } else {
15870                    end..end
15871                }
15872            }
15873
15874            // TODO: Handle selections that cross excerpts
15875            for selection in &mut selections {
15876                let start_column = snapshot
15877                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15878                    .len;
15879                let language = if let Some(language) =
15880                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15881                {
15882                    language
15883                } else {
15884                    continue;
15885                };
15886
15887                selection_edit_ranges.clear();
15888
15889                // If multiple selections contain a given row, avoid processing that
15890                // row more than once.
15891                let mut start_row = MultiBufferRow(selection.start.row);
15892                if last_toggled_row == Some(start_row) {
15893                    start_row = start_row.next_row();
15894                }
15895                let end_row =
15896                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15897                        MultiBufferRow(selection.end.row - 1)
15898                    } else {
15899                        MultiBufferRow(selection.end.row)
15900                    };
15901                last_toggled_row = Some(end_row);
15902
15903                if start_row > end_row {
15904                    continue;
15905                }
15906
15907                // If the language has line comments, toggle those.
15908                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15909
15910                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15911                if ignore_indent {
15912                    full_comment_prefixes = full_comment_prefixes
15913                        .into_iter()
15914                        .map(|s| Arc::from(s.trim_end()))
15915                        .collect();
15916                }
15917
15918                if !full_comment_prefixes.is_empty() {
15919                    let first_prefix = full_comment_prefixes
15920                        .first()
15921                        .expect("prefixes is non-empty");
15922                    let prefix_trimmed_lengths = full_comment_prefixes
15923                        .iter()
15924                        .map(|p| p.trim_end_matches(' ').len())
15925                        .collect::<SmallVec<[usize; 4]>>();
15926
15927                    let mut all_selection_lines_are_comments = true;
15928
15929                    for row in start_row.0..=end_row.0 {
15930                        let row = MultiBufferRow(row);
15931                        if start_row < end_row && snapshot.is_line_blank(row) {
15932                            continue;
15933                        }
15934
15935                        let prefix_range = full_comment_prefixes
15936                            .iter()
15937                            .zip(prefix_trimmed_lengths.iter().copied())
15938                            .map(|(prefix, trimmed_prefix_len)| {
15939                                comment_prefix_range(
15940                                    snapshot.deref(),
15941                                    row,
15942                                    &prefix[..trimmed_prefix_len],
15943                                    &prefix[trimmed_prefix_len..],
15944                                    ignore_indent,
15945                                )
15946                            })
15947                            .max_by_key(|range| range.end.column - range.start.column)
15948                            .expect("prefixes is non-empty");
15949
15950                        if prefix_range.is_empty() {
15951                            all_selection_lines_are_comments = false;
15952                        }
15953
15954                        selection_edit_ranges.push(prefix_range);
15955                    }
15956
15957                    if all_selection_lines_are_comments {
15958                        edits.extend(
15959                            selection_edit_ranges
15960                                .iter()
15961                                .cloned()
15962                                .map(|range| (range, empty_str.clone())),
15963                        );
15964                    } else {
15965                        let min_column = selection_edit_ranges
15966                            .iter()
15967                            .map(|range| range.start.column)
15968                            .min()
15969                            .unwrap_or(0);
15970                        edits.extend(selection_edit_ranges.iter().map(|range| {
15971                            let position = Point::new(range.start.row, min_column);
15972                            (position..position, first_prefix.clone())
15973                        }));
15974                    }
15975                } else if let Some(BlockCommentConfig {
15976                    start: full_comment_prefix,
15977                    end: comment_suffix,
15978                    ..
15979                }) = language.block_comment()
15980                {
15981                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15982                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15983                    let prefix_range = comment_prefix_range(
15984                        snapshot.deref(),
15985                        start_row,
15986                        comment_prefix,
15987                        comment_prefix_whitespace,
15988                        ignore_indent,
15989                    );
15990                    let suffix_range = comment_suffix_range(
15991                        snapshot.deref(),
15992                        end_row,
15993                        comment_suffix.trim_start_matches(' '),
15994                        comment_suffix.starts_with(' '),
15995                    );
15996
15997                    if prefix_range.is_empty() || suffix_range.is_empty() {
15998                        edits.push((
15999                            prefix_range.start..prefix_range.start,
16000                            full_comment_prefix.clone(),
16001                        ));
16002                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16003                        suffixes_inserted.push((end_row, comment_suffix.len()));
16004                    } else {
16005                        edits.push((prefix_range, empty_str.clone()));
16006                        edits.push((suffix_range, empty_str.clone()));
16007                    }
16008                } else {
16009                    continue;
16010                }
16011            }
16012
16013            drop(snapshot);
16014            this.buffer.update(cx, |buffer, cx| {
16015                buffer.edit(edits, None, cx);
16016            });
16017
16018            // Adjust selections so that they end before any comment suffixes that
16019            // were inserted.
16020            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16021            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16022            let snapshot = this.buffer.read(cx).read(cx);
16023            for selection in &mut selections {
16024                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16025                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16026                        Ordering::Less => {
16027                            suffixes_inserted.next();
16028                            continue;
16029                        }
16030                        Ordering::Greater => break,
16031                        Ordering::Equal => {
16032                            if selection.end.column == snapshot.line_len(row) {
16033                                if selection.is_empty() {
16034                                    selection.start.column -= suffix_len as u32;
16035                                }
16036                                selection.end.column -= suffix_len as u32;
16037                            }
16038                            break;
16039                        }
16040                    }
16041                }
16042            }
16043
16044            drop(snapshot);
16045            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16046
16047            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16048            let selections_on_single_row = selections.windows(2).all(|selections| {
16049                selections[0].start.row == selections[1].start.row
16050                    && selections[0].end.row == selections[1].end.row
16051                    && selections[0].start.row == selections[0].end.row
16052            });
16053            let selections_selecting = selections
16054                .iter()
16055                .any(|selection| selection.start != selection.end);
16056            let advance_downwards = action.advance_downwards
16057                && selections_on_single_row
16058                && !selections_selecting
16059                && !matches!(this.mode, EditorMode::SingleLine);
16060
16061            if advance_downwards {
16062                let snapshot = this.buffer.read(cx).snapshot(cx);
16063
16064                this.change_selections(Default::default(), window, cx, |s| {
16065                    s.move_cursors_with(|display_snapshot, display_point, _| {
16066                        let mut point = display_point.to_point(display_snapshot);
16067                        point.row += 1;
16068                        point = snapshot.clip_point(point, Bias::Left);
16069                        let display_point = point.to_display_point(display_snapshot);
16070                        let goal = SelectionGoal::HorizontalPosition(
16071                            display_snapshot
16072                                .x_for_display_point(display_point, text_layout_details)
16073                                .into(),
16074                        );
16075                        (display_point, goal)
16076                    })
16077                });
16078            }
16079        });
16080    }
16081
16082    pub fn select_enclosing_symbol(
16083        &mut self,
16084        _: &SelectEnclosingSymbol,
16085        window: &mut Window,
16086        cx: &mut Context<Self>,
16087    ) {
16088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16089
16090        let buffer = self.buffer.read(cx).snapshot(cx);
16091        let old_selections = self
16092            .selections
16093            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16094            .into_boxed_slice();
16095
16096        fn update_selection(
16097            selection: &Selection<MultiBufferOffset>,
16098            buffer_snap: &MultiBufferSnapshot,
16099        ) -> Option<Selection<MultiBufferOffset>> {
16100            let cursor = selection.head();
16101            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16102            for symbol in symbols.iter().rev() {
16103                let start = symbol.range.start.to_offset(buffer_snap);
16104                let end = symbol.range.end.to_offset(buffer_snap);
16105                let new_range = start..end;
16106                if start < selection.start || end > selection.end {
16107                    return Some(Selection {
16108                        id: selection.id,
16109                        start: new_range.start,
16110                        end: new_range.end,
16111                        goal: SelectionGoal::None,
16112                        reversed: selection.reversed,
16113                    });
16114                }
16115            }
16116            None
16117        }
16118
16119        let mut selected_larger_symbol = false;
16120        let new_selections = old_selections
16121            .iter()
16122            .map(|selection| match update_selection(selection, &buffer) {
16123                Some(new_selection) => {
16124                    if new_selection.range() != selection.range() {
16125                        selected_larger_symbol = true;
16126                    }
16127                    new_selection
16128                }
16129                None => selection.clone(),
16130            })
16131            .collect::<Vec<_>>();
16132
16133        if selected_larger_symbol {
16134            self.change_selections(Default::default(), window, cx, |s| {
16135                s.select(new_selections);
16136            });
16137        }
16138    }
16139
16140    pub fn select_larger_syntax_node(
16141        &mut self,
16142        _: &SelectLargerSyntaxNode,
16143        window: &mut Window,
16144        cx: &mut Context<Self>,
16145    ) {
16146        let Some(visible_row_count) = self.visible_row_count() else {
16147            return;
16148        };
16149        let old_selections: Box<[_]> = self
16150            .selections
16151            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16152            .into();
16153        if old_selections.is_empty() {
16154            return;
16155        }
16156
16157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16158
16159        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16160        let buffer = self.buffer.read(cx).snapshot(cx);
16161
16162        let mut selected_larger_node = false;
16163        let mut new_selections = old_selections
16164            .iter()
16165            .map(|selection| {
16166                let old_range = selection.start..selection.end;
16167
16168                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16169                    // manually select word at selection
16170                    if ["string_content", "inline"].contains(&node.kind()) {
16171                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16172                        // ignore if word is already selected
16173                        if !word_range.is_empty() && old_range != word_range {
16174                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16175                            // only select word if start and end point belongs to same word
16176                            if word_range == last_word_range {
16177                                selected_larger_node = true;
16178                                return Selection {
16179                                    id: selection.id,
16180                                    start: word_range.start,
16181                                    end: word_range.end,
16182                                    goal: SelectionGoal::None,
16183                                    reversed: selection.reversed,
16184                                };
16185                            }
16186                        }
16187                    }
16188                }
16189
16190                let mut new_range = old_range.clone();
16191                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16192                    new_range = range;
16193                    if !node.is_named() {
16194                        continue;
16195                    }
16196                    if !display_map.intersects_fold(new_range.start)
16197                        && !display_map.intersects_fold(new_range.end)
16198                    {
16199                        break;
16200                    }
16201                }
16202
16203                selected_larger_node |= new_range != old_range;
16204                Selection {
16205                    id: selection.id,
16206                    start: new_range.start,
16207                    end: new_range.end,
16208                    goal: SelectionGoal::None,
16209                    reversed: selection.reversed,
16210                }
16211            })
16212            .collect::<Vec<_>>();
16213
16214        if !selected_larger_node {
16215            return; // don't put this call in the history
16216        }
16217
16218        // scroll based on transformation done to the last selection created by the user
16219        let (last_old, last_new) = old_selections
16220            .last()
16221            .zip(new_selections.last().cloned())
16222            .expect("old_selections isn't empty");
16223
16224        // revert selection
16225        let is_selection_reversed = {
16226            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16227            new_selections.last_mut().expect("checked above").reversed =
16228                should_newest_selection_be_reversed;
16229            should_newest_selection_be_reversed
16230        };
16231
16232        if selected_larger_node {
16233            self.select_syntax_node_history.disable_clearing = true;
16234            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16235                s.select(new_selections.clone());
16236            });
16237            self.select_syntax_node_history.disable_clearing = false;
16238        }
16239
16240        let start_row = last_new.start.to_display_point(&display_map).row().0;
16241        let end_row = last_new.end.to_display_point(&display_map).row().0;
16242        let selection_height = end_row - start_row + 1;
16243        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16244
16245        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16246        let scroll_behavior = if fits_on_the_screen {
16247            self.request_autoscroll(Autoscroll::fit(), cx);
16248            SelectSyntaxNodeScrollBehavior::FitSelection
16249        } else if is_selection_reversed {
16250            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16251            SelectSyntaxNodeScrollBehavior::CursorTop
16252        } else {
16253            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16254            SelectSyntaxNodeScrollBehavior::CursorBottom
16255        };
16256
16257        self.select_syntax_node_history.push((
16258            old_selections,
16259            scroll_behavior,
16260            is_selection_reversed,
16261        ));
16262    }
16263
16264    pub fn select_smaller_syntax_node(
16265        &mut self,
16266        _: &SelectSmallerSyntaxNode,
16267        window: &mut Window,
16268        cx: &mut Context<Self>,
16269    ) {
16270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16271
16272        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16273            self.select_syntax_node_history.pop()
16274        {
16275            if let Some(selection) = selections.last_mut() {
16276                selection.reversed = is_selection_reversed;
16277            }
16278
16279            self.select_syntax_node_history.disable_clearing = true;
16280            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16281                s.select(selections.to_vec());
16282            });
16283            self.select_syntax_node_history.disable_clearing = false;
16284
16285            match scroll_behavior {
16286                SelectSyntaxNodeScrollBehavior::CursorTop => {
16287                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16288                }
16289                SelectSyntaxNodeScrollBehavior::FitSelection => {
16290                    self.request_autoscroll(Autoscroll::fit(), cx);
16291                }
16292                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16293                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16294                }
16295            }
16296        }
16297    }
16298
16299    pub fn unwrap_syntax_node(
16300        &mut self,
16301        _: &UnwrapSyntaxNode,
16302        window: &mut Window,
16303        cx: &mut Context<Self>,
16304    ) {
16305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16306
16307        let buffer = self.buffer.read(cx).snapshot(cx);
16308        let selections = self
16309            .selections
16310            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16311            .into_iter()
16312            // subtracting the offset requires sorting
16313            .sorted_by_key(|i| i.start);
16314
16315        let full_edits = selections
16316            .into_iter()
16317            .filter_map(|selection| {
16318                let child = if selection.is_empty()
16319                    && let Some((_, ancestor_range)) =
16320                        buffer.syntax_ancestor(selection.start..selection.end)
16321                {
16322                    ancestor_range
16323                } else {
16324                    selection.range()
16325                };
16326
16327                let mut parent = child.clone();
16328                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16329                    parent = ancestor_range;
16330                    if parent.start < child.start || parent.end > child.end {
16331                        break;
16332                    }
16333                }
16334
16335                if parent == child {
16336                    return None;
16337                }
16338                let text = buffer.text_for_range(child).collect::<String>();
16339                Some((selection.id, parent, text))
16340            })
16341            .collect::<Vec<_>>();
16342        if full_edits.is_empty() {
16343            return;
16344        }
16345
16346        self.transact(window, cx, |this, window, cx| {
16347            this.buffer.update(cx, |buffer, cx| {
16348                buffer.edit(
16349                    full_edits
16350                        .iter()
16351                        .map(|(_, p, t)| (p.clone(), t.clone()))
16352                        .collect::<Vec<_>>(),
16353                    None,
16354                    cx,
16355                );
16356            });
16357            this.change_selections(Default::default(), window, cx, |s| {
16358                let mut offset = 0;
16359                let mut selections = vec![];
16360                for (id, parent, text) in full_edits {
16361                    let start = parent.start - offset;
16362                    offset += (parent.end - parent.start) - text.len();
16363                    selections.push(Selection {
16364                        id,
16365                        start,
16366                        end: start + text.len(),
16367                        reversed: false,
16368                        goal: Default::default(),
16369                    });
16370                }
16371                s.select(selections);
16372            });
16373        });
16374    }
16375
16376    pub fn select_next_syntax_node(
16377        &mut self,
16378        _: &SelectNextSyntaxNode,
16379        window: &mut Window,
16380        cx: &mut Context<Self>,
16381    ) {
16382        let old_selections: Box<[_]> = self
16383            .selections
16384            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16385            .into();
16386        if old_selections.is_empty() {
16387            return;
16388        }
16389
16390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16391
16392        let buffer = self.buffer.read(cx).snapshot(cx);
16393        let mut selected_sibling = false;
16394
16395        let new_selections = old_selections
16396            .iter()
16397            .map(|selection| {
16398                let old_range = selection.start..selection.end;
16399
16400                let old_range =
16401                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16402                let excerpt = buffer.excerpt_containing(old_range.clone());
16403
16404                if let Some(mut excerpt) = excerpt
16405                    && let Some(node) = excerpt
16406                        .buffer()
16407                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16408                {
16409                    let new_range = excerpt.map_range_from_buffer(
16410                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16411                    );
16412                    selected_sibling = true;
16413                    Selection {
16414                        id: selection.id,
16415                        start: new_range.start,
16416                        end: new_range.end,
16417                        goal: SelectionGoal::None,
16418                        reversed: selection.reversed,
16419                    }
16420                } else {
16421                    selection.clone()
16422                }
16423            })
16424            .collect::<Vec<_>>();
16425
16426        if selected_sibling {
16427            self.change_selections(
16428                SelectionEffects::scroll(Autoscroll::fit()),
16429                window,
16430                cx,
16431                |s| {
16432                    s.select(new_selections);
16433                },
16434            );
16435        }
16436    }
16437
16438    pub fn select_prev_syntax_node(
16439        &mut self,
16440        _: &SelectPreviousSyntaxNode,
16441        window: &mut Window,
16442        cx: &mut Context<Self>,
16443    ) {
16444        let old_selections: Box<[_]> = self
16445            .selections
16446            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16447            .into();
16448        if old_selections.is_empty() {
16449            return;
16450        }
16451
16452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16453
16454        let buffer = self.buffer.read(cx).snapshot(cx);
16455        let mut selected_sibling = false;
16456
16457        let new_selections = old_selections
16458            .iter()
16459            .map(|selection| {
16460                let old_range = selection.start..selection.end;
16461                let old_range =
16462                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16463                let excerpt = buffer.excerpt_containing(old_range.clone());
16464
16465                if let Some(mut excerpt) = excerpt
16466                    && let Some(node) = excerpt
16467                        .buffer()
16468                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16469                {
16470                    let new_range = excerpt.map_range_from_buffer(
16471                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16472                    );
16473                    selected_sibling = true;
16474                    Selection {
16475                        id: selection.id,
16476                        start: new_range.start,
16477                        end: new_range.end,
16478                        goal: SelectionGoal::None,
16479                        reversed: selection.reversed,
16480                    }
16481                } else {
16482                    selection.clone()
16483                }
16484            })
16485            .collect::<Vec<_>>();
16486
16487        if selected_sibling {
16488            self.change_selections(
16489                SelectionEffects::scroll(Autoscroll::fit()),
16490                window,
16491                cx,
16492                |s| {
16493                    s.select(new_selections);
16494                },
16495            );
16496        }
16497    }
16498
16499    pub fn move_to_start_of_larger_syntax_node(
16500        &mut self,
16501        _: &MoveToStartOfLargerSyntaxNode,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        self.move_cursors_to_syntax_nodes(window, cx, false);
16506    }
16507
16508    pub fn move_to_end_of_larger_syntax_node(
16509        &mut self,
16510        _: &MoveToEndOfLargerSyntaxNode,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) {
16514        self.move_cursors_to_syntax_nodes(window, cx, true);
16515    }
16516
16517    fn move_cursors_to_syntax_nodes(
16518        &mut self,
16519        window: &mut Window,
16520        cx: &mut Context<Self>,
16521        move_to_end: bool,
16522    ) -> bool {
16523        let old_selections: Box<[_]> = self
16524            .selections
16525            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16526            .into();
16527        if old_selections.is_empty() {
16528            return false;
16529        }
16530
16531        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16532
16533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16534        let buffer = self.buffer.read(cx).snapshot(cx);
16535
16536        let mut any_cursor_moved = false;
16537        let new_selections = old_selections
16538            .iter()
16539            .map(|selection| {
16540                if !selection.is_empty() {
16541                    return selection.clone();
16542                }
16543
16544                let selection_pos = selection.head();
16545                let old_range = selection_pos..selection_pos;
16546
16547                let mut new_pos = selection_pos;
16548                let mut search_range = old_range;
16549                while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
16550                    search_range = range.clone();
16551                    if !node.is_named()
16552                        || display_map.intersects_fold(range.start)
16553                        || display_map.intersects_fold(range.end)
16554                        // If cursor is already at the end of the syntax node, continue searching
16555                        || (move_to_end && range.end == selection_pos)
16556                        // If cursor is already at the start of the syntax node, continue searching
16557                        || (!move_to_end && range.start == selection_pos)
16558                    {
16559                        continue;
16560                    }
16561
16562                    // If we found a string_content node, find the largest parent that is still string_content
16563                    // Enables us to skip to the end of strings without taking multiple steps inside the string
16564                    let (_, final_range) = if node.kind() == "string_content" {
16565                        let mut current_node = node;
16566                        let mut current_range = range;
16567                        while let Some((parent, parent_range)) =
16568                            buffer.syntax_ancestor(current_range.clone())
16569                        {
16570                            if parent.kind() == "string_content" {
16571                                current_node = parent;
16572                                current_range = parent_range;
16573                            } else {
16574                                break;
16575                            }
16576                        }
16577
16578                        (current_node, current_range)
16579                    } else {
16580                        (node, range)
16581                    };
16582
16583                    new_pos = if move_to_end {
16584                        final_range.end
16585                    } else {
16586                        final_range.start
16587                    };
16588
16589                    break;
16590                }
16591
16592                any_cursor_moved |= new_pos != selection_pos;
16593
16594                Selection {
16595                    id: selection.id,
16596                    start: new_pos,
16597                    end: new_pos,
16598                    goal: SelectionGoal::None,
16599                    reversed: false,
16600                }
16601            })
16602            .collect::<Vec<_>>();
16603
16604        self.change_selections(Default::default(), window, cx, |s| {
16605            s.select(new_selections);
16606        });
16607        self.request_autoscroll(Autoscroll::newest(), cx);
16608
16609        any_cursor_moved
16610    }
16611
16612    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16613        if !EditorSettings::get_global(cx).gutter.runnables {
16614            self.clear_tasks();
16615            return Task::ready(());
16616        }
16617        let project = self.project().map(Entity::downgrade);
16618        let task_sources = self.lsp_task_sources(cx);
16619        let multi_buffer = self.buffer.downgrade();
16620        cx.spawn_in(window, async move |editor, cx| {
16621            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16622            let Some(project) = project.and_then(|p| p.upgrade()) else {
16623                return;
16624            };
16625            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16626                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16627            }) else {
16628                return;
16629            };
16630
16631            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16632            if hide_runnables {
16633                return;
16634            }
16635            let new_rows =
16636                cx.background_spawn({
16637                    let snapshot = display_snapshot.clone();
16638                    async move {
16639                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16640                    }
16641                })
16642                    .await;
16643            let Ok(lsp_tasks) =
16644                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16645            else {
16646                return;
16647            };
16648            let lsp_tasks = lsp_tasks.await;
16649
16650            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16651                lsp_tasks
16652                    .into_iter()
16653                    .flat_map(|(kind, tasks)| {
16654                        tasks.into_iter().filter_map(move |(location, task)| {
16655                            Some((kind.clone(), location?, task))
16656                        })
16657                    })
16658                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16659                        let buffer = location.target.buffer;
16660                        let buffer_snapshot = buffer.read(cx).snapshot();
16661                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16662                            |(excerpt_id, snapshot, _)| {
16663                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16664                                    display_snapshot
16665                                        .buffer_snapshot()
16666                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16667                                } else {
16668                                    None
16669                                }
16670                            },
16671                        );
16672                        if let Some(offset) = offset {
16673                            let task_buffer_range =
16674                                location.target.range.to_point(&buffer_snapshot);
16675                            let context_buffer_range =
16676                                task_buffer_range.to_offset(&buffer_snapshot);
16677                            let context_range = BufferOffset(context_buffer_range.start)
16678                                ..BufferOffset(context_buffer_range.end);
16679
16680                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16681                                .or_insert_with(|| RunnableTasks {
16682                                    templates: Vec::new(),
16683                                    offset,
16684                                    column: task_buffer_range.start.column,
16685                                    extra_variables: HashMap::default(),
16686                                    context_range,
16687                                })
16688                                .templates
16689                                .push((kind, task.original_task().clone()));
16690                        }
16691
16692                        acc
16693                    })
16694            }) else {
16695                return;
16696            };
16697
16698            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16699                buffer.language_settings(cx).tasks.prefer_lsp
16700            }) else {
16701                return;
16702            };
16703
16704            let rows = Self::runnable_rows(
16705                project,
16706                display_snapshot,
16707                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16708                new_rows,
16709                cx.clone(),
16710            )
16711            .await;
16712            editor
16713                .update(cx, |editor, _| {
16714                    editor.clear_tasks();
16715                    for (key, mut value) in rows {
16716                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16717                            value.templates.extend(lsp_tasks.templates);
16718                        }
16719
16720                        editor.insert_tasks(key, value);
16721                    }
16722                    for (key, value) in lsp_tasks_by_rows {
16723                        editor.insert_tasks(key, value);
16724                    }
16725                })
16726                .ok();
16727        })
16728    }
16729    fn fetch_runnable_ranges(
16730        snapshot: &DisplaySnapshot,
16731        range: Range<Anchor>,
16732    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16733        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16734    }
16735
16736    fn runnable_rows(
16737        project: Entity<Project>,
16738        snapshot: DisplaySnapshot,
16739        prefer_lsp: bool,
16740        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16741        cx: AsyncWindowContext,
16742    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16743        cx.spawn(async move |cx| {
16744            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16745            for (run_range, mut runnable) in runnable_ranges {
16746                let Some(tasks) = cx
16747                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16748                    .ok()
16749                else {
16750                    continue;
16751                };
16752                let mut tasks = tasks.await;
16753
16754                if prefer_lsp {
16755                    tasks.retain(|(task_kind, _)| {
16756                        !matches!(task_kind, TaskSourceKind::Language { .. })
16757                    });
16758                }
16759                if tasks.is_empty() {
16760                    continue;
16761                }
16762
16763                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16764                let Some(row) = snapshot
16765                    .buffer_snapshot()
16766                    .buffer_line_for_row(MultiBufferRow(point.row))
16767                    .map(|(_, range)| range.start.row)
16768                else {
16769                    continue;
16770                };
16771
16772                let context_range =
16773                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16774                runnable_rows.push((
16775                    (runnable.buffer_id, row),
16776                    RunnableTasks {
16777                        templates: tasks,
16778                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16779                        context_range,
16780                        column: point.column,
16781                        extra_variables: runnable.extra_captures,
16782                    },
16783                ));
16784            }
16785            runnable_rows
16786        })
16787    }
16788
16789    fn templates_with_tags(
16790        project: &Entity<Project>,
16791        runnable: &mut Runnable,
16792        cx: &mut App,
16793    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16794        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16795            let (worktree_id, file) = project
16796                .buffer_for_id(runnable.buffer, cx)
16797                .and_then(|buffer| buffer.read(cx).file())
16798                .map(|file| (file.worktree_id(cx), file.clone()))
16799                .unzip();
16800
16801            (
16802                project.task_store().read(cx).task_inventory().cloned(),
16803                worktree_id,
16804                file,
16805            )
16806        });
16807
16808        let tags = mem::take(&mut runnable.tags);
16809        let language = runnable.language.clone();
16810        cx.spawn(async move |cx| {
16811            let mut templates_with_tags = Vec::new();
16812            if let Some(inventory) = inventory {
16813                for RunnableTag(tag) in tags {
16814                    let new_tasks = inventory.update(cx, |inventory, cx| {
16815                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16816                    });
16817                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16818                        move |(_, template)| {
16819                            template.tags.iter().any(|source_tag| source_tag == &tag)
16820                        },
16821                    ));
16822                }
16823            }
16824            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16825
16826            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16827                // Strongest source wins; if we have worktree tag binding, prefer that to
16828                // global and language bindings;
16829                // if we have a global binding, prefer that to language binding.
16830                let first_mismatch = templates_with_tags
16831                    .iter()
16832                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16833                if let Some(index) = first_mismatch {
16834                    templates_with_tags.truncate(index);
16835                }
16836            }
16837
16838            templates_with_tags
16839        })
16840    }
16841
16842    pub fn move_to_enclosing_bracket(
16843        &mut self,
16844        _: &MoveToEnclosingBracket,
16845        window: &mut Window,
16846        cx: &mut Context<Self>,
16847    ) {
16848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16849        self.change_selections(Default::default(), window, cx, |s| {
16850            s.move_offsets_with(|snapshot, selection| {
16851                let Some(enclosing_bracket_ranges) =
16852                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16853                else {
16854                    return;
16855                };
16856
16857                let mut best_length = usize::MAX;
16858                let mut best_inside = false;
16859                let mut best_in_bracket_range = false;
16860                let mut best_destination = None;
16861                for (open, close) in enclosing_bracket_ranges {
16862                    let close = close.to_inclusive();
16863                    let length = *close.end() - open.start;
16864                    let inside = selection.start >= open.end && selection.end <= *close.start();
16865                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16866                        || close.contains(&selection.head());
16867
16868                    // If best is next to a bracket and current isn't, skip
16869                    if !in_bracket_range && best_in_bracket_range {
16870                        continue;
16871                    }
16872
16873                    // Prefer smaller lengths unless best is inside and current isn't
16874                    if length > best_length && (best_inside || !inside) {
16875                        continue;
16876                    }
16877
16878                    best_length = length;
16879                    best_inside = inside;
16880                    best_in_bracket_range = in_bracket_range;
16881                    best_destination = Some(
16882                        if close.contains(&selection.start) && close.contains(&selection.end) {
16883                            if inside { open.end } else { open.start }
16884                        } else if inside {
16885                            *close.start()
16886                        } else {
16887                            *close.end()
16888                        },
16889                    );
16890                }
16891
16892                if let Some(destination) = best_destination {
16893                    selection.collapse_to(destination, SelectionGoal::None);
16894                }
16895            })
16896        });
16897    }
16898
16899    pub fn undo_selection(
16900        &mut self,
16901        _: &UndoSelection,
16902        window: &mut Window,
16903        cx: &mut Context<Self>,
16904    ) {
16905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16906        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16907            self.selection_history.mode = SelectionHistoryMode::Undoing;
16908            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16909                this.end_selection(window, cx);
16910                this.change_selections(
16911                    SelectionEffects::scroll(Autoscroll::newest()),
16912                    window,
16913                    cx,
16914                    |s| s.select_anchors(entry.selections.to_vec()),
16915                );
16916            });
16917            self.selection_history.mode = SelectionHistoryMode::Normal;
16918
16919            self.select_next_state = entry.select_next_state;
16920            self.select_prev_state = entry.select_prev_state;
16921            self.add_selections_state = entry.add_selections_state;
16922        }
16923    }
16924
16925    pub fn redo_selection(
16926        &mut self,
16927        _: &RedoSelection,
16928        window: &mut Window,
16929        cx: &mut Context<Self>,
16930    ) {
16931        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16932        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16933            self.selection_history.mode = SelectionHistoryMode::Redoing;
16934            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16935                this.end_selection(window, cx);
16936                this.change_selections(
16937                    SelectionEffects::scroll(Autoscroll::newest()),
16938                    window,
16939                    cx,
16940                    |s| s.select_anchors(entry.selections.to_vec()),
16941                );
16942            });
16943            self.selection_history.mode = SelectionHistoryMode::Normal;
16944
16945            self.select_next_state = entry.select_next_state;
16946            self.select_prev_state = entry.select_prev_state;
16947            self.add_selections_state = entry.add_selections_state;
16948        }
16949    }
16950
16951    pub fn expand_excerpts(
16952        &mut self,
16953        action: &ExpandExcerpts,
16954        _: &mut Window,
16955        cx: &mut Context<Self>,
16956    ) {
16957        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16958    }
16959
16960    pub fn expand_excerpts_down(
16961        &mut self,
16962        action: &ExpandExcerptsDown,
16963        _: &mut Window,
16964        cx: &mut Context<Self>,
16965    ) {
16966        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16967    }
16968
16969    pub fn expand_excerpts_up(
16970        &mut self,
16971        action: &ExpandExcerptsUp,
16972        _: &mut Window,
16973        cx: &mut Context<Self>,
16974    ) {
16975        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16976    }
16977
16978    pub fn expand_excerpts_for_direction(
16979        &mut self,
16980        lines: u32,
16981        direction: ExpandExcerptDirection,
16982        cx: &mut Context<Self>,
16983    ) {
16984        let selections = self.selections.disjoint_anchors_arc();
16985
16986        let lines = if lines == 0 {
16987            EditorSettings::get_global(cx).expand_excerpt_lines
16988        } else {
16989            lines
16990        };
16991
16992        let snapshot = self.buffer.read(cx).snapshot(cx);
16993        let mut excerpt_ids = selections
16994            .iter()
16995            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16996            .collect::<Vec<_>>();
16997        excerpt_ids.sort();
16998        excerpt_ids.dedup();
16999
17000        if self.delegate_expand_excerpts {
17001            cx.emit(EditorEvent::ExpandExcerptsRequested {
17002                excerpt_ids,
17003                lines,
17004                direction,
17005            });
17006            return;
17007        }
17008
17009        self.buffer.update(cx, |buffer, cx| {
17010            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
17011        })
17012    }
17013
17014    pub fn expand_excerpt(
17015        &mut self,
17016        excerpt: ExcerptId,
17017        direction: ExpandExcerptDirection,
17018        window: &mut Window,
17019        cx: &mut Context<Self>,
17020    ) {
17021        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17022
17023        if self.delegate_expand_excerpts {
17024            cx.emit(EditorEvent::ExpandExcerptsRequested {
17025                excerpt_ids: vec![excerpt],
17026                lines: lines_to_expand,
17027                direction,
17028            });
17029            return;
17030        }
17031
17032        let current_scroll_position = self.scroll_position(cx);
17033        let mut scroll = None;
17034
17035        if direction == ExpandExcerptDirection::Down {
17036            let multi_buffer = self.buffer.read(cx);
17037            let snapshot = multi_buffer.snapshot(cx);
17038            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
17039                && let Some(buffer) = multi_buffer.buffer(buffer_id)
17040                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
17041            {
17042                let buffer_snapshot = buffer.read(cx).snapshot();
17043                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
17044                let last_row = buffer_snapshot.max_point().row;
17045                let lines_below = last_row.saturating_sub(excerpt_end_row);
17046                if lines_below >= lines_to_expand {
17047                    scroll = Some(
17048                        current_scroll_position
17049                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17050                    );
17051                }
17052            }
17053        }
17054        if direction == ExpandExcerptDirection::Up
17055            && self
17056                .buffer
17057                .read(cx)
17058                .snapshot(cx)
17059                .excerpt_before(excerpt)
17060                .is_none()
17061        {
17062            scroll = Some(current_scroll_position);
17063        }
17064
17065        self.buffer.update(cx, |buffer, cx| {
17066            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
17067        });
17068
17069        if let Some(new_scroll_position) = scroll {
17070            self.set_scroll_position(new_scroll_position, window, cx);
17071        }
17072    }
17073
17074    pub fn go_to_singleton_buffer_point(
17075        &mut self,
17076        point: Point,
17077        window: &mut Window,
17078        cx: &mut Context<Self>,
17079    ) {
17080        self.go_to_singleton_buffer_range(point..point, window, cx);
17081    }
17082
17083    pub fn go_to_singleton_buffer_range(
17084        &mut self,
17085        range: Range<Point>,
17086        window: &mut Window,
17087        cx: &mut Context<Self>,
17088    ) {
17089        let multibuffer = self.buffer().read(cx);
17090        let Some(buffer) = multibuffer.as_singleton() else {
17091            return;
17092        };
17093        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
17094            return;
17095        };
17096        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
17097            return;
17098        };
17099        self.change_selections(
17100            SelectionEffects::default().nav_history(true),
17101            window,
17102            cx,
17103            |s| s.select_anchor_ranges([start..end]),
17104        );
17105    }
17106
17107    pub fn go_to_diagnostic(
17108        &mut self,
17109        action: &GoToDiagnostic,
17110        window: &mut Window,
17111        cx: &mut Context<Self>,
17112    ) {
17113        if !self.diagnostics_enabled() {
17114            return;
17115        }
17116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17117        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17118    }
17119
17120    pub fn go_to_prev_diagnostic(
17121        &mut self,
17122        action: &GoToPreviousDiagnostic,
17123        window: &mut Window,
17124        cx: &mut Context<Self>,
17125    ) {
17126        if !self.diagnostics_enabled() {
17127            return;
17128        }
17129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17130        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17131    }
17132
17133    pub fn go_to_diagnostic_impl(
17134        &mut self,
17135        direction: Direction,
17136        severity: GoToDiagnosticSeverityFilter,
17137        window: &mut Window,
17138        cx: &mut Context<Self>,
17139    ) {
17140        let buffer = self.buffer.read(cx).snapshot(cx);
17141        let selection = self
17142            .selections
17143            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17144
17145        let mut active_group_id = None;
17146        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17147            && active_group.active_range.start.to_offset(&buffer) == selection.start
17148        {
17149            active_group_id = Some(active_group.group_id);
17150        }
17151
17152        fn filtered<'a>(
17153            severity: GoToDiagnosticSeverityFilter,
17154            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17155        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17156            diagnostics
17157                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17158                .filter(|entry| entry.range.start != entry.range.end)
17159                .filter(|entry| !entry.diagnostic.is_unnecessary)
17160        }
17161
17162        let before = filtered(
17163            severity,
17164            buffer
17165                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17166                .filter(|entry| entry.range.start <= selection.start),
17167        );
17168        let after = filtered(
17169            severity,
17170            buffer
17171                .diagnostics_in_range(selection.start..buffer.len())
17172                .filter(|entry| entry.range.start >= selection.start),
17173        );
17174
17175        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17176        if direction == Direction::Prev {
17177            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17178            {
17179                for diagnostic in prev_diagnostics.into_iter().rev() {
17180                    if diagnostic.range.start != selection.start
17181                        || active_group_id
17182                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17183                    {
17184                        found = Some(diagnostic);
17185                        break 'outer;
17186                    }
17187                }
17188            }
17189        } else {
17190            for diagnostic in after.chain(before) {
17191                if diagnostic.range.start != selection.start
17192                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17193                {
17194                    found = Some(diagnostic);
17195                    break;
17196                }
17197            }
17198        }
17199        let Some(next_diagnostic) = found else {
17200            return;
17201        };
17202
17203        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17204        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17205            return;
17206        };
17207        let snapshot = self.snapshot(window, cx);
17208        if snapshot.intersects_fold(next_diagnostic.range.start) {
17209            self.unfold_ranges(
17210                std::slice::from_ref(&next_diagnostic.range),
17211                true,
17212                false,
17213                cx,
17214            );
17215        }
17216        self.change_selections(Default::default(), window, cx, |s| {
17217            s.select_ranges(vec![
17218                next_diagnostic.range.start..next_diagnostic.range.start,
17219            ])
17220        });
17221        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17222        self.refresh_edit_prediction(false, true, window, cx);
17223    }
17224
17225    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17227        let snapshot = self.snapshot(window, cx);
17228        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17229        self.go_to_hunk_before_or_after_position(
17230            &snapshot,
17231            selection.head(),
17232            Direction::Next,
17233            window,
17234            cx,
17235        );
17236    }
17237
17238    pub fn go_to_hunk_before_or_after_position(
17239        &mut self,
17240        snapshot: &EditorSnapshot,
17241        position: Point,
17242        direction: Direction,
17243        window: &mut Window,
17244        cx: &mut Context<Editor>,
17245    ) {
17246        let row = if direction == Direction::Next {
17247            self.hunk_after_position(snapshot, position)
17248                .map(|hunk| hunk.row_range.start)
17249        } else {
17250            self.hunk_before_position(snapshot, position)
17251        };
17252
17253        if let Some(row) = row {
17254            let destination = Point::new(row.0, 0);
17255            let autoscroll = Autoscroll::center();
17256
17257            self.unfold_ranges(&[destination..destination], false, false, cx);
17258            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17259                s.select_ranges([destination..destination]);
17260            });
17261        }
17262    }
17263
17264    fn hunk_after_position(
17265        &mut self,
17266        snapshot: &EditorSnapshot,
17267        position: Point,
17268    ) -> Option<MultiBufferDiffHunk> {
17269        snapshot
17270            .buffer_snapshot()
17271            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17272            .find(|hunk| hunk.row_range.start.0 > position.row)
17273            .or_else(|| {
17274                snapshot
17275                    .buffer_snapshot()
17276                    .diff_hunks_in_range(Point::zero()..position)
17277                    .find(|hunk| hunk.row_range.end.0 < position.row)
17278            })
17279    }
17280
17281    fn go_to_prev_hunk(
17282        &mut self,
17283        _: &GoToPreviousHunk,
17284        window: &mut Window,
17285        cx: &mut Context<Self>,
17286    ) {
17287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17288        let snapshot = self.snapshot(window, cx);
17289        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17290        self.go_to_hunk_before_or_after_position(
17291            &snapshot,
17292            selection.head(),
17293            Direction::Prev,
17294            window,
17295            cx,
17296        );
17297    }
17298
17299    fn hunk_before_position(
17300        &mut self,
17301        snapshot: &EditorSnapshot,
17302        position: Point,
17303    ) -> Option<MultiBufferRow> {
17304        snapshot
17305            .buffer_snapshot()
17306            .diff_hunk_before(position)
17307            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17308    }
17309
17310    fn go_to_next_change(
17311        &mut self,
17312        _: &GoToNextChange,
17313        window: &mut Window,
17314        cx: &mut Context<Self>,
17315    ) {
17316        if let Some(selections) = self
17317            .change_list
17318            .next_change(1, Direction::Next)
17319            .map(|s| s.to_vec())
17320        {
17321            self.change_selections(Default::default(), window, cx, |s| {
17322                let map = s.display_snapshot();
17323                s.select_display_ranges(selections.iter().map(|a| {
17324                    let point = a.to_display_point(&map);
17325                    point..point
17326                }))
17327            })
17328        }
17329    }
17330
17331    fn go_to_previous_change(
17332        &mut self,
17333        _: &GoToPreviousChange,
17334        window: &mut Window,
17335        cx: &mut Context<Self>,
17336    ) {
17337        if let Some(selections) = self
17338            .change_list
17339            .next_change(1, Direction::Prev)
17340            .map(|s| s.to_vec())
17341        {
17342            self.change_selections(Default::default(), window, cx, |s| {
17343                let map = s.display_snapshot();
17344                s.select_display_ranges(selections.iter().map(|a| {
17345                    let point = a.to_display_point(&map);
17346                    point..point
17347                }))
17348            })
17349        }
17350    }
17351
17352    pub fn go_to_next_document_highlight(
17353        &mut self,
17354        _: &GoToNextDocumentHighlight,
17355        window: &mut Window,
17356        cx: &mut Context<Self>,
17357    ) {
17358        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17359    }
17360
17361    pub fn go_to_prev_document_highlight(
17362        &mut self,
17363        _: &GoToPreviousDocumentHighlight,
17364        window: &mut Window,
17365        cx: &mut Context<Self>,
17366    ) {
17367        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17368    }
17369
17370    pub fn go_to_document_highlight_before_or_after_position(
17371        &mut self,
17372        direction: Direction,
17373        window: &mut Window,
17374        cx: &mut Context<Editor>,
17375    ) {
17376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17377        let snapshot = self.snapshot(window, cx);
17378        let buffer = &snapshot.buffer_snapshot();
17379        let position = self
17380            .selections
17381            .newest::<Point>(&snapshot.display_snapshot)
17382            .head();
17383        let anchor_position = buffer.anchor_after(position);
17384
17385        // Get all document highlights (both read and write)
17386        let mut all_highlights = Vec::new();
17387
17388        if let Some((_, read_highlights)) = self
17389            .background_highlights
17390            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17391        {
17392            all_highlights.extend(read_highlights.iter());
17393        }
17394
17395        if let Some((_, write_highlights)) = self
17396            .background_highlights
17397            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17398        {
17399            all_highlights.extend(write_highlights.iter());
17400        }
17401
17402        if all_highlights.is_empty() {
17403            return;
17404        }
17405
17406        // Sort highlights by position
17407        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17408
17409        let target_highlight = match direction {
17410            Direction::Next => {
17411                // Find the first highlight after the current position
17412                all_highlights
17413                    .iter()
17414                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17415            }
17416            Direction::Prev => {
17417                // Find the last highlight before the current position
17418                all_highlights
17419                    .iter()
17420                    .rev()
17421                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17422            }
17423        };
17424
17425        if let Some(highlight) = target_highlight {
17426            let destination = highlight.start.to_point(buffer);
17427            let autoscroll = Autoscroll::center();
17428
17429            self.unfold_ranges(&[destination..destination], false, false, cx);
17430            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17431                s.select_ranges([destination..destination]);
17432            });
17433        }
17434    }
17435
17436    fn go_to_line<T: 'static>(
17437        &mut self,
17438        position: Anchor,
17439        highlight_color: Option<Hsla>,
17440        window: &mut Window,
17441        cx: &mut Context<Self>,
17442    ) {
17443        let snapshot = self.snapshot(window, cx).display_snapshot;
17444        let position = position.to_point(&snapshot.buffer_snapshot());
17445        let start = snapshot
17446            .buffer_snapshot()
17447            .clip_point(Point::new(position.row, 0), Bias::Left);
17448        let end = start + Point::new(1, 0);
17449        let start = snapshot.buffer_snapshot().anchor_before(start);
17450        let end = snapshot.buffer_snapshot().anchor_before(end);
17451
17452        self.highlight_rows::<T>(
17453            start..end,
17454            highlight_color
17455                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17456            Default::default(),
17457            cx,
17458        );
17459
17460        if self.buffer.read(cx).is_singleton() {
17461            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17462        }
17463    }
17464
17465    pub fn go_to_definition(
17466        &mut self,
17467        _: &GoToDefinition,
17468        window: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) -> Task<Result<Navigated>> {
17471        let definition =
17472            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17473        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17474        cx.spawn_in(window, async move |editor, cx| {
17475            if definition.await? == Navigated::Yes {
17476                return Ok(Navigated::Yes);
17477            }
17478            match fallback_strategy {
17479                GoToDefinitionFallback::None => Ok(Navigated::No),
17480                GoToDefinitionFallback::FindAllReferences => {
17481                    match editor.update_in(cx, |editor, window, cx| {
17482                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17483                    })? {
17484                        Some(references) => references.await,
17485                        None => Ok(Navigated::No),
17486                    }
17487                }
17488            }
17489        })
17490    }
17491
17492    pub fn go_to_declaration(
17493        &mut self,
17494        _: &GoToDeclaration,
17495        window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) -> Task<Result<Navigated>> {
17498        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17499    }
17500
17501    pub fn go_to_declaration_split(
17502        &mut self,
17503        _: &GoToDeclaration,
17504        window: &mut Window,
17505        cx: &mut Context<Self>,
17506    ) -> Task<Result<Navigated>> {
17507        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17508    }
17509
17510    pub fn go_to_implementation(
17511        &mut self,
17512        _: &GoToImplementation,
17513        window: &mut Window,
17514        cx: &mut Context<Self>,
17515    ) -> Task<Result<Navigated>> {
17516        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17517    }
17518
17519    pub fn go_to_implementation_split(
17520        &mut self,
17521        _: &GoToImplementationSplit,
17522        window: &mut Window,
17523        cx: &mut Context<Self>,
17524    ) -> Task<Result<Navigated>> {
17525        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17526    }
17527
17528    pub fn go_to_type_definition(
17529        &mut self,
17530        _: &GoToTypeDefinition,
17531        window: &mut Window,
17532        cx: &mut Context<Self>,
17533    ) -> Task<Result<Navigated>> {
17534        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17535    }
17536
17537    pub fn go_to_definition_split(
17538        &mut self,
17539        _: &GoToDefinitionSplit,
17540        window: &mut Window,
17541        cx: &mut Context<Self>,
17542    ) -> Task<Result<Navigated>> {
17543        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17544    }
17545
17546    pub fn go_to_type_definition_split(
17547        &mut self,
17548        _: &GoToTypeDefinitionSplit,
17549        window: &mut Window,
17550        cx: &mut Context<Self>,
17551    ) -> Task<Result<Navigated>> {
17552        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17553    }
17554
17555    fn go_to_definition_of_kind(
17556        &mut self,
17557        kind: GotoDefinitionKind,
17558        split: bool,
17559        window: &mut Window,
17560        cx: &mut Context<Self>,
17561    ) -> Task<Result<Navigated>> {
17562        let Some(provider) = self.semantics_provider.clone() else {
17563            return Task::ready(Ok(Navigated::No));
17564        };
17565        let head = self
17566            .selections
17567            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17568            .head();
17569        let buffer = self.buffer.read(cx);
17570        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17571            return Task::ready(Ok(Navigated::No));
17572        };
17573        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17574            return Task::ready(Ok(Navigated::No));
17575        };
17576
17577        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
17578
17579        cx.spawn_in(window, async move |editor, cx| {
17580            let Some(definitions) = definitions.await? else {
17581                return Ok(Navigated::No);
17582            };
17583            let navigated = editor
17584                .update_in(cx, |editor, window, cx| {
17585                    editor.navigate_to_hover_links(
17586                        Some(kind),
17587                        definitions
17588                            .into_iter()
17589                            .filter(|location| {
17590                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17591                            })
17592                            .map(HoverLink::Text)
17593                            .collect::<Vec<_>>(),
17594                        nav_entry,
17595                        split,
17596                        window,
17597                        cx,
17598                    )
17599                })?
17600                .await?;
17601            anyhow::Ok(navigated)
17602        })
17603    }
17604
17605    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17606        let selection = self.selections.newest_anchor();
17607        let head = selection.head();
17608        let tail = selection.tail();
17609
17610        let Some((buffer, start_position)) =
17611            self.buffer.read(cx).text_anchor_for_position(head, cx)
17612        else {
17613            return;
17614        };
17615
17616        let end_position = if head != tail {
17617            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17618                return;
17619            };
17620            Some(pos)
17621        } else {
17622            None
17623        };
17624
17625        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17626            let url = if let Some(end_pos) = end_position {
17627                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17628            } else {
17629                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17630            };
17631
17632            if let Some(url) = url {
17633                cx.update(|window, cx| {
17634                    if parse_zed_link(&url, cx).is_some() {
17635                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17636                    } else {
17637                        cx.open_url(&url);
17638                    }
17639                })?;
17640            }
17641
17642            anyhow::Ok(())
17643        });
17644
17645        url_finder.detach();
17646    }
17647
17648    pub fn open_selected_filename(
17649        &mut self,
17650        _: &OpenSelectedFilename,
17651        window: &mut Window,
17652        cx: &mut Context<Self>,
17653    ) {
17654        let Some(workspace) = self.workspace() else {
17655            return;
17656        };
17657
17658        let position = self.selections.newest_anchor().head();
17659
17660        let Some((buffer, buffer_position)) =
17661            self.buffer.read(cx).text_anchor_for_position(position, cx)
17662        else {
17663            return;
17664        };
17665
17666        let project = self.project.clone();
17667
17668        cx.spawn_in(window, async move |_, cx| {
17669            let result = find_file(&buffer, project, buffer_position, cx).await;
17670
17671            if let Some((_, path)) = result {
17672                workspace
17673                    .update_in(cx, |workspace, window, cx| {
17674                        workspace.open_resolved_path(path, window, cx)
17675                    })?
17676                    .await?;
17677            }
17678            anyhow::Ok(())
17679        })
17680        .detach();
17681    }
17682
17683    pub(crate) fn navigate_to_hover_links(
17684        &mut self,
17685        kind: Option<GotoDefinitionKind>,
17686        definitions: Vec<HoverLink>,
17687        origin: Option<NavigationEntry>,
17688        split: bool,
17689        window: &mut Window,
17690        cx: &mut Context<Editor>,
17691    ) -> Task<Result<Navigated>> {
17692        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17693        let mut first_url_or_file = None;
17694        let definitions: Vec<_> = definitions
17695            .into_iter()
17696            .filter_map(|def| match def {
17697                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17698                HoverLink::InlayHint(lsp_location, server_id) => {
17699                    let computation =
17700                        self.compute_target_location(lsp_location, server_id, window, cx);
17701                    Some(cx.background_spawn(computation))
17702                }
17703                HoverLink::Url(url) => {
17704                    first_url_or_file = Some(Either::Left(url));
17705                    None
17706                }
17707                HoverLink::File(path) => {
17708                    first_url_or_file = Some(Either::Right(path));
17709                    None
17710                }
17711            })
17712            .collect();
17713
17714        let workspace = self.workspace();
17715
17716        cx.spawn_in(window, async move |editor, cx| {
17717            let locations: Vec<Location> = future::join_all(definitions)
17718                .await
17719                .into_iter()
17720                .filter_map(|location| location.transpose())
17721                .collect::<Result<_>>()
17722                .context("location tasks")?;
17723            let mut locations = cx.update(|_, cx| {
17724                locations
17725                    .into_iter()
17726                    .map(|location| {
17727                        let buffer = location.buffer.read(cx);
17728                        (location.buffer, location.range.to_point(buffer))
17729                    })
17730                    .into_group_map()
17731            })?;
17732            let mut num_locations = 0;
17733            for ranges in locations.values_mut() {
17734                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17735                ranges.dedup();
17736                num_locations += ranges.len();
17737            }
17738
17739            if num_locations > 1 {
17740                let tab_kind = match kind {
17741                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17742                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17743                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17744                    Some(GotoDefinitionKind::Type) => "Types",
17745                };
17746                let title = editor
17747                    .update_in(cx, |_, _, cx| {
17748                        let target = locations
17749                            .iter()
17750                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17751                            .map(|(buffer, location)| {
17752                                buffer
17753                                    .read(cx)
17754                                    .text_for_range(location.clone())
17755                                    .collect::<String>()
17756                            })
17757                            .filter(|text| !text.contains('\n'))
17758                            .unique()
17759                            .take(3)
17760                            .join(", ");
17761                        if target.is_empty() {
17762                            tab_kind.to_owned()
17763                        } else {
17764                            format!("{tab_kind} for {target}")
17765                        }
17766                    })
17767                    .context("buffer title")?;
17768
17769                let Some(workspace) = workspace else {
17770                    return Ok(Navigated::No);
17771                };
17772
17773                let opened = workspace
17774                    .update_in(cx, |workspace, window, cx| {
17775                        let allow_preview = PreviewTabsSettings::get_global(cx)
17776                            .enable_preview_multibuffer_from_code_navigation;
17777                        if let Some((target_editor, target_pane)) =
17778                            Self::open_locations_in_multibuffer(
17779                                workspace,
17780                                locations,
17781                                title,
17782                                split,
17783                                allow_preview,
17784                                MultibufferSelectionMode::First,
17785                                window,
17786                                cx,
17787                            )
17788                        {
17789                            // We create our own nav history instead of using
17790                            // `target_editor.nav_history` because `nav_history`
17791                            // seems to be populated asynchronously when an item
17792                            // is added to a pane
17793                            let mut nav_history = target_pane
17794                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
17795                            target_editor.update(cx, |editor, cx| {
17796                                let nav_data = editor
17797                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
17798                                let target =
17799                                    Some(nav_history.navigation_entry(Some(
17800                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
17801                                    )));
17802                                nav_history.push_tag(origin, target);
17803                            })
17804                        }
17805                    })
17806                    .is_ok();
17807
17808                anyhow::Ok(Navigated::from_bool(opened))
17809            } else if num_locations == 0 {
17810                // If there is one url or file, open it directly
17811                match first_url_or_file {
17812                    Some(Either::Left(url)) => {
17813                        cx.update(|window, cx| {
17814                            if parse_zed_link(&url, cx).is_some() {
17815                                window
17816                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17817                            } else {
17818                                cx.open_url(&url);
17819                            }
17820                        })?;
17821                        Ok(Navigated::Yes)
17822                    }
17823                    Some(Either::Right(path)) => {
17824                        // TODO(andrew): respect preview tab settings
17825                        //               `enable_keep_preview_on_code_navigation` and
17826                        //               `enable_preview_file_from_code_navigation`
17827                        let Some(workspace) = workspace else {
17828                            return Ok(Navigated::No);
17829                        };
17830                        workspace
17831                            .update_in(cx, |workspace, window, cx| {
17832                                workspace.open_resolved_path(path, window, cx)
17833                            })?
17834                            .await?;
17835                        Ok(Navigated::Yes)
17836                    }
17837                    None => Ok(Navigated::No),
17838                }
17839            } else {
17840                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17841                let target_range = target_ranges.first().unwrap().clone();
17842
17843                editor.update_in(cx, |editor, window, cx| {
17844                    let range = editor.range_for_match(&target_range);
17845                    let range = collapse_multiline_range(range);
17846
17847                    if !split
17848                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17849                    {
17850                        editor.go_to_singleton_buffer_range(range, window, cx);
17851
17852                        let target =
17853                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
17854                        if let Some(mut nav_history) = editor.nav_history.clone() {
17855                            nav_history.push_tag(origin, target);
17856                        }
17857                    } else {
17858                        let Some(workspace) = workspace else {
17859                            return Navigated::No;
17860                        };
17861                        let pane = workspace.read(cx).active_pane().clone();
17862                        window.defer(cx, move |window, cx| {
17863                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
17864                                workspace.update(cx, |workspace, cx| {
17865                                    let pane = if split {
17866                                        workspace.adjacent_pane(window, cx)
17867                                    } else {
17868                                        workspace.active_pane().clone()
17869                                    };
17870
17871                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17872                                    let keep_old_preview = preview_tabs_settings
17873                                        .enable_keep_preview_on_code_navigation;
17874                                    let allow_new_preview = preview_tabs_settings
17875                                        .enable_preview_file_from_code_navigation;
17876
17877                                    let editor = workspace.open_project_item(
17878                                        pane.clone(),
17879                                        target_buffer.clone(),
17880                                        true,
17881                                        true,
17882                                        keep_old_preview,
17883                                        allow_new_preview,
17884                                        window,
17885                                        cx,
17886                                    );
17887                                    (editor, pane)
17888                                });
17889                            // We create our own nav history instead of using
17890                            // `target_editor.nav_history` because `nav_history`
17891                            // seems to be populated asynchronously when an item
17892                            // is added to a pane
17893                            let mut nav_history = target_pane
17894                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
17895                            target_editor.update(cx, |target_editor, cx| {
17896                                // When selecting a definition in a different buffer, disable the nav history
17897                                // to avoid creating a history entry at the previous cursor location.
17898                                pane.update(cx, |pane, _| pane.disable_history());
17899                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17900
17901                                let nav_data = target_editor.navigation_data(
17902                                    target_editor.selections.newest_anchor().head(),
17903                                    cx,
17904                                );
17905                                let target =
17906                                    Some(nav_history.navigation_entry(Some(
17907                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
17908                                    )));
17909                                nav_history.push_tag(origin, target);
17910                                pane.update(cx, |pane, _| pane.enable_history());
17911                            });
17912                        });
17913                    }
17914                    Navigated::Yes
17915                })
17916            }
17917        })
17918    }
17919
17920    fn compute_target_location(
17921        &self,
17922        lsp_location: lsp::Location,
17923        server_id: LanguageServerId,
17924        window: &mut Window,
17925        cx: &mut Context<Self>,
17926    ) -> Task<anyhow::Result<Option<Location>>> {
17927        let Some(project) = self.project.clone() else {
17928            return Task::ready(Ok(None));
17929        };
17930
17931        cx.spawn_in(window, async move |editor, cx| {
17932            let location_task = editor.update(cx, |_, cx| {
17933                project.update(cx, |project, cx| {
17934                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17935                })
17936            })?;
17937            let location = Some({
17938                let target_buffer_handle = location_task.await.context("open local buffer")?;
17939                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17940                    let target_start = target_buffer
17941                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17942                    let target_end = target_buffer
17943                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17944                    target_buffer.anchor_after(target_start)
17945                        ..target_buffer.anchor_before(target_end)
17946                });
17947                Location {
17948                    buffer: target_buffer_handle,
17949                    range,
17950                }
17951            });
17952            Ok(location)
17953        })
17954    }
17955
17956    fn go_to_next_reference(
17957        &mut self,
17958        _: &GoToNextReference,
17959        window: &mut Window,
17960        cx: &mut Context<Self>,
17961    ) {
17962        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17963        if let Some(task) = task {
17964            task.detach();
17965        };
17966    }
17967
17968    fn go_to_prev_reference(
17969        &mut self,
17970        _: &GoToPreviousReference,
17971        window: &mut Window,
17972        cx: &mut Context<Self>,
17973    ) {
17974        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17975        if let Some(task) = task {
17976            task.detach();
17977        };
17978    }
17979
17980    pub fn go_to_reference_before_or_after_position(
17981        &mut self,
17982        direction: Direction,
17983        count: usize,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) -> Option<Task<Result<()>>> {
17987        let selection = self.selections.newest_anchor();
17988        let head = selection.head();
17989
17990        let multi_buffer = self.buffer.read(cx);
17991
17992        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17993        let workspace = self.workspace()?;
17994        let project = workspace.read(cx).project().clone();
17995        let references =
17996            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17997        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17998            let Some(locations) = references.await? else {
17999                return Ok(());
18000            };
18001
18002            if locations.is_empty() {
18003                // totally normal - the cursor may be on something which is not
18004                // a symbol (e.g. a keyword)
18005                log::info!("no references found under cursor");
18006                return Ok(());
18007            }
18008
18009            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18010
18011            let (locations, current_location_index) =
18012                multi_buffer.update(cx, |multi_buffer, cx| {
18013                    let mut locations = locations
18014                        .into_iter()
18015                        .filter_map(|loc| {
18016                            let start = multi_buffer.buffer_anchor_to_anchor(
18017                                &loc.buffer,
18018                                loc.range.start,
18019                                cx,
18020                            )?;
18021                            let end = multi_buffer.buffer_anchor_to_anchor(
18022                                &loc.buffer,
18023                                loc.range.end,
18024                                cx,
18025                            )?;
18026                            Some(start..end)
18027                        })
18028                        .collect::<Vec<_>>();
18029
18030                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18031                    // There is an O(n) implementation, but given this list will be
18032                    // small (usually <100 items), the extra O(log(n)) factor isn't
18033                    // worth the (surprisingly large amount of) extra complexity.
18034                    locations
18035                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18036
18037                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18038
18039                    let current_location_index = locations.iter().position(|loc| {
18040                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18041                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18042                    });
18043
18044                    (locations, current_location_index)
18045                });
18046
18047            let Some(current_location_index) = current_location_index else {
18048                // This indicates something has gone wrong, because we already
18049                // handle the "no references" case above
18050                log::error!(
18051                    "failed to find current reference under cursor. Total references: {}",
18052                    locations.len()
18053                );
18054                return Ok(());
18055            };
18056
18057            let destination_location_index = match direction {
18058                Direction::Next => (current_location_index + count) % locations.len(),
18059                Direction::Prev => {
18060                    (current_location_index + locations.len() - count % locations.len())
18061                        % locations.len()
18062                }
18063            };
18064
18065            // TODO(cameron): is this needed?
18066            // the thinking is to avoid "jumping to the current location" (avoid
18067            // polluting "jumplist" in vim terms)
18068            if current_location_index == destination_location_index {
18069                return Ok(());
18070            }
18071
18072            let Range { start, end } = locations[destination_location_index];
18073
18074            editor.update_in(cx, |editor, window, cx| {
18075                let effects = SelectionEffects::default();
18076
18077                editor.unfold_ranges(&[start..end], false, false, cx);
18078                editor.change_selections(effects, window, cx, |s| {
18079                    s.select_ranges([start..start]);
18080                });
18081            })?;
18082
18083            Ok(())
18084        }))
18085    }
18086
18087    pub fn find_all_references(
18088        &mut self,
18089        action: &FindAllReferences,
18090        window: &mut Window,
18091        cx: &mut Context<Self>,
18092    ) -> Option<Task<Result<Navigated>>> {
18093        let always_open_multibuffer = action.always_open_multibuffer;
18094        let selection = self.selections.newest_anchor();
18095        let multi_buffer = self.buffer.read(cx);
18096        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18097        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18098        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18099        let head = selection_offset.head();
18100
18101        let head_anchor = multi_buffer_snapshot.anchor_at(
18102            head,
18103            if head < selection_offset.tail() {
18104                Bias::Right
18105            } else {
18106                Bias::Left
18107            },
18108        );
18109
18110        match self
18111            .find_all_references_task_sources
18112            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18113        {
18114            Ok(_) => {
18115                log::info!(
18116                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18117                );
18118                return None;
18119            }
18120            Err(i) => {
18121                self.find_all_references_task_sources.insert(i, head_anchor);
18122            }
18123        }
18124
18125        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18126        let workspace = self.workspace()?;
18127        let project = workspace.read(cx).project().clone();
18128        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18129        Some(cx.spawn_in(window, async move |editor, cx| {
18130            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18131                if let Ok(i) = editor
18132                    .find_all_references_task_sources
18133                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18134                {
18135                    editor.find_all_references_task_sources.remove(i);
18136                }
18137            });
18138
18139            let Some(locations) = references.await? else {
18140                return anyhow::Ok(Navigated::No);
18141            };
18142            let mut locations = cx.update(|_, cx| {
18143                locations
18144                    .into_iter()
18145                    .map(|location| {
18146                        let buffer = location.buffer.read(cx);
18147                        (location.buffer, location.range.to_point(buffer))
18148                    })
18149                    // if special-casing the single-match case, remove ranges
18150                    // that intersect current selection
18151                    .filter(|(location_buffer, location)| {
18152                        if always_open_multibuffer || &buffer != location_buffer {
18153                            return true;
18154                        }
18155
18156                        !location.contains_inclusive(&selection_point.range())
18157                    })
18158                    .into_group_map()
18159            })?;
18160            if locations.is_empty() {
18161                return anyhow::Ok(Navigated::No);
18162            }
18163            for ranges in locations.values_mut() {
18164                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18165                ranges.dedup();
18166            }
18167            let mut num_locations = 0;
18168            for ranges in locations.values_mut() {
18169                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18170                ranges.dedup();
18171                num_locations += ranges.len();
18172            }
18173
18174            if num_locations == 1 && !always_open_multibuffer {
18175                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18176                let target_range = target_ranges.first().unwrap().clone();
18177
18178                return editor.update_in(cx, |editor, window, cx| {
18179                    let range = target_range.to_point(target_buffer.read(cx));
18180                    let range = editor.range_for_match(&range);
18181                    let range = range.start..range.start;
18182
18183                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18184                        editor.go_to_singleton_buffer_range(range, window, cx);
18185                    } else {
18186                        let pane = workspace.read(cx).active_pane().clone();
18187                        window.defer(cx, move |window, cx| {
18188                            let target_editor: Entity<Self> =
18189                                workspace.update(cx, |workspace, cx| {
18190                                    let pane = workspace.active_pane().clone();
18191
18192                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18193                                    let keep_old_preview = preview_tabs_settings
18194                                        .enable_keep_preview_on_code_navigation;
18195                                    let allow_new_preview = preview_tabs_settings
18196                                        .enable_preview_file_from_code_navigation;
18197
18198                                    workspace.open_project_item(
18199                                        pane,
18200                                        target_buffer.clone(),
18201                                        true,
18202                                        true,
18203                                        keep_old_preview,
18204                                        allow_new_preview,
18205                                        window,
18206                                        cx,
18207                                    )
18208                                });
18209                            target_editor.update(cx, |target_editor, cx| {
18210                                // When selecting a definition in a different buffer, disable the nav history
18211                                // to avoid creating a history entry at the previous cursor location.
18212                                pane.update(cx, |pane, _| pane.disable_history());
18213                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18214                                pane.update(cx, |pane, _| pane.enable_history());
18215                            });
18216                        });
18217                    }
18218                    Navigated::No
18219                });
18220            }
18221
18222            workspace.update_in(cx, |workspace, window, cx| {
18223                let target = locations
18224                    .iter()
18225                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18226                    .map(|(buffer, location)| {
18227                        buffer
18228                            .read(cx)
18229                            .text_for_range(location.clone())
18230                            .collect::<String>()
18231                    })
18232                    .filter(|text| !text.contains('\n'))
18233                    .unique()
18234                    .take(3)
18235                    .join(", ");
18236                let title = if target.is_empty() {
18237                    "References".to_owned()
18238                } else {
18239                    format!("References to {target}")
18240                };
18241                let allow_preview = PreviewTabsSettings::get_global(cx)
18242                    .enable_preview_multibuffer_from_code_navigation;
18243                Self::open_locations_in_multibuffer(
18244                    workspace,
18245                    locations,
18246                    title,
18247                    false,
18248                    allow_preview,
18249                    MultibufferSelectionMode::First,
18250                    window,
18251                    cx,
18252                );
18253                Navigated::Yes
18254            })
18255        }))
18256    }
18257
18258    /// Opens a multibuffer with the given project locations in it.
18259    pub fn open_locations_in_multibuffer(
18260        workspace: &mut Workspace,
18261        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18262        title: String,
18263        split: bool,
18264        allow_preview: bool,
18265        multibuffer_selection_mode: MultibufferSelectionMode,
18266        window: &mut Window,
18267        cx: &mut Context<Workspace>,
18268    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18269        if locations.is_empty() {
18270            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18271            return None;
18272        }
18273
18274        let capability = workspace.project().read(cx).capability();
18275        let mut ranges = <Vec<Range<Anchor>>>::new();
18276
18277        // a key to find existing multibuffer editors with the same set of locations
18278        // to prevent us from opening more and more multibuffer tabs for searches and the like
18279        let mut key = (title.clone(), vec![]);
18280        let excerpt_buffer = cx.new(|cx| {
18281            let key = &mut key.1;
18282            let mut multibuffer = MultiBuffer::new(capability);
18283            for (buffer, mut ranges_for_buffer) in locations {
18284                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18285                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18286                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18287                    PathKey::for_buffer(&buffer, cx),
18288                    buffer.clone(),
18289                    ranges_for_buffer,
18290                    multibuffer_context_lines(cx),
18291                    cx,
18292                );
18293                ranges.extend(new_ranges)
18294            }
18295
18296            multibuffer.with_title(title)
18297        });
18298        let existing = workspace.active_pane().update(cx, |pane, cx| {
18299            pane.items()
18300                .filter_map(|item| item.downcast::<Editor>())
18301                .find(|editor| {
18302                    editor
18303                        .read(cx)
18304                        .lookup_key
18305                        .as_ref()
18306                        .and_then(|it| {
18307                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18308                        })
18309                        .is_some_and(|it| *it == key)
18310                })
18311        });
18312        let was_existing = existing.is_some();
18313        let editor = existing.unwrap_or_else(|| {
18314            cx.new(|cx| {
18315                let mut editor = Editor::for_multibuffer(
18316                    excerpt_buffer,
18317                    Some(workspace.project().clone()),
18318                    window,
18319                    cx,
18320                );
18321                editor.lookup_key = Some(Box::new(key));
18322                editor
18323            })
18324        });
18325        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18326            MultibufferSelectionMode::First => {
18327                if let Some(first_range) = ranges.first() {
18328                    editor.change_selections(
18329                        SelectionEffects::no_scroll(),
18330                        window,
18331                        cx,
18332                        |selections| {
18333                            selections.clear_disjoint();
18334                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18335                        },
18336                    );
18337                }
18338                editor.highlight_background::<Self>(
18339                    &ranges,
18340                    |_, theme| theme.colors().editor_highlighted_line_background,
18341                    cx,
18342                );
18343            }
18344            MultibufferSelectionMode::All => {
18345                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18346                    selections.clear_disjoint();
18347                    selections.select_anchor_ranges(ranges);
18348                });
18349            }
18350        });
18351
18352        let item = Box::new(editor.clone());
18353
18354        let pane = if split {
18355            workspace.adjacent_pane(window, cx)
18356        } else {
18357            workspace.active_pane().clone()
18358        };
18359        let activate_pane = split;
18360
18361        let mut destination_index = None;
18362        pane.update(cx, |pane, cx| {
18363            if allow_preview && !was_existing {
18364                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18365            }
18366            if was_existing && !allow_preview {
18367                pane.unpreview_item_if_preview(item.item_id());
18368            }
18369            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18370        });
18371
18372        Some((editor, pane))
18373    }
18374
18375    pub fn rename(
18376        &mut self,
18377        _: &Rename,
18378        window: &mut Window,
18379        cx: &mut Context<Self>,
18380    ) -> Option<Task<Result<()>>> {
18381        use language::ToOffset as _;
18382
18383        let provider = self.semantics_provider.clone()?;
18384        let selection = self.selections.newest_anchor().clone();
18385        let (cursor_buffer, cursor_buffer_position) = self
18386            .buffer
18387            .read(cx)
18388            .text_anchor_for_position(selection.head(), cx)?;
18389        let (tail_buffer, cursor_buffer_position_end) = self
18390            .buffer
18391            .read(cx)
18392            .text_anchor_for_position(selection.tail(), cx)?;
18393        if tail_buffer != cursor_buffer {
18394            return None;
18395        }
18396
18397        let snapshot = cursor_buffer.read(cx).snapshot();
18398        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18399        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18400        let prepare_rename = provider
18401            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18402            .unwrap_or_else(|| Task::ready(Ok(None)));
18403        drop(snapshot);
18404
18405        Some(cx.spawn_in(window, async move |this, cx| {
18406            let rename_range = if let Some(range) = prepare_rename.await? {
18407                Some(range)
18408            } else {
18409                this.update(cx, |this, cx| {
18410                    let buffer = this.buffer.read(cx).snapshot(cx);
18411                    let mut buffer_highlights = this
18412                        .document_highlights_for_position(selection.head(), &buffer)
18413                        .filter(|highlight| {
18414                            highlight.start.excerpt_id == selection.head().excerpt_id
18415                                && highlight.end.excerpt_id == selection.head().excerpt_id
18416                        });
18417                    buffer_highlights
18418                        .next()
18419                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18420                })?
18421            };
18422            if let Some(rename_range) = rename_range {
18423                this.update_in(cx, |this, window, cx| {
18424                    let snapshot = cursor_buffer.read(cx).snapshot();
18425                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18426                    let cursor_offset_in_rename_range =
18427                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18428                    let cursor_offset_in_rename_range_end =
18429                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18430
18431                    this.take_rename(false, window, cx);
18432                    let buffer = this.buffer.read(cx).read(cx);
18433                    let cursor_offset = selection.head().to_offset(&buffer);
18434                    let rename_start =
18435                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18436                    let rename_end = rename_start + rename_buffer_range.len();
18437                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18438                    let mut old_highlight_id = None;
18439                    let old_name: Arc<str> = buffer
18440                        .chunks(rename_start..rename_end, true)
18441                        .map(|chunk| {
18442                            if old_highlight_id.is_none() {
18443                                old_highlight_id = chunk.syntax_highlight_id;
18444                            }
18445                            chunk.text
18446                        })
18447                        .collect::<String>()
18448                        .into();
18449
18450                    drop(buffer);
18451
18452                    // Position the selection in the rename editor so that it matches the current selection.
18453                    this.show_local_selections = false;
18454                    let rename_editor = cx.new(|cx| {
18455                        let mut editor = Editor::single_line(window, cx);
18456                        editor.buffer.update(cx, |buffer, cx| {
18457                            buffer.edit(
18458                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18459                                None,
18460                                cx,
18461                            )
18462                        });
18463                        let cursor_offset_in_rename_range =
18464                            MultiBufferOffset(cursor_offset_in_rename_range);
18465                        let cursor_offset_in_rename_range_end =
18466                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18467                        let rename_selection_range = match cursor_offset_in_rename_range
18468                            .cmp(&cursor_offset_in_rename_range_end)
18469                        {
18470                            Ordering::Equal => {
18471                                editor.select_all(&SelectAll, window, cx);
18472                                return editor;
18473                            }
18474                            Ordering::Less => {
18475                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18476                            }
18477                            Ordering::Greater => {
18478                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18479                            }
18480                        };
18481                        if rename_selection_range.end.0 > old_name.len() {
18482                            editor.select_all(&SelectAll, window, cx);
18483                        } else {
18484                            editor.change_selections(Default::default(), window, cx, |s| {
18485                                s.select_ranges([rename_selection_range]);
18486                            });
18487                        }
18488                        editor
18489                    });
18490                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18491                        if e == &EditorEvent::Focused {
18492                            cx.emit(EditorEvent::FocusedIn)
18493                        }
18494                    })
18495                    .detach();
18496
18497                    let write_highlights =
18498                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18499                    let read_highlights =
18500                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18501                    let ranges = write_highlights
18502                        .iter()
18503                        .flat_map(|(_, ranges)| ranges.iter())
18504                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18505                        .cloned()
18506                        .collect();
18507
18508                    this.highlight_text::<Rename>(
18509                        ranges,
18510                        HighlightStyle {
18511                            fade_out: Some(0.6),
18512                            ..Default::default()
18513                        },
18514                        cx,
18515                    );
18516                    let rename_focus_handle = rename_editor.focus_handle(cx);
18517                    window.focus(&rename_focus_handle, cx);
18518                    let block_id = this.insert_blocks(
18519                        [BlockProperties {
18520                            style: BlockStyle::Flex,
18521                            placement: BlockPlacement::Below(range.start),
18522                            height: Some(1),
18523                            render: Arc::new({
18524                                let rename_editor = rename_editor.clone();
18525                                move |cx: &mut BlockContext| {
18526                                    let mut text_style = cx.editor_style.text.clone();
18527                                    if let Some(highlight_style) = old_highlight_id
18528                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18529                                    {
18530                                        text_style = text_style.highlight(highlight_style);
18531                                    }
18532                                    div()
18533                                        .block_mouse_except_scroll()
18534                                        .pl(cx.anchor_x)
18535                                        .child(EditorElement::new(
18536                                            &rename_editor,
18537                                            EditorStyle {
18538                                                background: cx.theme().system().transparent,
18539                                                local_player: cx.editor_style.local_player,
18540                                                text: text_style,
18541                                                scrollbar_width: cx.editor_style.scrollbar_width,
18542                                                syntax: cx.editor_style.syntax.clone(),
18543                                                status: cx.editor_style.status.clone(),
18544                                                inlay_hints_style: HighlightStyle {
18545                                                    font_weight: Some(FontWeight::BOLD),
18546                                                    ..make_inlay_hints_style(cx.app)
18547                                                },
18548                                                edit_prediction_styles: make_suggestion_styles(
18549                                                    cx.app,
18550                                                ),
18551                                                ..EditorStyle::default()
18552                                            },
18553                                        ))
18554                                        .into_any_element()
18555                                }
18556                            }),
18557                            priority: 0,
18558                        }],
18559                        Some(Autoscroll::fit()),
18560                        cx,
18561                    )[0];
18562                    this.pending_rename = Some(RenameState {
18563                        range,
18564                        old_name,
18565                        editor: rename_editor,
18566                        block_id,
18567                    });
18568                })?;
18569            }
18570
18571            Ok(())
18572        }))
18573    }
18574
18575    pub fn confirm_rename(
18576        &mut self,
18577        _: &ConfirmRename,
18578        window: &mut Window,
18579        cx: &mut Context<Self>,
18580    ) -> Option<Task<Result<()>>> {
18581        let rename = self.take_rename(false, window, cx)?;
18582        let workspace = self.workspace()?.downgrade();
18583        let (buffer, start) = self
18584            .buffer
18585            .read(cx)
18586            .text_anchor_for_position(rename.range.start, cx)?;
18587        let (end_buffer, _) = self
18588            .buffer
18589            .read(cx)
18590            .text_anchor_for_position(rename.range.end, cx)?;
18591        if buffer != end_buffer {
18592            return None;
18593        }
18594
18595        let old_name = rename.old_name;
18596        let new_name = rename.editor.read(cx).text(cx);
18597
18598        let rename = self.semantics_provider.as_ref()?.perform_rename(
18599            &buffer,
18600            start,
18601            new_name.clone(),
18602            cx,
18603        )?;
18604
18605        Some(cx.spawn_in(window, async move |editor, cx| {
18606            let project_transaction = rename.await?;
18607            Self::open_project_transaction(
18608                &editor,
18609                workspace,
18610                project_transaction,
18611                format!("Rename: {}{}", old_name, new_name),
18612                cx,
18613            )
18614            .await?;
18615
18616            editor.update(cx, |editor, cx| {
18617                editor.refresh_document_highlights(cx);
18618            })?;
18619            Ok(())
18620        }))
18621    }
18622
18623    fn take_rename(
18624        &mut self,
18625        moving_cursor: bool,
18626        window: &mut Window,
18627        cx: &mut Context<Self>,
18628    ) -> Option<RenameState> {
18629        let rename = self.pending_rename.take()?;
18630        if rename.editor.focus_handle(cx).is_focused(window) {
18631            window.focus(&self.focus_handle, cx);
18632        }
18633
18634        self.remove_blocks(
18635            [rename.block_id].into_iter().collect(),
18636            Some(Autoscroll::fit()),
18637            cx,
18638        );
18639        self.clear_highlights::<Rename>(cx);
18640        self.show_local_selections = true;
18641
18642        if moving_cursor {
18643            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18644                editor
18645                    .selections
18646                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18647                    .head()
18648            });
18649
18650            // Update the selection to match the position of the selection inside
18651            // the rename editor.
18652            let snapshot = self.buffer.read(cx).read(cx);
18653            let rename_range = rename.range.to_offset(&snapshot);
18654            let cursor_in_editor = snapshot
18655                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18656                .min(rename_range.end);
18657            drop(snapshot);
18658
18659            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18660                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18661            });
18662        } else {
18663            self.refresh_document_highlights(cx);
18664        }
18665
18666        Some(rename)
18667    }
18668
18669    pub fn pending_rename(&self) -> Option<&RenameState> {
18670        self.pending_rename.as_ref()
18671    }
18672
18673    fn format(
18674        &mut self,
18675        _: &Format,
18676        window: &mut Window,
18677        cx: &mut Context<Self>,
18678    ) -> Option<Task<Result<()>>> {
18679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18680
18681        let project = match &self.project {
18682            Some(project) => project.clone(),
18683            None => return None,
18684        };
18685
18686        Some(self.perform_format(
18687            project,
18688            FormatTrigger::Manual,
18689            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18690            window,
18691            cx,
18692        ))
18693    }
18694
18695    fn format_selections(
18696        &mut self,
18697        _: &FormatSelections,
18698        window: &mut Window,
18699        cx: &mut Context<Self>,
18700    ) -> Option<Task<Result<()>>> {
18701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18702
18703        let project = match &self.project {
18704            Some(project) => project.clone(),
18705            None => return None,
18706        };
18707
18708        let ranges = self
18709            .selections
18710            .all_adjusted(&self.display_snapshot(cx))
18711            .into_iter()
18712            .map(|selection| selection.range())
18713            .collect_vec();
18714
18715        Some(self.perform_format(
18716            project,
18717            FormatTrigger::Manual,
18718            FormatTarget::Ranges(ranges),
18719            window,
18720            cx,
18721        ))
18722    }
18723
18724    fn perform_format(
18725        &mut self,
18726        project: Entity<Project>,
18727        trigger: FormatTrigger,
18728        target: FormatTarget,
18729        window: &mut Window,
18730        cx: &mut Context<Self>,
18731    ) -> Task<Result<()>> {
18732        let buffer = self.buffer.clone();
18733        let (buffers, target) = match target {
18734            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18735            FormatTarget::Ranges(selection_ranges) => {
18736                let multi_buffer = buffer.read(cx);
18737                let snapshot = multi_buffer.read(cx);
18738                let mut buffers = HashSet::default();
18739                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18740                    BTreeMap::new();
18741                for selection_range in selection_ranges {
18742                    for (buffer, buffer_range, _) in
18743                        snapshot.range_to_buffer_ranges(selection_range)
18744                    {
18745                        let buffer_id = buffer.remote_id();
18746                        let start = buffer.anchor_before(buffer_range.start);
18747                        let end = buffer.anchor_after(buffer_range.end);
18748                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18749                        buffer_id_to_ranges
18750                            .entry(buffer_id)
18751                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18752                            .or_insert_with(|| vec![start..end]);
18753                    }
18754                }
18755                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18756            }
18757        };
18758
18759        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18760        let selections_prev = transaction_id_prev
18761            .and_then(|transaction_id_prev| {
18762                // default to selections as they were after the last edit, if we have them,
18763                // instead of how they are now.
18764                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18765                // will take you back to where you made the last edit, instead of staying where you scrolled
18766                self.selection_history
18767                    .transaction(transaction_id_prev)
18768                    .map(|t| t.0.clone())
18769            })
18770            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18771
18772        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18773        let format = project.update(cx, |project, cx| {
18774            project.format(buffers, target, true, trigger, cx)
18775        });
18776
18777        cx.spawn_in(window, async move |editor, cx| {
18778            let transaction = futures::select_biased! {
18779                transaction = format.log_err().fuse() => transaction,
18780                () = timeout => {
18781                    log::warn!("timed out waiting for formatting");
18782                    None
18783                }
18784            };
18785
18786            buffer.update(cx, |buffer, cx| {
18787                if let Some(transaction) = transaction
18788                    && !buffer.is_singleton()
18789                {
18790                    buffer.push_transaction(&transaction.0, cx);
18791                }
18792                cx.notify();
18793            });
18794
18795            if let Some(transaction_id_now) =
18796                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18797            {
18798                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18799                if has_new_transaction {
18800                    editor
18801                        .update(cx, |editor, _| {
18802                            editor
18803                                .selection_history
18804                                .insert_transaction(transaction_id_now, selections_prev);
18805                        })
18806                        .ok();
18807                }
18808            }
18809
18810            Ok(())
18811        })
18812    }
18813
18814    fn organize_imports(
18815        &mut self,
18816        _: &OrganizeImports,
18817        window: &mut Window,
18818        cx: &mut Context<Self>,
18819    ) -> Option<Task<Result<()>>> {
18820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18821        let project = match &self.project {
18822            Some(project) => project.clone(),
18823            None => return None,
18824        };
18825        Some(self.perform_code_action_kind(
18826            project,
18827            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18828            window,
18829            cx,
18830        ))
18831    }
18832
18833    fn perform_code_action_kind(
18834        &mut self,
18835        project: Entity<Project>,
18836        kind: CodeActionKind,
18837        window: &mut Window,
18838        cx: &mut Context<Self>,
18839    ) -> Task<Result<()>> {
18840        let buffer = self.buffer.clone();
18841        let buffers = buffer.read(cx).all_buffers();
18842        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18843        let apply_action = project.update(cx, |project, cx| {
18844            project.apply_code_action_kind(buffers, kind, true, cx)
18845        });
18846        cx.spawn_in(window, async move |_, cx| {
18847            let transaction = futures::select_biased! {
18848                () = timeout => {
18849                    log::warn!("timed out waiting for executing code action");
18850                    None
18851                }
18852                transaction = apply_action.log_err().fuse() => transaction,
18853            };
18854            buffer.update(cx, |buffer, cx| {
18855                // check if we need this
18856                if let Some(transaction) = transaction
18857                    && !buffer.is_singleton()
18858                {
18859                    buffer.push_transaction(&transaction.0, cx);
18860                }
18861                cx.notify();
18862            });
18863            Ok(())
18864        })
18865    }
18866
18867    pub fn restart_language_server(
18868        &mut self,
18869        _: &RestartLanguageServer,
18870        _: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) {
18873        if let Some(project) = self.project.clone() {
18874            self.buffer.update(cx, |multi_buffer, cx| {
18875                project.update(cx, |project, cx| {
18876                    project.restart_language_servers_for_buffers(
18877                        multi_buffer.all_buffers().into_iter().collect(),
18878                        HashSet::default(),
18879                        cx,
18880                    );
18881                });
18882            })
18883        }
18884    }
18885
18886    pub fn stop_language_server(
18887        &mut self,
18888        _: &StopLanguageServer,
18889        _: &mut Window,
18890        cx: &mut Context<Self>,
18891    ) {
18892        if let Some(project) = self.project.clone() {
18893            self.buffer.update(cx, |multi_buffer, cx| {
18894                project.update(cx, |project, cx| {
18895                    project.stop_language_servers_for_buffers(
18896                        multi_buffer.all_buffers().into_iter().collect(),
18897                        HashSet::default(),
18898                        cx,
18899                    );
18900                });
18901            });
18902            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18903        }
18904    }
18905
18906    fn cancel_language_server_work(
18907        workspace: &mut Workspace,
18908        _: &actions::CancelLanguageServerWork,
18909        _: &mut Window,
18910        cx: &mut Context<Workspace>,
18911    ) {
18912        let project = workspace.project();
18913        let buffers = workspace
18914            .active_item(cx)
18915            .and_then(|item| item.act_as::<Editor>(cx))
18916            .map_or(HashSet::default(), |editor| {
18917                editor.read(cx).buffer.read(cx).all_buffers()
18918            });
18919        project.update(cx, |project, cx| {
18920            project.cancel_language_server_work_for_buffers(buffers, cx);
18921        });
18922    }
18923
18924    fn show_character_palette(
18925        &mut self,
18926        _: &ShowCharacterPalette,
18927        window: &mut Window,
18928        _: &mut Context<Self>,
18929    ) {
18930        window.show_character_palette();
18931    }
18932
18933    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18934        if !self.diagnostics_enabled() {
18935            return;
18936        }
18937
18938        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18939            let buffer = self.buffer.read(cx).snapshot(cx);
18940            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18941            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18942            let is_valid = buffer
18943                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18944                .any(|entry| {
18945                    entry.diagnostic.is_primary
18946                        && !entry.range.is_empty()
18947                        && entry.range.start == primary_range_start
18948                        && entry.diagnostic.message == active_diagnostics.active_message
18949                });
18950
18951            if !is_valid {
18952                self.dismiss_diagnostics(cx);
18953            }
18954        }
18955    }
18956
18957    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18958        match &self.active_diagnostics {
18959            ActiveDiagnostic::Group(group) => Some(group),
18960            _ => None,
18961        }
18962    }
18963
18964    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18965        if !self.diagnostics_enabled() {
18966            return;
18967        }
18968        self.dismiss_diagnostics(cx);
18969        self.active_diagnostics = ActiveDiagnostic::All;
18970    }
18971
18972    fn activate_diagnostics(
18973        &mut self,
18974        buffer_id: BufferId,
18975        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18976        window: &mut Window,
18977        cx: &mut Context<Self>,
18978    ) {
18979        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18980            return;
18981        }
18982        self.dismiss_diagnostics(cx);
18983        let snapshot = self.snapshot(window, cx);
18984        let buffer = self.buffer.read(cx).snapshot(cx);
18985        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18986            return;
18987        };
18988
18989        let diagnostic_group = buffer
18990            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18991            .collect::<Vec<_>>();
18992
18993        let language_registry = self
18994            .project()
18995            .map(|project| project.read(cx).languages().clone());
18996
18997        let blocks = renderer.render_group(
18998            diagnostic_group,
18999            buffer_id,
19000            snapshot,
19001            cx.weak_entity(),
19002            language_registry,
19003            cx,
19004        );
19005
19006        let blocks = self.display_map.update(cx, |display_map, cx| {
19007            display_map.insert_blocks(blocks, cx).into_iter().collect()
19008        });
19009        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19010            active_range: buffer.anchor_before(diagnostic.range.start)
19011                ..buffer.anchor_after(diagnostic.range.end),
19012            active_message: diagnostic.diagnostic.message.clone(),
19013            group_id: diagnostic.diagnostic.group_id,
19014            blocks,
19015        });
19016        cx.notify();
19017    }
19018
19019    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19020        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19021            return;
19022        };
19023
19024        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19025        if let ActiveDiagnostic::Group(group) = prev {
19026            self.display_map.update(cx, |display_map, cx| {
19027                display_map.remove_blocks(group.blocks, cx);
19028            });
19029            cx.notify();
19030        }
19031    }
19032
19033    /// Disable inline diagnostics rendering for this editor.
19034    pub fn disable_inline_diagnostics(&mut self) {
19035        self.inline_diagnostics_enabled = false;
19036        self.inline_diagnostics_update = Task::ready(());
19037        self.inline_diagnostics.clear();
19038    }
19039
19040    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19041        self.diagnostics_enabled = false;
19042        self.dismiss_diagnostics(cx);
19043        self.inline_diagnostics_update = Task::ready(());
19044        self.inline_diagnostics.clear();
19045    }
19046
19047    pub fn disable_word_completions(&mut self) {
19048        self.word_completions_enabled = false;
19049    }
19050
19051    pub fn diagnostics_enabled(&self) -> bool {
19052        self.diagnostics_enabled && self.mode.is_full()
19053    }
19054
19055    pub fn inline_diagnostics_enabled(&self) -> bool {
19056        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19057    }
19058
19059    pub fn show_inline_diagnostics(&self) -> bool {
19060        self.show_inline_diagnostics
19061    }
19062
19063    pub fn toggle_inline_diagnostics(
19064        &mut self,
19065        _: &ToggleInlineDiagnostics,
19066        window: &mut Window,
19067        cx: &mut Context<Editor>,
19068    ) {
19069        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19070        self.refresh_inline_diagnostics(false, window, cx);
19071    }
19072
19073    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19074        self.diagnostics_max_severity = severity;
19075        self.display_map.update(cx, |display_map, _| {
19076            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19077        });
19078    }
19079
19080    pub fn toggle_diagnostics(
19081        &mut self,
19082        _: &ToggleDiagnostics,
19083        window: &mut Window,
19084        cx: &mut Context<Editor>,
19085    ) {
19086        if !self.diagnostics_enabled() {
19087            return;
19088        }
19089
19090        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19091            EditorSettings::get_global(cx)
19092                .diagnostics_max_severity
19093                .filter(|severity| severity != &DiagnosticSeverity::Off)
19094                .unwrap_or(DiagnosticSeverity::Hint)
19095        } else {
19096            DiagnosticSeverity::Off
19097        };
19098        self.set_max_diagnostics_severity(new_severity, cx);
19099        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19100            self.active_diagnostics = ActiveDiagnostic::None;
19101            self.inline_diagnostics_update = Task::ready(());
19102            self.inline_diagnostics.clear();
19103        } else {
19104            self.refresh_inline_diagnostics(false, window, cx);
19105        }
19106
19107        cx.notify();
19108    }
19109
19110    pub fn toggle_minimap(
19111        &mut self,
19112        _: &ToggleMinimap,
19113        window: &mut Window,
19114        cx: &mut Context<Editor>,
19115    ) {
19116        if self.supports_minimap(cx) {
19117            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19118        }
19119    }
19120
19121    fn refresh_inline_diagnostics(
19122        &mut self,
19123        debounce: bool,
19124        window: &mut Window,
19125        cx: &mut Context<Self>,
19126    ) {
19127        let max_severity = ProjectSettings::get_global(cx)
19128            .diagnostics
19129            .inline
19130            .max_severity
19131            .unwrap_or(self.diagnostics_max_severity);
19132
19133        if !self.inline_diagnostics_enabled()
19134            || !self.diagnostics_enabled()
19135            || !self.show_inline_diagnostics
19136            || max_severity == DiagnosticSeverity::Off
19137        {
19138            self.inline_diagnostics_update = Task::ready(());
19139            self.inline_diagnostics.clear();
19140            return;
19141        }
19142
19143        let debounce_ms = ProjectSettings::get_global(cx)
19144            .diagnostics
19145            .inline
19146            .update_debounce_ms;
19147        let debounce = if debounce && debounce_ms > 0 {
19148            Some(Duration::from_millis(debounce_ms))
19149        } else {
19150            None
19151        };
19152        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19153            if let Some(debounce) = debounce {
19154                cx.background_executor().timer(debounce).await;
19155            }
19156            let Some(snapshot) = editor.upgrade().map(|editor| {
19157                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19158            }) else {
19159                return;
19160            };
19161
19162            let new_inline_diagnostics = cx
19163                .background_spawn(async move {
19164                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19165                    for diagnostic_entry in
19166                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19167                    {
19168                        let message = diagnostic_entry
19169                            .diagnostic
19170                            .message
19171                            .split_once('\n')
19172                            .map(|(line, _)| line)
19173                            .map(SharedString::new)
19174                            .unwrap_or_else(|| {
19175                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19176                            });
19177                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19178                        let (Ok(i) | Err(i)) = inline_diagnostics
19179                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19180                        inline_diagnostics.insert(
19181                            i,
19182                            (
19183                                start_anchor,
19184                                InlineDiagnostic {
19185                                    message,
19186                                    group_id: diagnostic_entry.diagnostic.group_id,
19187                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19188                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19189                                    severity: diagnostic_entry.diagnostic.severity,
19190                                },
19191                            ),
19192                        );
19193                    }
19194                    inline_diagnostics
19195                })
19196                .await;
19197
19198            editor
19199                .update(cx, |editor, cx| {
19200                    editor.inline_diagnostics = new_inline_diagnostics;
19201                    cx.notify();
19202                })
19203                .ok();
19204        });
19205    }
19206
19207    fn pull_diagnostics(
19208        &mut self,
19209        buffer_id: Option<BufferId>,
19210        window: &Window,
19211        cx: &mut Context<Self>,
19212    ) -> Option<()> {
19213        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
19214            return None;
19215        }
19216        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19217            .diagnostics
19218            .lsp_pull_diagnostics;
19219        if !pull_diagnostics_settings.enabled {
19220            return None;
19221        }
19222        let project = self.project()?.downgrade();
19223
19224        let mut edited_buffer_ids = HashSet::default();
19225        let mut edited_worktree_ids = HashSet::default();
19226        let edited_buffers = match buffer_id {
19227            Some(buffer_id) => {
19228                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19229                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
19230                edited_buffer_ids.insert(buffer.read(cx).remote_id());
19231                edited_worktree_ids.insert(worktree_id);
19232                vec![buffer]
19233            }
19234            None => self
19235                .buffer()
19236                .read(cx)
19237                .all_buffers()
19238                .into_iter()
19239                .filter(|buffer| {
19240                    let buffer = buffer.read(cx);
19241                    match buffer.file().map(|f| f.worktree_id(cx)) {
19242                        Some(worktree_id) => {
19243                            edited_buffer_ids.insert(buffer.remote_id());
19244                            edited_worktree_ids.insert(worktree_id);
19245                            true
19246                        }
19247                        None => false,
19248                    }
19249                })
19250                .collect::<Vec<_>>(),
19251        };
19252
19253        if edited_buffers.is_empty() {
19254            self.pull_diagnostics_task = Task::ready(());
19255            self.pull_diagnostics_background_task = Task::ready(());
19256            return None;
19257        }
19258
19259        let mut already_used_buffers = HashSet::default();
19260        let related_open_buffers = self
19261            .workspace
19262            .as_ref()
19263            .and_then(|(workspace, _)| workspace.upgrade())
19264            .into_iter()
19265            .flat_map(|workspace| workspace.read(cx).panes())
19266            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
19267            .filter(|editor| editor != &cx.entity())
19268            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
19269            .filter(|buffer| {
19270                let buffer = buffer.read(cx);
19271                let buffer_id = buffer.remote_id();
19272                if already_used_buffers.insert(buffer_id) {
19273                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
19274                        return !edited_buffer_ids.contains(&buffer_id)
19275                            && edited_worktree_ids.contains(&worktree_id);
19276                    }
19277                }
19278                false
19279            })
19280            .collect::<Vec<_>>();
19281
19282        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19283        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
19284            if buffers.is_empty() {
19285                return Task::ready(());
19286            }
19287            let project_weak = project.clone();
19288            cx.spawn_in(window, async move |_, cx| {
19289                cx.background_executor().timer(delay).await;
19290
19291                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
19292                    buffers
19293                        .into_iter()
19294                        .filter_map(|buffer| {
19295                            project_weak
19296                                .update(cx, |project, cx| {
19297                                    project.lsp_store().update(cx, |lsp_store, cx| {
19298                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19299                                    })
19300                                })
19301                                .ok()
19302                        })
19303                        .collect::<FuturesUnordered<_>>()
19304                }) else {
19305                    return;
19306                };
19307
19308                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
19309                    if let Err(e) = pull_task {
19310                        log::error!("Failed to update project diagnostics: {e:#}");
19311                    }
19312                }
19313            })
19314        };
19315
19316        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
19317        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
19318
19319        Some(())
19320    }
19321
19322    pub fn set_selections_from_remote(
19323        &mut self,
19324        selections: Vec<Selection<Anchor>>,
19325        pending_selection: Option<Selection<Anchor>>,
19326        window: &mut Window,
19327        cx: &mut Context<Self>,
19328    ) {
19329        let old_cursor_position = self.selections.newest_anchor().head();
19330        self.selections
19331            .change_with(&self.display_snapshot(cx), |s| {
19332                s.select_anchors(selections);
19333                if let Some(pending_selection) = pending_selection {
19334                    s.set_pending(pending_selection, SelectMode::Character);
19335                } else {
19336                    s.clear_pending();
19337                }
19338            });
19339        self.selections_did_change(
19340            false,
19341            &old_cursor_position,
19342            SelectionEffects::default(),
19343            window,
19344            cx,
19345        );
19346    }
19347
19348    pub fn transact(
19349        &mut self,
19350        window: &mut Window,
19351        cx: &mut Context<Self>,
19352        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19353    ) -> Option<TransactionId> {
19354        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19355            this.start_transaction_at(Instant::now(), window, cx);
19356            update(this, window, cx);
19357            this.end_transaction_at(Instant::now(), cx)
19358        })
19359    }
19360
19361    pub fn start_transaction_at(
19362        &mut self,
19363        now: Instant,
19364        window: &mut Window,
19365        cx: &mut Context<Self>,
19366    ) -> Option<TransactionId> {
19367        self.end_selection(window, cx);
19368        if let Some(tx_id) = self
19369            .buffer
19370            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19371        {
19372            self.selection_history
19373                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19374            cx.emit(EditorEvent::TransactionBegun {
19375                transaction_id: tx_id,
19376            });
19377            Some(tx_id)
19378        } else {
19379            None
19380        }
19381    }
19382
19383    pub fn end_transaction_at(
19384        &mut self,
19385        now: Instant,
19386        cx: &mut Context<Self>,
19387    ) -> Option<TransactionId> {
19388        if let Some(transaction_id) = self
19389            .buffer
19390            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19391        {
19392            if let Some((_, end_selections)) =
19393                self.selection_history.transaction_mut(transaction_id)
19394            {
19395                *end_selections = Some(self.selections.disjoint_anchors_arc());
19396            } else {
19397                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19398            }
19399
19400            cx.emit(EditorEvent::Edited { transaction_id });
19401            Some(transaction_id)
19402        } else {
19403            None
19404        }
19405    }
19406
19407    pub fn modify_transaction_selection_history(
19408        &mut self,
19409        transaction_id: TransactionId,
19410        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19411    ) -> bool {
19412        self.selection_history
19413            .transaction_mut(transaction_id)
19414            .map(modify)
19415            .is_some()
19416    }
19417
19418    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19419        if self.selection_mark_mode {
19420            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19421                s.move_with(|_, sel| {
19422                    sel.collapse_to(sel.head(), SelectionGoal::None);
19423                });
19424            })
19425        }
19426        self.selection_mark_mode = true;
19427        cx.notify();
19428    }
19429
19430    pub fn swap_selection_ends(
19431        &mut self,
19432        _: &actions::SwapSelectionEnds,
19433        window: &mut Window,
19434        cx: &mut Context<Self>,
19435    ) {
19436        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19437            s.move_with(|_, sel| {
19438                if sel.start != sel.end {
19439                    sel.reversed = !sel.reversed
19440                }
19441            });
19442        });
19443        self.request_autoscroll(Autoscroll::newest(), cx);
19444        cx.notify();
19445    }
19446
19447    pub fn toggle_focus(
19448        workspace: &mut Workspace,
19449        _: &actions::ToggleFocus,
19450        window: &mut Window,
19451        cx: &mut Context<Workspace>,
19452    ) {
19453        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19454            return;
19455        };
19456        workspace.activate_item(&item, true, true, window, cx);
19457    }
19458
19459    pub fn toggle_fold(
19460        &mut self,
19461        _: &actions::ToggleFold,
19462        window: &mut Window,
19463        cx: &mut Context<Self>,
19464    ) {
19465        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19466            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19467            let selection = self.selections.newest::<Point>(&display_map);
19468
19469            let range = if selection.is_empty() {
19470                let point = selection.head().to_display_point(&display_map);
19471                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19472                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19473                    .to_point(&display_map);
19474                start..end
19475            } else {
19476                selection.range()
19477            };
19478            if display_map.folds_in_range(range).next().is_some() {
19479                self.unfold_lines(&Default::default(), window, cx)
19480            } else {
19481                self.fold(&Default::default(), window, cx)
19482            }
19483        } else {
19484            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19485            let buffer_ids: HashSet<_> = self
19486                .selections
19487                .disjoint_anchor_ranges()
19488                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19489                .collect();
19490
19491            let should_unfold = buffer_ids
19492                .iter()
19493                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19494
19495            for buffer_id in buffer_ids {
19496                if should_unfold {
19497                    self.unfold_buffer(buffer_id, cx);
19498                } else {
19499                    self.fold_buffer(buffer_id, cx);
19500                }
19501            }
19502        }
19503    }
19504
19505    pub fn toggle_fold_recursive(
19506        &mut self,
19507        _: &actions::ToggleFoldRecursive,
19508        window: &mut Window,
19509        cx: &mut Context<Self>,
19510    ) {
19511        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19512
19513        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19514        let range = if selection.is_empty() {
19515            let point = selection.head().to_display_point(&display_map);
19516            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19517            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19518                .to_point(&display_map);
19519            start..end
19520        } else {
19521            selection.range()
19522        };
19523        if display_map.folds_in_range(range).next().is_some() {
19524            self.unfold_recursive(&Default::default(), window, cx)
19525        } else {
19526            self.fold_recursive(&Default::default(), window, cx)
19527        }
19528    }
19529
19530    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19531        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19532            let mut to_fold = Vec::new();
19533            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19534            let selections = self.selections.all_adjusted(&display_map);
19535
19536            for selection in selections {
19537                let range = selection.range().sorted();
19538                let buffer_start_row = range.start.row;
19539
19540                if range.start.row != range.end.row {
19541                    let mut found = false;
19542                    let mut row = range.start.row;
19543                    while row <= range.end.row {
19544                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19545                        {
19546                            found = true;
19547                            row = crease.range().end.row + 1;
19548                            to_fold.push(crease);
19549                        } else {
19550                            row += 1
19551                        }
19552                    }
19553                    if found {
19554                        continue;
19555                    }
19556                }
19557
19558                for row in (0..=range.start.row).rev() {
19559                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19560                        && crease.range().end.row >= buffer_start_row
19561                    {
19562                        to_fold.push(crease);
19563                        if row <= range.start.row {
19564                            break;
19565                        }
19566                    }
19567                }
19568            }
19569
19570            self.fold_creases(to_fold, true, window, cx);
19571        } else {
19572            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19573            let buffer_ids = self
19574                .selections
19575                .disjoint_anchor_ranges()
19576                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19577                .collect::<HashSet<_>>();
19578            for buffer_id in buffer_ids {
19579                self.fold_buffer(buffer_id, cx);
19580            }
19581        }
19582    }
19583
19584    pub fn toggle_fold_all(
19585        &mut self,
19586        _: &actions::ToggleFoldAll,
19587        window: &mut Window,
19588        cx: &mut Context<Self>,
19589    ) {
19590        let has_folds = if self.buffer.read(cx).is_singleton() {
19591            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19592            let has_folds = display_map
19593                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19594                .next()
19595                .is_some();
19596            has_folds
19597        } else {
19598            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19599            let has_folds = buffer_ids
19600                .iter()
19601                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19602            has_folds
19603        };
19604
19605        if has_folds {
19606            self.unfold_all(&actions::UnfoldAll, window, cx);
19607        } else {
19608            self.fold_all(&actions::FoldAll, window, cx);
19609        }
19610    }
19611
19612    fn fold_at_level(
19613        &mut self,
19614        fold_at: &FoldAtLevel,
19615        window: &mut Window,
19616        cx: &mut Context<Self>,
19617    ) {
19618        if !self.buffer.read(cx).is_singleton() {
19619            return;
19620        }
19621
19622        let fold_at_level = fold_at.0;
19623        let snapshot = self.buffer.read(cx).snapshot(cx);
19624        let mut to_fold = Vec::new();
19625        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19626
19627        let row_ranges_to_keep: Vec<Range<u32>> = self
19628            .selections
19629            .all::<Point>(&self.display_snapshot(cx))
19630            .into_iter()
19631            .map(|sel| sel.start.row..sel.end.row)
19632            .collect();
19633
19634        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19635            while start_row < end_row {
19636                match self
19637                    .snapshot(window, cx)
19638                    .crease_for_buffer_row(MultiBufferRow(start_row))
19639                {
19640                    Some(crease) => {
19641                        let nested_start_row = crease.range().start.row + 1;
19642                        let nested_end_row = crease.range().end.row;
19643
19644                        if current_level < fold_at_level {
19645                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19646                        } else if current_level == fold_at_level {
19647                            // Fold iff there is no selection completely contained within the fold region
19648                            if !row_ranges_to_keep.iter().any(|selection| {
19649                                selection.end >= nested_start_row
19650                                    && selection.start <= nested_end_row
19651                            }) {
19652                                to_fold.push(crease);
19653                            }
19654                        }
19655
19656                        start_row = nested_end_row + 1;
19657                    }
19658                    None => start_row += 1,
19659                }
19660            }
19661        }
19662
19663        self.fold_creases(to_fold, true, window, cx);
19664    }
19665
19666    pub fn fold_at_level_1(
19667        &mut self,
19668        _: &actions::FoldAtLevel1,
19669        window: &mut Window,
19670        cx: &mut Context<Self>,
19671    ) {
19672        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19673    }
19674
19675    pub fn fold_at_level_2(
19676        &mut self,
19677        _: &actions::FoldAtLevel2,
19678        window: &mut Window,
19679        cx: &mut Context<Self>,
19680    ) {
19681        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19682    }
19683
19684    pub fn fold_at_level_3(
19685        &mut self,
19686        _: &actions::FoldAtLevel3,
19687        window: &mut Window,
19688        cx: &mut Context<Self>,
19689    ) {
19690        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19691    }
19692
19693    pub fn fold_at_level_4(
19694        &mut self,
19695        _: &actions::FoldAtLevel4,
19696        window: &mut Window,
19697        cx: &mut Context<Self>,
19698    ) {
19699        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19700    }
19701
19702    pub fn fold_at_level_5(
19703        &mut self,
19704        _: &actions::FoldAtLevel5,
19705        window: &mut Window,
19706        cx: &mut Context<Self>,
19707    ) {
19708        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19709    }
19710
19711    pub fn fold_at_level_6(
19712        &mut self,
19713        _: &actions::FoldAtLevel6,
19714        window: &mut Window,
19715        cx: &mut Context<Self>,
19716    ) {
19717        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19718    }
19719
19720    pub fn fold_at_level_7(
19721        &mut self,
19722        _: &actions::FoldAtLevel7,
19723        window: &mut Window,
19724        cx: &mut Context<Self>,
19725    ) {
19726        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19727    }
19728
19729    pub fn fold_at_level_8(
19730        &mut self,
19731        _: &actions::FoldAtLevel8,
19732        window: &mut Window,
19733        cx: &mut Context<Self>,
19734    ) {
19735        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19736    }
19737
19738    pub fn fold_at_level_9(
19739        &mut self,
19740        _: &actions::FoldAtLevel9,
19741        window: &mut Window,
19742        cx: &mut Context<Self>,
19743    ) {
19744        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19745    }
19746
19747    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19748        if self.buffer.read(cx).is_singleton() {
19749            let mut fold_ranges = Vec::new();
19750            let snapshot = self.buffer.read(cx).snapshot(cx);
19751
19752            for row in 0..snapshot.max_row().0 {
19753                if let Some(foldable_range) = self
19754                    .snapshot(window, cx)
19755                    .crease_for_buffer_row(MultiBufferRow(row))
19756                {
19757                    fold_ranges.push(foldable_range);
19758                }
19759            }
19760
19761            self.fold_creases(fold_ranges, true, window, cx);
19762        } else {
19763            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19764                editor
19765                    .update_in(cx, |editor, _, cx| {
19766                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19767                            editor.fold_buffer(buffer_id, cx);
19768                        }
19769                    })
19770                    .ok();
19771            });
19772        }
19773        cx.emit(SearchEvent::ResultsCollapsedChanged(
19774            CollapseDirection::Collapsed,
19775        ));
19776    }
19777
19778    pub fn fold_function_bodies(
19779        &mut self,
19780        _: &actions::FoldFunctionBodies,
19781        window: &mut Window,
19782        cx: &mut Context<Self>,
19783    ) {
19784        let snapshot = self.buffer.read(cx).snapshot(cx);
19785
19786        let ranges = snapshot
19787            .text_object_ranges(
19788                MultiBufferOffset(0)..snapshot.len(),
19789                TreeSitterOptions::default(),
19790            )
19791            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19792            .collect::<Vec<_>>();
19793
19794        let creases = ranges
19795            .into_iter()
19796            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19797            .collect();
19798
19799        self.fold_creases(creases, true, window, cx);
19800    }
19801
19802    pub fn fold_recursive(
19803        &mut self,
19804        _: &actions::FoldRecursive,
19805        window: &mut Window,
19806        cx: &mut Context<Self>,
19807    ) {
19808        let mut to_fold = Vec::new();
19809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19810        let selections = self.selections.all_adjusted(&display_map);
19811
19812        for selection in selections {
19813            let range = selection.range().sorted();
19814            let buffer_start_row = range.start.row;
19815
19816            if range.start.row != range.end.row {
19817                let mut found = false;
19818                for row in range.start.row..=range.end.row {
19819                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19820                        found = true;
19821                        to_fold.push(crease);
19822                    }
19823                }
19824                if found {
19825                    continue;
19826                }
19827            }
19828
19829            for row in (0..=range.start.row).rev() {
19830                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19831                    if crease.range().end.row >= buffer_start_row {
19832                        to_fold.push(crease);
19833                    } else {
19834                        break;
19835                    }
19836                }
19837            }
19838        }
19839
19840        self.fold_creases(to_fold, true, window, cx);
19841    }
19842
19843    pub fn fold_at(
19844        &mut self,
19845        buffer_row: MultiBufferRow,
19846        window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19850
19851        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19852            let autoscroll = self
19853                .selections
19854                .all::<Point>(&display_map)
19855                .iter()
19856                .any(|selection| crease.range().overlaps(&selection.range()));
19857
19858            self.fold_creases(vec![crease], autoscroll, window, cx);
19859        }
19860    }
19861
19862    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19863        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19864            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19865            let buffer = display_map.buffer_snapshot();
19866            let selections = self.selections.all::<Point>(&display_map);
19867            let ranges = selections
19868                .iter()
19869                .map(|s| {
19870                    let range = s.display_range(&display_map).sorted();
19871                    let mut start = range.start.to_point(&display_map);
19872                    let mut end = range.end.to_point(&display_map);
19873                    start.column = 0;
19874                    end.column = buffer.line_len(MultiBufferRow(end.row));
19875                    start..end
19876                })
19877                .collect::<Vec<_>>();
19878
19879            self.unfold_ranges(&ranges, true, true, cx);
19880        } else {
19881            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19882            let buffer_ids = self
19883                .selections
19884                .disjoint_anchor_ranges()
19885                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19886                .collect::<HashSet<_>>();
19887            for buffer_id in buffer_ids {
19888                self.unfold_buffer(buffer_id, cx);
19889            }
19890        }
19891    }
19892
19893    pub fn unfold_recursive(
19894        &mut self,
19895        _: &UnfoldRecursive,
19896        _window: &mut Window,
19897        cx: &mut Context<Self>,
19898    ) {
19899        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19900        let selections = self.selections.all::<Point>(&display_map);
19901        let ranges = selections
19902            .iter()
19903            .map(|s| {
19904                let mut range = s.display_range(&display_map).sorted();
19905                *range.start.column_mut() = 0;
19906                *range.end.column_mut() = display_map.line_len(range.end.row());
19907                let start = range.start.to_point(&display_map);
19908                let end = range.end.to_point(&display_map);
19909                start..end
19910            })
19911            .collect::<Vec<_>>();
19912
19913        self.unfold_ranges(&ranges, true, true, cx);
19914    }
19915
19916    pub fn unfold_at(
19917        &mut self,
19918        buffer_row: MultiBufferRow,
19919        _window: &mut Window,
19920        cx: &mut Context<Self>,
19921    ) {
19922        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19923
19924        let intersection_range = Point::new(buffer_row.0, 0)
19925            ..Point::new(
19926                buffer_row.0,
19927                display_map.buffer_snapshot().line_len(buffer_row),
19928            );
19929
19930        let autoscroll = self
19931            .selections
19932            .all::<Point>(&display_map)
19933            .iter()
19934            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19935
19936        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19937    }
19938
19939    pub fn unfold_all(
19940        &mut self,
19941        _: &actions::UnfoldAll,
19942        _window: &mut Window,
19943        cx: &mut Context<Self>,
19944    ) {
19945        if self.buffer.read(cx).is_singleton() {
19946            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19947            self.unfold_ranges(
19948                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19949                true,
19950                true,
19951                cx,
19952            );
19953        } else {
19954            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19955                editor
19956                    .update(cx, |editor, cx| {
19957                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19958                            editor.unfold_buffer(buffer_id, cx);
19959                        }
19960                    })
19961                    .ok();
19962            });
19963        }
19964        cx.emit(SearchEvent::ResultsCollapsedChanged(
19965            CollapseDirection::Expanded,
19966        ));
19967    }
19968
19969    pub fn fold_selected_ranges(
19970        &mut self,
19971        _: &FoldSelectedRanges,
19972        window: &mut Window,
19973        cx: &mut Context<Self>,
19974    ) {
19975        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19976        let selections = self.selections.all_adjusted(&display_map);
19977        let ranges = selections
19978            .into_iter()
19979            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19980            .collect::<Vec<_>>();
19981        self.fold_creases(ranges, true, window, cx);
19982    }
19983
19984    pub fn fold_ranges<T: ToOffset + Clone>(
19985        &mut self,
19986        ranges: Vec<Range<T>>,
19987        auto_scroll: bool,
19988        window: &mut Window,
19989        cx: &mut Context<Self>,
19990    ) {
19991        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19992        let ranges = ranges
19993            .into_iter()
19994            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19995            .collect::<Vec<_>>();
19996        self.fold_creases(ranges, auto_scroll, window, cx);
19997    }
19998
19999    pub fn fold_creases<T: ToOffset + Clone>(
20000        &mut self,
20001        creases: Vec<Crease<T>>,
20002        auto_scroll: bool,
20003        _window: &mut Window,
20004        cx: &mut Context<Self>,
20005    ) {
20006        if creases.is_empty() {
20007            return;
20008        }
20009
20010        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20011
20012        if auto_scroll {
20013            self.request_autoscroll(Autoscroll::fit(), cx);
20014        }
20015
20016        cx.notify();
20017
20018        self.scrollbar_marker_state.dirty = true;
20019        self.folds_did_change(cx);
20020    }
20021
20022    /// Removes any folds whose ranges intersect any of the given ranges.
20023    pub fn unfold_ranges<T: ToOffset + Clone>(
20024        &mut self,
20025        ranges: &[Range<T>],
20026        inclusive: bool,
20027        auto_scroll: bool,
20028        cx: &mut Context<Self>,
20029    ) {
20030        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20031            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
20032        });
20033        self.folds_did_change(cx);
20034    }
20035
20036    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20037        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
20038            return;
20039        }
20040
20041        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20042        self.display_map.update(cx, |display_map, cx| {
20043            display_map.fold_buffers([buffer_id], cx)
20044        });
20045
20046        let snapshot = self.display_snapshot(cx);
20047        self.selections.change_with(&snapshot, |selections| {
20048            selections.remove_selections_from_buffer(buffer_id);
20049        });
20050
20051        cx.emit(EditorEvent::BufferFoldToggled {
20052            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
20053            folded: true,
20054        });
20055        cx.notify();
20056    }
20057
20058    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20059        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20060            return;
20061        }
20062        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20063        self.display_map.update(cx, |display_map, cx| {
20064            display_map.unfold_buffers([buffer_id], cx);
20065        });
20066        cx.emit(EditorEvent::BufferFoldToggled {
20067            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
20068            folded: false,
20069        });
20070        cx.notify();
20071    }
20072
20073    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20074        self.display_map.read(cx).is_buffer_folded(buffer)
20075    }
20076
20077    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20078        self.display_map.read(cx).folded_buffers()
20079    }
20080
20081    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20082        self.display_map.update(cx, |display_map, cx| {
20083            display_map.disable_header_for_buffer(buffer_id, cx);
20084        });
20085        cx.notify();
20086    }
20087
20088    /// Removes any folds with the given ranges.
20089    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20090        &mut self,
20091        ranges: &[Range<T>],
20092        type_id: TypeId,
20093        auto_scroll: bool,
20094        cx: &mut Context<Self>,
20095    ) {
20096        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20097            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20098        });
20099        self.folds_did_change(cx);
20100    }
20101
20102    fn remove_folds_with<T: ToOffset + Clone>(
20103        &mut self,
20104        ranges: &[Range<T>],
20105        auto_scroll: bool,
20106        cx: &mut Context<Self>,
20107        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20108    ) {
20109        if ranges.is_empty() {
20110            return;
20111        }
20112
20113        let mut buffers_affected = HashSet::default();
20114        let multi_buffer = self.buffer().read(cx);
20115        for range in ranges {
20116            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
20117                buffers_affected.insert(buffer.read(cx).remote_id());
20118            };
20119        }
20120
20121        self.display_map.update(cx, update);
20122
20123        if auto_scroll {
20124            self.request_autoscroll(Autoscroll::fit(), cx);
20125        }
20126
20127        cx.notify();
20128        self.scrollbar_marker_state.dirty = true;
20129        self.active_indent_guides_state.dirty = true;
20130    }
20131
20132    pub fn update_renderer_widths(
20133        &mut self,
20134        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20135        cx: &mut Context<Self>,
20136    ) -> bool {
20137        self.display_map
20138            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20139    }
20140
20141    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20142        self.display_map.read(cx).fold_placeholder.clone()
20143    }
20144
20145    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20146        self.buffer.update(cx, |buffer, cx| {
20147            buffer.set_all_diff_hunks_expanded(cx);
20148        });
20149    }
20150
20151    pub fn expand_all_diff_hunks(
20152        &mut self,
20153        _: &ExpandAllDiffHunks,
20154        _window: &mut Window,
20155        cx: &mut Context<Self>,
20156    ) {
20157        self.buffer.update(cx, |buffer, cx| {
20158            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20159        });
20160    }
20161
20162    pub fn collapse_all_diff_hunks(
20163        &mut self,
20164        _: &CollapseAllDiffHunks,
20165        _window: &mut Window,
20166        cx: &mut Context<Self>,
20167    ) {
20168        self.buffer.update(cx, |buffer, cx| {
20169            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20170        });
20171    }
20172
20173    pub fn toggle_selected_diff_hunks(
20174        &mut self,
20175        _: &ToggleSelectedDiffHunks,
20176        _window: &mut Window,
20177        cx: &mut Context<Self>,
20178    ) {
20179        let ranges: Vec<_> = self
20180            .selections
20181            .disjoint_anchors()
20182            .iter()
20183            .map(|s| s.range())
20184            .collect();
20185        self.toggle_diff_hunks_in_ranges(ranges, cx);
20186    }
20187
20188    pub fn diff_hunks_in_ranges<'a>(
20189        &'a self,
20190        ranges: &'a [Range<Anchor>],
20191        buffer: &'a MultiBufferSnapshot,
20192    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20193        ranges.iter().flat_map(move |range| {
20194            let end_excerpt_id = range.end.excerpt_id;
20195            let range = range.to_point(buffer);
20196            let mut peek_end = range.end;
20197            if range.end.row < buffer.max_row().0 {
20198                peek_end = Point::new(range.end.row + 1, 0);
20199            }
20200            buffer
20201                .diff_hunks_in_range(range.start..peek_end)
20202                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20203        })
20204    }
20205
20206    pub fn has_stageable_diff_hunks_in_ranges(
20207        &self,
20208        ranges: &[Range<Anchor>],
20209        snapshot: &MultiBufferSnapshot,
20210    ) -> bool {
20211        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20212        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20213    }
20214
20215    pub fn toggle_staged_selected_diff_hunks(
20216        &mut self,
20217        _: &::git::ToggleStaged,
20218        _: &mut Window,
20219        cx: &mut Context<Self>,
20220    ) {
20221        let snapshot = self.buffer.read(cx).snapshot(cx);
20222        let ranges: Vec<_> = self
20223            .selections
20224            .disjoint_anchors()
20225            .iter()
20226            .map(|s| s.range())
20227            .collect();
20228        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20229        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20230    }
20231
20232    pub fn set_render_diff_hunk_controls(
20233        &mut self,
20234        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20235        cx: &mut Context<Self>,
20236    ) {
20237        self.render_diff_hunk_controls = render_diff_hunk_controls;
20238        cx.notify();
20239    }
20240
20241    pub fn stage_and_next(
20242        &mut self,
20243        _: &::git::StageAndNext,
20244        window: &mut Window,
20245        cx: &mut Context<Self>,
20246    ) {
20247        self.do_stage_or_unstage_and_next(true, window, cx);
20248    }
20249
20250    pub fn unstage_and_next(
20251        &mut self,
20252        _: &::git::UnstageAndNext,
20253        window: &mut Window,
20254        cx: &mut Context<Self>,
20255    ) {
20256        self.do_stage_or_unstage_and_next(false, window, cx);
20257    }
20258
20259    pub fn stage_or_unstage_diff_hunks(
20260        &mut self,
20261        stage: bool,
20262        ranges: Vec<Range<Anchor>>,
20263        cx: &mut Context<Self>,
20264    ) {
20265        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20266        cx.spawn(async move |this, cx| {
20267            task.await?;
20268            this.update(cx, |this, cx| {
20269                let snapshot = this.buffer.read(cx).snapshot(cx);
20270                let chunk_by = this
20271                    .diff_hunks_in_ranges(&ranges, &snapshot)
20272                    .chunk_by(|hunk| hunk.buffer_id);
20273                for (buffer_id, hunks) in &chunk_by {
20274                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20275                }
20276            })
20277        })
20278        .detach_and_log_err(cx);
20279    }
20280
20281    fn save_buffers_for_ranges_if_needed(
20282        &mut self,
20283        ranges: &[Range<Anchor>],
20284        cx: &mut Context<Editor>,
20285    ) -> Task<Result<()>> {
20286        let multibuffer = self.buffer.read(cx);
20287        let snapshot = multibuffer.read(cx);
20288        let buffer_ids: HashSet<_> = ranges
20289            .iter()
20290            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20291            .collect();
20292        drop(snapshot);
20293
20294        let mut buffers = HashSet::default();
20295        for buffer_id in buffer_ids {
20296            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20297                let buffer = buffer_entity.read(cx);
20298                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20299                {
20300                    buffers.insert(buffer_entity);
20301                }
20302            }
20303        }
20304
20305        if let Some(project) = &self.project {
20306            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20307        } else {
20308            Task::ready(Ok(()))
20309        }
20310    }
20311
20312    fn do_stage_or_unstage_and_next(
20313        &mut self,
20314        stage: bool,
20315        window: &mut Window,
20316        cx: &mut Context<Self>,
20317    ) {
20318        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20319
20320        if ranges.iter().any(|range| range.start != range.end) {
20321            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20322            return;
20323        }
20324
20325        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20326        let snapshot = self.snapshot(window, cx);
20327        let position = self
20328            .selections
20329            .newest::<Point>(&snapshot.display_snapshot)
20330            .head();
20331        let mut row = snapshot
20332            .buffer_snapshot()
20333            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20334            .find(|hunk| hunk.row_range.start.0 > position.row)
20335            .map(|hunk| hunk.row_range.start);
20336
20337        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20338        // Outside of the project diff editor, wrap around to the beginning.
20339        if !all_diff_hunks_expanded {
20340            row = row.or_else(|| {
20341                snapshot
20342                    .buffer_snapshot()
20343                    .diff_hunks_in_range(Point::zero()..position)
20344                    .find(|hunk| hunk.row_range.end.0 < position.row)
20345                    .map(|hunk| hunk.row_range.start)
20346            });
20347        }
20348
20349        if let Some(row) = row {
20350            let destination = Point::new(row.0, 0);
20351            let autoscroll = Autoscroll::center();
20352
20353            self.unfold_ranges(&[destination..destination], false, false, cx);
20354            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20355                s.select_ranges([destination..destination]);
20356            });
20357        }
20358    }
20359
20360    fn do_stage_or_unstage(
20361        &self,
20362        stage: bool,
20363        buffer_id: BufferId,
20364        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20365        cx: &mut App,
20366    ) -> Option<()> {
20367        let project = self.project()?;
20368        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20369        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20370        let buffer_snapshot = buffer.read(cx).snapshot();
20371        let file_exists = buffer_snapshot
20372            .file()
20373            .is_some_and(|file| file.disk_state().exists());
20374        diff.update(cx, |diff, cx| {
20375            diff.stage_or_unstage_hunks(
20376                stage,
20377                &hunks
20378                    .map(|hunk| buffer_diff::DiffHunk {
20379                        buffer_range: hunk.buffer_range,
20380                        // We don't need to pass in word diffs here because they're only used for rendering and
20381                        // this function changes internal state
20382                        base_word_diffs: Vec::default(),
20383                        buffer_word_diffs: Vec::default(),
20384                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20385                            ..hunk.diff_base_byte_range.end.0,
20386                        secondary_status: hunk.status.secondary,
20387                        range: Point::zero()..Point::zero(), // unused
20388                    })
20389                    .collect::<Vec<_>>(),
20390                &buffer_snapshot,
20391                file_exists,
20392                cx,
20393            )
20394        });
20395        None
20396    }
20397
20398    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20399        let ranges: Vec<_> = self
20400            .selections
20401            .disjoint_anchors()
20402            .iter()
20403            .map(|s| s.range())
20404            .collect();
20405        self.buffer
20406            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20407    }
20408
20409    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20410        self.buffer.update(cx, |buffer, cx| {
20411            let ranges = vec![Anchor::min()..Anchor::max()];
20412            if !buffer.all_diff_hunks_expanded()
20413                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20414            {
20415                buffer.collapse_diff_hunks(ranges, cx);
20416                true
20417            } else {
20418                false
20419            }
20420        })
20421    }
20422
20423    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20424        if self.buffer.read(cx).all_diff_hunks_expanded() {
20425            return true;
20426        }
20427        let ranges = vec![Anchor::min()..Anchor::max()];
20428        self.buffer
20429            .read(cx)
20430            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20431    }
20432
20433    fn toggle_diff_hunks_in_ranges(
20434        &mut self,
20435        ranges: Vec<Range<Anchor>>,
20436        cx: &mut Context<Editor>,
20437    ) {
20438        self.buffer.update(cx, |buffer, cx| {
20439            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20440            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20441        })
20442    }
20443
20444    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20445        self.buffer.update(cx, |buffer, cx| {
20446            let snapshot = buffer.snapshot(cx);
20447            let excerpt_id = range.end.excerpt_id;
20448            let point_range = range.to_point(&snapshot);
20449            let expand = !buffer.single_hunk_is_expanded(range, cx);
20450            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20451        })
20452    }
20453
20454    pub(crate) fn apply_all_diff_hunks(
20455        &mut self,
20456        _: &ApplyAllDiffHunks,
20457        window: &mut Window,
20458        cx: &mut Context<Self>,
20459    ) {
20460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20461
20462        let buffers = self.buffer.read(cx).all_buffers();
20463        for branch_buffer in buffers {
20464            branch_buffer.update(cx, |branch_buffer, cx| {
20465                branch_buffer.merge_into_base(Vec::new(), cx);
20466            });
20467        }
20468
20469        if let Some(project) = self.project.clone() {
20470            self.save(
20471                SaveOptions {
20472                    format: true,
20473                    autosave: false,
20474                },
20475                project,
20476                window,
20477                cx,
20478            )
20479            .detach_and_log_err(cx);
20480        }
20481    }
20482
20483    pub(crate) fn apply_selected_diff_hunks(
20484        &mut self,
20485        _: &ApplyDiffHunk,
20486        window: &mut Window,
20487        cx: &mut Context<Self>,
20488    ) {
20489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20490        let snapshot = self.snapshot(window, cx);
20491        let hunks = snapshot.hunks_for_ranges(
20492            self.selections
20493                .all(&snapshot.display_snapshot)
20494                .into_iter()
20495                .map(|selection| selection.range()),
20496        );
20497        let mut ranges_by_buffer = HashMap::default();
20498        self.transact(window, cx, |editor, _window, cx| {
20499            for hunk in hunks {
20500                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20501                    ranges_by_buffer
20502                        .entry(buffer.clone())
20503                        .or_insert_with(Vec::new)
20504                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20505                }
20506            }
20507
20508            for (buffer, ranges) in ranges_by_buffer {
20509                buffer.update(cx, |buffer, cx| {
20510                    buffer.merge_into_base(ranges, cx);
20511                });
20512            }
20513        });
20514
20515        if let Some(project) = self.project.clone() {
20516            self.save(
20517                SaveOptions {
20518                    format: true,
20519                    autosave: false,
20520                },
20521                project,
20522                window,
20523                cx,
20524            )
20525            .detach_and_log_err(cx);
20526        }
20527    }
20528
20529    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20530        if hovered != self.gutter_hovered {
20531            self.gutter_hovered = hovered;
20532            cx.notify();
20533        }
20534    }
20535
20536    pub fn insert_blocks(
20537        &mut self,
20538        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20539        autoscroll: Option<Autoscroll>,
20540        cx: &mut Context<Self>,
20541    ) -> Vec<CustomBlockId> {
20542        let blocks = self
20543            .display_map
20544            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20545        if let Some(autoscroll) = autoscroll {
20546            self.request_autoscroll(autoscroll, cx);
20547        }
20548        cx.notify();
20549        blocks
20550    }
20551
20552    pub fn resize_blocks(
20553        &mut self,
20554        heights: HashMap<CustomBlockId, u32>,
20555        autoscroll: Option<Autoscroll>,
20556        cx: &mut Context<Self>,
20557    ) {
20558        self.display_map
20559            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20560        if let Some(autoscroll) = autoscroll {
20561            self.request_autoscroll(autoscroll, cx);
20562        }
20563        cx.notify();
20564    }
20565
20566    pub fn replace_blocks(
20567        &mut self,
20568        renderers: HashMap<CustomBlockId, RenderBlock>,
20569        autoscroll: Option<Autoscroll>,
20570        cx: &mut Context<Self>,
20571    ) {
20572        self.display_map
20573            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20574        if let Some(autoscroll) = autoscroll {
20575            self.request_autoscroll(autoscroll, cx);
20576        }
20577        cx.notify();
20578    }
20579
20580    pub fn remove_blocks(
20581        &mut self,
20582        block_ids: HashSet<CustomBlockId>,
20583        autoscroll: Option<Autoscroll>,
20584        cx: &mut Context<Self>,
20585    ) {
20586        self.display_map.update(cx, |display_map, cx| {
20587            display_map.remove_blocks(block_ids, cx)
20588        });
20589        if let Some(autoscroll) = autoscroll {
20590            self.request_autoscroll(autoscroll, cx);
20591        }
20592        cx.notify();
20593    }
20594
20595    pub fn row_for_block(
20596        &self,
20597        block_id: CustomBlockId,
20598        cx: &mut Context<Self>,
20599    ) -> Option<DisplayRow> {
20600        self.display_map
20601            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20602    }
20603
20604    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20605        self.focused_block = Some(focused_block);
20606    }
20607
20608    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20609        self.focused_block.take()
20610    }
20611
20612    pub fn insert_creases(
20613        &mut self,
20614        creases: impl IntoIterator<Item = Crease<Anchor>>,
20615        cx: &mut Context<Self>,
20616    ) -> Vec<CreaseId> {
20617        self.display_map
20618            .update(cx, |map, cx| map.insert_creases(creases, cx))
20619    }
20620
20621    pub fn remove_creases(
20622        &mut self,
20623        ids: impl IntoIterator<Item = CreaseId>,
20624        cx: &mut Context<Self>,
20625    ) -> Vec<(CreaseId, Range<Anchor>)> {
20626        self.display_map
20627            .update(cx, |map, cx| map.remove_creases(ids, cx))
20628    }
20629
20630    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20631        self.display_map
20632            .update(cx, |map, cx| map.snapshot(cx))
20633            .longest_row()
20634    }
20635
20636    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20637        self.display_map
20638            .update(cx, |map, cx| map.snapshot(cx))
20639            .max_point()
20640    }
20641
20642    pub fn text(&self, cx: &App) -> String {
20643        self.buffer.read(cx).read(cx).text()
20644    }
20645
20646    pub fn is_empty(&self, cx: &App) -> bool {
20647        self.buffer.read(cx).read(cx).is_empty()
20648    }
20649
20650    pub fn text_option(&self, cx: &App) -> Option<String> {
20651        let text = self.text(cx);
20652        let text = text.trim();
20653
20654        if text.is_empty() {
20655            return None;
20656        }
20657
20658        Some(text.to_string())
20659    }
20660
20661    pub fn set_text(
20662        &mut self,
20663        text: impl Into<Arc<str>>,
20664        window: &mut Window,
20665        cx: &mut Context<Self>,
20666    ) {
20667        self.transact(window, cx, |this, _, cx| {
20668            this.buffer
20669                .read(cx)
20670                .as_singleton()
20671                .expect("you can only call set_text on editors for singleton buffers")
20672                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20673        });
20674    }
20675
20676    pub fn display_text(&self, cx: &mut App) -> String {
20677        self.display_map
20678            .update(cx, |map, cx| map.snapshot(cx))
20679            .text()
20680    }
20681
20682    fn create_minimap(
20683        &self,
20684        minimap_settings: MinimapSettings,
20685        window: &mut Window,
20686        cx: &mut Context<Self>,
20687    ) -> Option<Entity<Self>> {
20688        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20689            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20690    }
20691
20692    fn initialize_new_minimap(
20693        &self,
20694        minimap_settings: MinimapSettings,
20695        window: &mut Window,
20696        cx: &mut Context<Self>,
20697    ) -> Entity<Self> {
20698        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20699        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20700
20701        let mut minimap = Editor::new_internal(
20702            EditorMode::Minimap {
20703                parent: cx.weak_entity(),
20704            },
20705            self.buffer.clone(),
20706            None,
20707            Some(self.display_map.clone()),
20708            window,
20709            cx,
20710        );
20711        minimap.scroll_manager.clone_state(&self.scroll_manager);
20712        minimap.set_text_style_refinement(TextStyleRefinement {
20713            font_size: Some(MINIMAP_FONT_SIZE),
20714            font_weight: Some(MINIMAP_FONT_WEIGHT),
20715            font_family: Some(MINIMAP_FONT_FAMILY),
20716            ..Default::default()
20717        });
20718        minimap.update_minimap_configuration(minimap_settings, cx);
20719        cx.new(|_| minimap)
20720    }
20721
20722    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20723        let current_line_highlight = minimap_settings
20724            .current_line_highlight
20725            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20726        self.set_current_line_highlight(Some(current_line_highlight));
20727    }
20728
20729    pub fn minimap(&self) -> Option<&Entity<Self>> {
20730        self.minimap
20731            .as_ref()
20732            .filter(|_| self.minimap_visibility.visible())
20733    }
20734
20735    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20736        let mut wrap_guides = smallvec![];
20737
20738        if self.show_wrap_guides == Some(false) {
20739            return wrap_guides;
20740        }
20741
20742        let settings = self.buffer.read(cx).language_settings(cx);
20743        if settings.show_wrap_guides {
20744            match self.soft_wrap_mode(cx) {
20745                SoftWrap::Column(soft_wrap) => {
20746                    wrap_guides.push((soft_wrap as usize, true));
20747                }
20748                SoftWrap::Bounded(soft_wrap) => {
20749                    wrap_guides.push((soft_wrap as usize, true));
20750                }
20751                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20752            }
20753            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20754        }
20755
20756        wrap_guides
20757    }
20758
20759    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20760        let settings = self.buffer.read(cx).language_settings(cx);
20761        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20762        match mode {
20763            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20764                SoftWrap::None
20765            }
20766            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20767            language_settings::SoftWrap::PreferredLineLength => {
20768                SoftWrap::Column(settings.preferred_line_length)
20769            }
20770            language_settings::SoftWrap::Bounded => {
20771                SoftWrap::Bounded(settings.preferred_line_length)
20772            }
20773        }
20774    }
20775
20776    pub fn set_soft_wrap_mode(
20777        &mut self,
20778        mode: language_settings::SoftWrap,
20779
20780        cx: &mut Context<Self>,
20781    ) {
20782        self.soft_wrap_mode_override = Some(mode);
20783        cx.notify();
20784    }
20785
20786    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20787        self.hard_wrap = hard_wrap;
20788        cx.notify();
20789    }
20790
20791    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20792        self.text_style_refinement = Some(style);
20793    }
20794
20795    /// called by the Element so we know what style we were most recently rendered with.
20796    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20797        // We intentionally do not inform the display map about the minimap style
20798        // so that wrapping is not recalculated and stays consistent for the editor
20799        // and its linked minimap.
20800        if !self.mode.is_minimap() {
20801            let font = style.text.font();
20802            let font_size = style.text.font_size.to_pixels(window.rem_size());
20803            let display_map = self
20804                .placeholder_display_map
20805                .as_ref()
20806                .filter(|_| self.is_empty(cx))
20807                .unwrap_or(&self.display_map);
20808
20809            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20810        }
20811        self.style = Some(style);
20812    }
20813
20814    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20815        if self.style.is_none() {
20816            self.style = Some(self.create_style(cx));
20817        }
20818        self.style.as_ref().unwrap()
20819    }
20820
20821    // Called by the element. This method is not designed to be called outside of the editor
20822    // element's layout code because it does not notify when rewrapping is computed synchronously.
20823    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20824        if self.is_empty(cx) {
20825            self.placeholder_display_map
20826                .as_ref()
20827                .map_or(false, |display_map| {
20828                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20829                })
20830        } else {
20831            self.display_map
20832                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20833        }
20834    }
20835
20836    pub fn set_soft_wrap(&mut self) {
20837        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20838    }
20839
20840    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20841        if self.soft_wrap_mode_override.is_some() {
20842            self.soft_wrap_mode_override.take();
20843        } else {
20844            let soft_wrap = match self.soft_wrap_mode(cx) {
20845                SoftWrap::GitDiff => return,
20846                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20847                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20848                    language_settings::SoftWrap::None
20849                }
20850            };
20851            self.soft_wrap_mode_override = Some(soft_wrap);
20852        }
20853        cx.notify();
20854    }
20855
20856    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20857        let Some(workspace) = self.workspace() else {
20858            return;
20859        };
20860        let fs = workspace.read(cx).app_state().fs.clone();
20861        let current_show = TabBarSettings::get_global(cx).show;
20862        update_settings_file(fs, cx, move |setting, _| {
20863            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20864        });
20865    }
20866
20867    pub fn toggle_indent_guides(
20868        &mut self,
20869        _: &ToggleIndentGuides,
20870        _: &mut Window,
20871        cx: &mut Context<Self>,
20872    ) {
20873        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20874            self.buffer
20875                .read(cx)
20876                .language_settings(cx)
20877                .indent_guides
20878                .enabled
20879        });
20880        self.show_indent_guides = Some(!currently_enabled);
20881        cx.notify();
20882    }
20883
20884    fn should_show_indent_guides(&self) -> Option<bool> {
20885        self.show_indent_guides
20886    }
20887
20888    pub fn disable_indent_guides_for_buffer(
20889        &mut self,
20890        buffer_id: BufferId,
20891        cx: &mut Context<Self>,
20892    ) {
20893        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20894        cx.notify();
20895    }
20896
20897    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20898        self.buffers_with_disabled_indent_guides
20899            .contains(&buffer_id)
20900    }
20901
20902    pub fn toggle_line_numbers(
20903        &mut self,
20904        _: &ToggleLineNumbers,
20905        _: &mut Window,
20906        cx: &mut Context<Self>,
20907    ) {
20908        let mut editor_settings = EditorSettings::get_global(cx).clone();
20909        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20910        EditorSettings::override_global(editor_settings, cx);
20911    }
20912
20913    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20914        if let Some(show_line_numbers) = self.show_line_numbers {
20915            return show_line_numbers;
20916        }
20917        EditorSettings::get_global(cx).gutter.line_numbers
20918    }
20919
20920    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20921        match (
20922            self.use_relative_line_numbers,
20923            EditorSettings::get_global(cx).relative_line_numbers,
20924        ) {
20925            (None, setting) => setting,
20926            (Some(false), _) => RelativeLineNumbers::Disabled,
20927            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20928            (Some(true), _) => RelativeLineNumbers::Enabled,
20929        }
20930    }
20931
20932    pub fn toggle_relative_line_numbers(
20933        &mut self,
20934        _: &ToggleRelativeLineNumbers,
20935        _: &mut Window,
20936        cx: &mut Context<Self>,
20937    ) {
20938        let is_relative = self.relative_line_numbers(cx);
20939        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20940    }
20941
20942    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20943        self.use_relative_line_numbers = is_relative;
20944        cx.notify();
20945    }
20946
20947    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20948        self.show_gutter = show_gutter;
20949        cx.notify();
20950    }
20951
20952    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20953        self.show_scrollbars = ScrollbarAxes {
20954            horizontal: show,
20955            vertical: show,
20956        };
20957        cx.notify();
20958    }
20959
20960    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20961        self.show_scrollbars.vertical = show;
20962        cx.notify();
20963    }
20964
20965    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20966        self.show_scrollbars.horizontal = show;
20967        cx.notify();
20968    }
20969
20970    pub fn set_minimap_visibility(
20971        &mut self,
20972        minimap_visibility: MinimapVisibility,
20973        window: &mut Window,
20974        cx: &mut Context<Self>,
20975    ) {
20976        if self.minimap_visibility != minimap_visibility {
20977            if minimap_visibility.visible() && self.minimap.is_none() {
20978                let minimap_settings = EditorSettings::get_global(cx).minimap;
20979                self.minimap =
20980                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20981            }
20982            self.minimap_visibility = minimap_visibility;
20983            cx.notify();
20984        }
20985    }
20986
20987    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20988        self.set_show_scrollbars(false, cx);
20989        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20990    }
20991
20992    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20993        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20994    }
20995
20996    /// Normally the text in full mode and auto height editors is padded on the
20997    /// left side by roughly half a character width for improved hit testing.
20998    ///
20999    /// Use this method to disable this for cases where this is not wanted (e.g.
21000    /// if you want to align the editor text with some other text above or below)
21001    /// or if you want to add this padding to single-line editors.
21002    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21003        self.offset_content = offset_content;
21004        cx.notify();
21005    }
21006
21007    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21008        self.show_line_numbers = Some(show_line_numbers);
21009        cx.notify();
21010    }
21011
21012    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21013        self.disable_expand_excerpt_buttons = true;
21014        cx.notify();
21015    }
21016
21017    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21018        self.delegate_expand_excerpts = delegate;
21019    }
21020
21021    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21022        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21023        cx.notify();
21024    }
21025
21026    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21027        self.show_code_actions = Some(show_code_actions);
21028        cx.notify();
21029    }
21030
21031    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21032        self.show_runnables = Some(show_runnables);
21033        cx.notify();
21034    }
21035
21036    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21037        self.show_breakpoints = Some(show_breakpoints);
21038        cx.notify();
21039    }
21040
21041    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21042        self.show_diff_review_button = show;
21043        cx.notify();
21044    }
21045
21046    pub fn show_diff_review_button(&self) -> bool {
21047        self.show_diff_review_button
21048    }
21049
21050    pub fn render_diff_review_button(
21051        &self,
21052        display_row: DisplayRow,
21053        width: Pixels,
21054        cx: &mut Context<Self>,
21055    ) -> impl IntoElement {
21056        let text_color = cx.theme().colors().text;
21057        let icon_color = cx.theme().colors().icon_accent;
21058
21059        h_flex()
21060            .id("diff_review_button")
21061            .cursor_pointer()
21062            .w(width - px(1.))
21063            .h(relative(0.9))
21064            .justify_center()
21065            .rounded_sm()
21066            .border_1()
21067            .border_color(text_color.opacity(0.1))
21068            .bg(text_color.opacity(0.15))
21069            .hover(|s| {
21070                s.bg(icon_color.opacity(0.4))
21071                    .border_color(icon_color.opacity(0.5))
21072            })
21073            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21074            .tooltip(Tooltip::text("Add Review"))
21075            .on_click(cx.listener(move |editor, _event: &ClickEvent, window, cx| {
21076                editor.show_diff_review_overlay(display_row, window, cx);
21077            }))
21078    }
21079
21080    /// Calculates the appropriate block height for the diff review overlay.
21081    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21082    /// and 2 lines per comment when expanded.
21083    fn calculate_overlay_height(
21084        &self,
21085        hunk_key: &DiffHunkKey,
21086        comments_expanded: bool,
21087        snapshot: &MultiBufferSnapshot,
21088    ) -> u32 {
21089        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21090        let base_height: u32 = 2; // Input row with avatar and buttons
21091
21092        if comment_count == 0 {
21093            base_height
21094        } else if comments_expanded {
21095            // Header (1 line) + 2 lines per comment
21096            base_height + 1 + (comment_count as u32 * 2)
21097        } else {
21098            // Just header when collapsed
21099            base_height + 1
21100        }
21101    }
21102
21103    pub fn show_diff_review_overlay(
21104        &mut self,
21105        display_row: DisplayRow,
21106        window: &mut Window,
21107        cx: &mut Context<Self>,
21108    ) {
21109        // Check if there's already an overlay for the same hunk - if so, just focus it
21110        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21111        let editor_snapshot = self.snapshot(window, cx);
21112        let display_point = DisplayPoint::new(display_row, 0);
21113        let buffer_point = editor_snapshot
21114            .display_snapshot
21115            .display_point_to_point(display_point, Bias::Left);
21116
21117        // Compute the hunk key for this display row
21118        let file_path = buffer_snapshot
21119            .file_at(Point::new(buffer_point.row, 0))
21120            .map(|file: &Arc<dyn language::File>| file.path().clone())
21121            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21122        let hunk_start_anchor = buffer_snapshot.anchor_before(Point::new(buffer_point.row, 0));
21123        let new_hunk_key = DiffHunkKey {
21124            file_path,
21125            hunk_start_anchor,
21126        };
21127
21128        // Check if we already have an overlay for this hunk
21129        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21130            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21131        }) {
21132            // Just focus the existing overlay's prompt editor
21133            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21134            window.focus(&focus_handle, cx);
21135            return;
21136        }
21137
21138        // Dismiss overlays that have no comments for their hunks
21139        self.dismiss_overlays_without_comments(cx);
21140
21141        // Get the current user's avatar URI from the project's user_store
21142        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21143            let user_store = project.read(cx).user_store();
21144            user_store
21145                .read(cx)
21146                .current_user()
21147                .map(|user| user.avatar_uri.clone())
21148        });
21149
21150        // Create anchor at the end of the row so the block appears immediately below it
21151        let line_len = buffer_snapshot.line_len(MultiBufferRow(buffer_point.row));
21152        let anchor = buffer_snapshot.anchor_after(Point::new(buffer_point.row, line_len));
21153
21154        // Use the hunk key we already computed
21155        let hunk_key = new_hunk_key;
21156
21157        // Create the prompt editor for the review input
21158        let prompt_editor = cx.new(|cx| {
21159            let mut editor = Editor::single_line(window, cx);
21160            editor.set_placeholder_text("Add a review comment...", window, cx);
21161            editor
21162        });
21163
21164        // Register the Newline action on the prompt editor to submit the review
21165        let parent_editor = cx.entity().downgrade();
21166        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21167            prompt_editor.register_action({
21168                let parent_editor = parent_editor.clone();
21169                move |_: &crate::actions::Newline, window, cx| {
21170                    if let Some(editor) = parent_editor.upgrade() {
21171                        editor.update(cx, |editor, cx| {
21172                            editor.submit_diff_review_comment(window, cx);
21173                        });
21174                    }
21175                }
21176            })
21177        });
21178
21179        // Calculate initial height based on existing comments for this hunk
21180        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21181
21182        // Create the overlay block
21183        let prompt_editor_for_render = prompt_editor.clone();
21184        let hunk_key_for_render = hunk_key.clone();
21185        let editor_handle = cx.entity().downgrade();
21186        let block = BlockProperties {
21187            style: BlockStyle::Sticky,
21188            placement: BlockPlacement::Below(anchor),
21189            height: Some(initial_height),
21190            render: Arc::new(move |cx| {
21191                Self::render_diff_review_overlay(
21192                    &prompt_editor_for_render,
21193                    &hunk_key_for_render,
21194                    &editor_handle,
21195                    cx,
21196                )
21197            }),
21198            priority: 0,
21199        };
21200
21201        let block_ids = self.insert_blocks([block], None, cx);
21202        let Some(block_id) = block_ids.into_iter().next() else {
21203            log::error!("Failed to insert diff review overlay block");
21204            return;
21205        };
21206
21207        self.diff_review_overlays.push(DiffReviewOverlay {
21208            display_row,
21209            block_id,
21210            prompt_editor: prompt_editor.clone(),
21211            hunk_key,
21212            comments_expanded: true,
21213            inline_edit_editors: HashMap::default(),
21214            inline_edit_subscriptions: HashMap::default(),
21215            user_avatar_uri,
21216            _subscription: subscription,
21217        });
21218
21219        // Focus the prompt editor
21220        let focus_handle = prompt_editor.focus_handle(cx);
21221        window.focus(&focus_handle, cx);
21222
21223        cx.notify();
21224    }
21225
21226    /// Dismisses all diff review overlays.
21227    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21228        if self.diff_review_overlays.is_empty() {
21229            return;
21230        }
21231        let block_ids: HashSet<_> = self
21232            .diff_review_overlays
21233            .drain(..)
21234            .map(|overlay| overlay.block_id)
21235            .collect();
21236        self.remove_blocks(block_ids, None, cx);
21237        cx.notify();
21238    }
21239
21240    /// Dismisses overlays that have no comments stored for their hunks.
21241    /// Keeps overlays that have at least one comment.
21242    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21243        let snapshot = self.buffer.read(cx).snapshot(cx);
21244
21245        // First, compute which overlays have comments (to avoid borrow issues with retain)
21246        let overlays_with_comments: Vec<bool> = self
21247            .diff_review_overlays
21248            .iter()
21249            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
21250            .collect();
21251
21252        // Now collect block IDs to remove and retain overlays
21253        let mut block_ids_to_remove = HashSet::default();
21254        let mut index = 0;
21255        self.diff_review_overlays.retain(|overlay| {
21256            let has_comments = overlays_with_comments[index];
21257            index += 1;
21258            if !has_comments {
21259                block_ids_to_remove.insert(overlay.block_id);
21260            }
21261            has_comments
21262        });
21263
21264        if !block_ids_to_remove.is_empty() {
21265            self.remove_blocks(block_ids_to_remove, None, cx);
21266            cx.notify();
21267        }
21268    }
21269
21270    /// Refreshes the diff review overlay block to update its height and render function.
21271    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
21272    fn refresh_diff_review_overlay_height(
21273        &mut self,
21274        hunk_key: &DiffHunkKey,
21275        _window: &mut Window,
21276        cx: &mut Context<Self>,
21277    ) {
21278        // Extract all needed data from overlay first to avoid borrow conflicts
21279        let snapshot = self.buffer.read(cx).snapshot(cx);
21280        let (comments_expanded, block_id, prompt_editor) = {
21281            let Some(overlay) = self
21282                .diff_review_overlays
21283                .iter()
21284                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21285            else {
21286                return;
21287            };
21288
21289            (
21290                overlay.comments_expanded,
21291                overlay.block_id,
21292                overlay.prompt_editor.clone(),
21293            )
21294        };
21295
21296        // Calculate new height
21297        let snapshot = self.buffer.read(cx).snapshot(cx);
21298        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
21299
21300        // Update the block height using resize_blocks (avoids flicker)
21301        let mut heights = HashMap::default();
21302        heights.insert(block_id, new_height);
21303        self.resize_blocks(heights, None, cx);
21304
21305        // Update the render function using replace_blocks (avoids flicker)
21306        let hunk_key_for_render = hunk_key.clone();
21307        let editor_handle = cx.entity().downgrade();
21308        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
21309            Arc::new(move |cx| {
21310                Self::render_diff_review_overlay(
21311                    &prompt_editor,
21312                    &hunk_key_for_render,
21313                    &editor_handle,
21314                    cx,
21315                )
21316            });
21317
21318        let mut renderers = HashMap::default();
21319        renderers.insert(block_id, render);
21320        self.replace_blocks(renderers, None, cx);
21321    }
21322
21323    /// Action handler for SubmitDiffReviewComment.
21324    pub fn submit_diff_review_comment_action(
21325        &mut self,
21326        _: &SubmitDiffReviewComment,
21327        window: &mut Window,
21328        cx: &mut Context<Self>,
21329    ) {
21330        self.submit_diff_review_comment(window, cx);
21331    }
21332
21333    /// Stores the diff review comment locally.
21334    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
21335    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21336        // Find the overlay that currently has focus
21337        let overlay_index = self
21338            .diff_review_overlays
21339            .iter()
21340            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
21341        let Some(overlay_index) = overlay_index else {
21342            return;
21343        };
21344        let overlay = &self.diff_review_overlays[overlay_index];
21345
21346        // Get the comment text from the prompt editor
21347        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
21348
21349        // Don't submit if the comment is empty
21350        if comment_text.is_empty() {
21351            return;
21352        }
21353
21354        // Get the display row and hunk key
21355        let display_row = overlay.display_row;
21356        let hunk_key = overlay.hunk_key.clone();
21357
21358        // Convert to buffer position for anchors
21359        let snapshot = self.snapshot(window, cx);
21360        let display_point = DisplayPoint::new(display_row, 0);
21361        let buffer_point = snapshot
21362            .display_snapshot
21363            .display_point_to_point(display_point, Bias::Left);
21364
21365        // Get the line range
21366        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21367        let line_start = Point::new(buffer_point.row, 0);
21368        let line_end = Point::new(
21369            buffer_point.row,
21370            buffer_snapshot.line_len(MultiBufferRow(buffer_point.row)),
21371        );
21372
21373        // Create anchors for the selection
21374        let anchor_start = buffer_snapshot.anchor_after(line_start);
21375        let anchor_end = buffer_snapshot.anchor_before(line_end);
21376
21377        // Store the comment locally
21378        self.add_review_comment(
21379            hunk_key.clone(),
21380            comment_text,
21381            display_row,
21382            anchor_start..anchor_end,
21383            cx,
21384        );
21385
21386        // Clear the prompt editor but keep the overlay open
21387        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
21388            overlay.prompt_editor.update(cx, |editor, cx| {
21389                editor.clear(window, cx);
21390            });
21391        }
21392
21393        // Refresh the overlay to update the block height for the new comment
21394        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21395
21396        cx.notify();
21397    }
21398
21399    /// Returns the prompt editor for the diff review overlay, if one is active.
21400    /// This is primarily used for testing.
21401    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
21402        self.diff_review_overlays
21403            .first()
21404            .map(|overlay| &overlay.prompt_editor)
21405    }
21406
21407    /// Returns the display row for the first diff review overlay, if one is active.
21408    pub fn diff_review_display_row(&self) -> Option<DisplayRow> {
21409        self.diff_review_overlays
21410            .first()
21411            .map(|overlay| overlay.display_row)
21412    }
21413
21414    /// Sets whether the comments section is expanded in the diff review overlay.
21415    /// This is primarily used for testing.
21416    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
21417        for overlay in &mut self.diff_review_overlays {
21418            overlay.comments_expanded = expanded;
21419        }
21420        cx.notify();
21421    }
21422
21423    /// Compares two DiffHunkKeys for equality by resolving their anchors.
21424    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
21425        a.file_path == b.file_path
21426            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
21427    }
21428
21429    /// Returns comments for a specific hunk, ordered by creation time.
21430    pub fn comments_for_hunk<'a>(
21431        &'a self,
21432        key: &DiffHunkKey,
21433        snapshot: &MultiBufferSnapshot,
21434    ) -> &'a [StoredReviewComment] {
21435        let key_point = key.hunk_start_anchor.to_point(snapshot);
21436        self.stored_review_comments
21437            .iter()
21438            .find(|(k, _)| {
21439                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21440            })
21441            .map(|(_, comments)| comments.as_slice())
21442            .unwrap_or(&[])
21443    }
21444
21445    /// Returns the total count of stored review comments across all hunks.
21446    pub fn total_review_comment_count(&self) -> usize {
21447        self.stored_review_comments
21448            .iter()
21449            .map(|(_, v)| v.len())
21450            .sum()
21451    }
21452
21453    /// Returns the count of comments for a specific hunk.
21454    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
21455        let key_point = key.hunk_start_anchor.to_point(snapshot);
21456        self.stored_review_comments
21457            .iter()
21458            .find(|(k, _)| {
21459                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21460            })
21461            .map(|(_, v)| v.len())
21462            .unwrap_or(0)
21463    }
21464
21465    /// Adds a new review comment to a specific hunk.
21466    pub fn add_review_comment(
21467        &mut self,
21468        hunk_key: DiffHunkKey,
21469        comment: String,
21470        display_row: DisplayRow,
21471        anchor_range: Range<Anchor>,
21472        cx: &mut Context<Self>,
21473    ) -> usize {
21474        let id = self.next_review_comment_id;
21475        self.next_review_comment_id += 1;
21476
21477        let stored_comment = StoredReviewComment::new(id, comment, display_row, anchor_range);
21478
21479        let snapshot = self.buffer.read(cx).snapshot(cx);
21480        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
21481
21482        // Find existing entry for this hunk or add a new one
21483        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
21484            k.file_path == hunk_key.file_path
21485                && k.hunk_start_anchor.to_point(&snapshot) == key_point
21486        }) {
21487            comments.push(stored_comment);
21488        } else {
21489            self.stored_review_comments
21490                .push((hunk_key, vec![stored_comment]));
21491        }
21492
21493        cx.emit(EditorEvent::ReviewCommentsChanged {
21494            total_count: self.total_review_comment_count(),
21495        });
21496        cx.notify();
21497        id
21498    }
21499
21500    /// Removes a review comment by ID from any hunk.
21501    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
21502        for (_, comments) in self.stored_review_comments.iter_mut() {
21503            if let Some(index) = comments.iter().position(|c| c.id == id) {
21504                comments.remove(index);
21505                cx.emit(EditorEvent::ReviewCommentsChanged {
21506                    total_count: self.total_review_comment_count(),
21507                });
21508                cx.notify();
21509                return true;
21510            }
21511        }
21512        false
21513    }
21514
21515    /// Updates a review comment's text by ID.
21516    pub fn update_review_comment(
21517        &mut self,
21518        id: usize,
21519        new_comment: String,
21520        cx: &mut Context<Self>,
21521    ) -> bool {
21522        for (_, comments) in self.stored_review_comments.iter_mut() {
21523            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21524                comment.comment = new_comment;
21525                comment.is_editing = false;
21526                cx.emit(EditorEvent::ReviewCommentsChanged {
21527                    total_count: self.total_review_comment_count(),
21528                });
21529                cx.notify();
21530                return true;
21531            }
21532        }
21533        false
21534    }
21535
21536    /// Sets a comment's editing state.
21537    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
21538        for (_, comments) in self.stored_review_comments.iter_mut() {
21539            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21540                comment.is_editing = is_editing;
21541                cx.notify();
21542                return;
21543            }
21544        }
21545    }
21546
21547    /// Takes all stored comments from all hunks, clearing the storage.
21548    /// Returns a Vec of (hunk_key, comments) pairs.
21549    pub fn take_all_review_comments(
21550        &mut self,
21551        cx: &mut Context<Self>,
21552    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
21553        // Dismiss all overlays when taking comments (e.g., when sending to agent)
21554        self.dismiss_all_diff_review_overlays(cx);
21555        let comments = std::mem::take(&mut self.stored_review_comments);
21556        // Reset the ID counter since all comments have been taken
21557        self.next_review_comment_id = 0;
21558        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
21559        cx.notify();
21560        comments
21561    }
21562
21563    /// Removes review comments whose anchors are no longer valid or whose
21564    /// associated diff hunks no longer exist.
21565    ///
21566    /// This should be called when the buffer changes to prevent orphaned comments
21567    /// from accumulating.
21568    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
21569        let snapshot = self.buffer.read(cx).snapshot(cx);
21570        let original_count = self.total_review_comment_count();
21571
21572        // Remove comments with invalid hunk anchors
21573        self.stored_review_comments
21574            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
21575
21576        // Also clean up individual comments with invalid anchor ranges
21577        for (_, comments) in &mut self.stored_review_comments {
21578            comments.retain(|comment| {
21579                comment.anchor_range.start.is_valid(&snapshot)
21580                    && comment.anchor_range.end.is_valid(&snapshot)
21581            });
21582        }
21583
21584        // Remove empty hunk entries
21585        self.stored_review_comments
21586            .retain(|(_, comments)| !comments.is_empty());
21587
21588        let new_count = self.total_review_comment_count();
21589        if new_count != original_count {
21590            cx.emit(EditorEvent::ReviewCommentsChanged {
21591                total_count: new_count,
21592            });
21593            cx.notify();
21594        }
21595    }
21596
21597    /// Toggles the expanded state of the comments section in the overlay.
21598    pub fn toggle_review_comments_expanded(
21599        &mut self,
21600        _: &ToggleReviewCommentsExpanded,
21601        window: &mut Window,
21602        cx: &mut Context<Self>,
21603    ) {
21604        // Find the overlay that currently has focus, or use the first one
21605        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
21606            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
21607                overlay.comments_expanded = !overlay.comments_expanded;
21608                Some(overlay.hunk_key.clone())
21609            } else {
21610                None
21611            }
21612        });
21613
21614        // If no focused overlay found, toggle the first one
21615        let hunk_key = overlay_info.or_else(|| {
21616            self.diff_review_overlays.first_mut().map(|overlay| {
21617                overlay.comments_expanded = !overlay.comments_expanded;
21618                overlay.hunk_key.clone()
21619            })
21620        });
21621
21622        if let Some(hunk_key) = hunk_key {
21623            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21624            cx.notify();
21625        }
21626    }
21627
21628    /// Handles the EditReviewComment action - sets a comment into editing mode.
21629    pub fn edit_review_comment(
21630        &mut self,
21631        action: &EditReviewComment,
21632        window: &mut Window,
21633        cx: &mut Context<Self>,
21634    ) {
21635        let comment_id = action.id;
21636
21637        // Set the comment to editing mode
21638        self.set_comment_editing(comment_id, true, cx);
21639
21640        // Find the overlay that contains this comment and create an inline editor if needed
21641        // First, find which hunk this comment belongs to
21642        let hunk_key = self
21643            .stored_review_comments
21644            .iter()
21645            .find_map(|(key, comments)| {
21646                if comments.iter().any(|c| c.id == comment_id) {
21647                    Some(key.clone())
21648                } else {
21649                    None
21650                }
21651            });
21652
21653        let snapshot = self.buffer.read(cx).snapshot(cx);
21654        if let Some(hunk_key) = hunk_key {
21655            if let Some(overlay) = self
21656                .diff_review_overlays
21657                .iter_mut()
21658                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21659            {
21660                if let std::collections::hash_map::Entry::Vacant(entry) =
21661                    overlay.inline_edit_editors.entry(comment_id)
21662                {
21663                    // Find the comment text
21664                    let comment_text = self
21665                        .stored_review_comments
21666                        .iter()
21667                        .flat_map(|(_, comments)| comments)
21668                        .find(|c| c.id == comment_id)
21669                        .map(|c| c.comment.clone())
21670                        .unwrap_or_default();
21671
21672                    // Create inline editor
21673                    let parent_editor = cx.entity().downgrade();
21674                    let inline_editor = cx.new(|cx| {
21675                        let mut editor = Editor::single_line(window, cx);
21676                        editor.set_text(&*comment_text, window, cx);
21677                        // Select all text for easy replacement
21678                        editor.select_all(&crate::actions::SelectAll, window, cx);
21679                        editor
21680                    });
21681
21682                    // Register the Newline action to confirm the edit
21683                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
21684                        inline_editor.register_action({
21685                            let parent_editor = parent_editor.clone();
21686                            move |_: &crate::actions::Newline, window, cx| {
21687                                if let Some(editor) = parent_editor.upgrade() {
21688                                    editor.update(cx, |editor, cx| {
21689                                        editor.confirm_edit_review_comment(comment_id, window, cx);
21690                                    });
21691                                }
21692                            }
21693                        })
21694                    });
21695
21696                    // Store the subscription to keep the action handler alive
21697                    overlay
21698                        .inline_edit_subscriptions
21699                        .insert(comment_id, subscription);
21700
21701                    // Focus the inline editor
21702                    let focus_handle = inline_editor.focus_handle(cx);
21703                    window.focus(&focus_handle, cx);
21704
21705                    entry.insert(inline_editor);
21706                }
21707            }
21708        }
21709
21710        cx.notify();
21711    }
21712
21713    /// Confirms an inline edit of a review comment.
21714    pub fn confirm_edit_review_comment(
21715        &mut self,
21716        comment_id: usize,
21717        _window: &mut Window,
21718        cx: &mut Context<Self>,
21719    ) {
21720        // Get the new text from the inline editor
21721        // Find the overlay containing this comment's inline editor
21722        let snapshot = self.buffer.read(cx).snapshot(cx);
21723        let hunk_key = self
21724            .stored_review_comments
21725            .iter()
21726            .find_map(|(key, comments)| {
21727                if comments.iter().any(|c| c.id == comment_id) {
21728                    Some(key.clone())
21729                } else {
21730                    None
21731                }
21732            });
21733
21734        let new_text = hunk_key
21735            .as_ref()
21736            .and_then(|hunk_key| {
21737                self.diff_review_overlays
21738                    .iter()
21739                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21740            })
21741            .as_ref()
21742            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
21743            .map(|editor| editor.read(cx).text(cx).trim().to_string());
21744
21745        if let Some(new_text) = new_text {
21746            if !new_text.is_empty() {
21747                self.update_review_comment(comment_id, new_text, cx);
21748            }
21749        }
21750
21751        // Remove the inline editor and its subscription
21752        if let Some(hunk_key) = hunk_key {
21753            if let Some(overlay) = self
21754                .diff_review_overlays
21755                .iter_mut()
21756                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21757            {
21758                overlay.inline_edit_editors.remove(&comment_id);
21759                overlay.inline_edit_subscriptions.remove(&comment_id);
21760            }
21761        }
21762
21763        // Clear editing state
21764        self.set_comment_editing(comment_id, false, cx);
21765    }
21766
21767    /// Cancels an inline edit of a review comment.
21768    pub fn cancel_edit_review_comment(
21769        &mut self,
21770        comment_id: usize,
21771        _window: &mut Window,
21772        cx: &mut Context<Self>,
21773    ) {
21774        // Find which hunk this comment belongs to
21775        let hunk_key = self
21776            .stored_review_comments
21777            .iter()
21778            .find_map(|(key, comments)| {
21779                if comments.iter().any(|c| c.id == comment_id) {
21780                    Some(key.clone())
21781                } else {
21782                    None
21783                }
21784            });
21785
21786        // Remove the inline editor and its subscription
21787        if let Some(hunk_key) = hunk_key {
21788            let snapshot = self.buffer.read(cx).snapshot(cx);
21789            if let Some(overlay) = self
21790                .diff_review_overlays
21791                .iter_mut()
21792                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21793            {
21794                overlay.inline_edit_editors.remove(&comment_id);
21795                overlay.inline_edit_subscriptions.remove(&comment_id);
21796            }
21797        }
21798
21799        // Clear editing state
21800        self.set_comment_editing(comment_id, false, cx);
21801    }
21802
21803    /// Action handler for ConfirmEditReviewComment.
21804    pub fn confirm_edit_review_comment_action(
21805        &mut self,
21806        action: &ConfirmEditReviewComment,
21807        window: &mut Window,
21808        cx: &mut Context<Self>,
21809    ) {
21810        self.confirm_edit_review_comment(action.id, window, cx);
21811    }
21812
21813    /// Action handler for CancelEditReviewComment.
21814    pub fn cancel_edit_review_comment_action(
21815        &mut self,
21816        action: &CancelEditReviewComment,
21817        window: &mut Window,
21818        cx: &mut Context<Self>,
21819    ) {
21820        self.cancel_edit_review_comment(action.id, window, cx);
21821    }
21822
21823    /// Handles the DeleteReviewComment action - removes a comment.
21824    pub fn delete_review_comment(
21825        &mut self,
21826        action: &DeleteReviewComment,
21827        window: &mut Window,
21828        cx: &mut Context<Self>,
21829    ) {
21830        // Get the hunk key before removing the comment
21831        // Find the hunk key from the comment itself
21832        let comment_id = action.id;
21833        let hunk_key = self
21834            .stored_review_comments
21835            .iter()
21836            .find_map(|(key, comments)| {
21837                if comments.iter().any(|c| c.id == comment_id) {
21838                    Some(key.clone())
21839                } else {
21840                    None
21841                }
21842            });
21843
21844        // Also get it from the overlay for refresh purposes
21845        let overlay_hunk_key = self
21846            .diff_review_overlays
21847            .first()
21848            .map(|o| o.hunk_key.clone());
21849
21850        self.remove_review_comment(action.id, cx);
21851
21852        // Refresh the overlay height after removing a comment
21853        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
21854            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21855        }
21856    }
21857
21858    fn render_diff_review_overlay(
21859        prompt_editor: &Entity<Editor>,
21860        hunk_key: &DiffHunkKey,
21861        editor_handle: &WeakEntity<Editor>,
21862        cx: &mut BlockContext,
21863    ) -> AnyElement {
21864        let theme = cx.theme();
21865        let colors = theme.colors();
21866
21867        // Get stored comments, expanded state, inline editors, and user avatar from the editor
21868        let (comments, comments_expanded, inline_editors, user_avatar_uri) = editor_handle
21869            .upgrade()
21870            .map(|editor| {
21871                let editor = editor.read(cx);
21872                let snapshot = editor.buffer().read(cx).snapshot(cx);
21873                let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
21874                let snapshot = editor.buffer.read(cx).snapshot(cx);
21875                let (expanded, editors, avatar_uri) = editor
21876                    .diff_review_overlays
21877                    .iter()
21878                    .find(|overlay| Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21879                    .as_ref()
21880                    .map(|o| {
21881                        (
21882                            o.comments_expanded,
21883                            o.inline_edit_editors.clone(),
21884                            o.user_avatar_uri.clone(),
21885                        )
21886                    })
21887                    .unwrap_or((true, HashMap::default(), None));
21888                (comments, expanded, editors, avatar_uri)
21889            })
21890            .unwrap_or((Vec::new(), true, HashMap::default(), None));
21891
21892        let comment_count = comments.len();
21893        let avatar_size = px(20.);
21894        let action_icon_size = IconSize::XSmall;
21895
21896        v_flex()
21897            .w_full()
21898            .bg(colors.editor_background)
21899            .border_b_1()
21900            .border_color(colors.border)
21901            .px_2()
21902            .pb_2()
21903            .gap_2()
21904            // Top row: editable input with user's avatar
21905            .child(
21906                h_flex()
21907                    .w_full()
21908                    .items_center()
21909                    .gap_2()
21910                    .px_2()
21911                    .py_1p5()
21912                    .rounded_md()
21913                    .bg(colors.surface_background)
21914                    .child(
21915                        div()
21916                            .size(avatar_size)
21917                            .flex_shrink_0()
21918                            .rounded_full()
21919                            .overflow_hidden()
21920                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
21921                                Avatar::new(avatar_uri.clone())
21922                                    .size(avatar_size)
21923                                    .into_any_element()
21924                            } else {
21925                                Icon::new(IconName::Person)
21926                                    .size(IconSize::Small)
21927                                    .color(ui::Color::Muted)
21928                                    .into_any_element()
21929                            }),
21930                    )
21931                    .child(
21932                        div()
21933                            .flex_1()
21934                            .border_1()
21935                            .border_color(colors.border)
21936                            .rounded_md()
21937                            .bg(colors.editor_background)
21938                            .px_2()
21939                            .py_1()
21940                            .child(prompt_editor.clone()),
21941                    )
21942                    .child(
21943                        h_flex()
21944                            .flex_shrink_0()
21945                            .gap_1()
21946                            .child(
21947                                IconButton::new("diff-review-close", IconName::Close)
21948                                    .icon_color(ui::Color::Muted)
21949                                    .icon_size(action_icon_size)
21950                                    .tooltip(Tooltip::text("Close"))
21951                                    .on_click(|_, window, cx| {
21952                                        window
21953                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
21954                                    }),
21955                            )
21956                            .child(
21957                                IconButton::new("diff-review-add", IconName::Return)
21958                                    .icon_color(ui::Color::Muted)
21959                                    .icon_size(action_icon_size)
21960                                    .tooltip(Tooltip::text("Add comment"))
21961                                    .on_click(|_, window, cx| {
21962                                        window.dispatch_action(
21963                                            Box::new(crate::actions::SubmitDiffReviewComment),
21964                                            cx,
21965                                        );
21966                                    }),
21967                            ),
21968                    ),
21969            )
21970            // Expandable comments section (only shown when there are comments)
21971            .when(comment_count > 0, |el| {
21972                el.child(Self::render_comments_section(
21973                    comments,
21974                    comments_expanded,
21975                    inline_editors,
21976                    user_avatar_uri,
21977                    avatar_size,
21978                    action_icon_size,
21979                    colors,
21980                ))
21981            })
21982            .into_any_element()
21983    }
21984
21985    fn render_comments_section(
21986        comments: Vec<StoredReviewComment>,
21987        expanded: bool,
21988        inline_editors: HashMap<usize, Entity<Editor>>,
21989        user_avatar_uri: Option<SharedUri>,
21990        avatar_size: Pixels,
21991        action_icon_size: IconSize,
21992        colors: &theme::ThemeColors,
21993    ) -> impl IntoElement {
21994        let comment_count = comments.len();
21995
21996        v_flex()
21997            .w_full()
21998            .gap_1()
21999            // Header with expand/collapse toggle
22000            .child(
22001                h_flex()
22002                    .id("review-comments-header")
22003                    .w_full()
22004                    .items_center()
22005                    .gap_1()
22006                    .px_2()
22007                    .py_1()
22008                    .cursor_pointer()
22009                    .rounded_md()
22010                    .hover(|style| style.bg(colors.ghost_element_hover))
22011                    .on_click(|_, window: &mut Window, cx| {
22012                        window.dispatch_action(
22013                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22014                            cx,
22015                        );
22016                    })
22017                    .child(
22018                        Icon::new(if expanded {
22019                            IconName::ChevronDown
22020                        } else {
22021                            IconName::ChevronRight
22022                        })
22023                        .size(IconSize::Small)
22024                        .color(ui::Color::Muted),
22025                    )
22026                    .child(
22027                        Label::new(format!(
22028                            "{} Comment{}",
22029                            comment_count,
22030                            if comment_count == 1 { "" } else { "s" }
22031                        ))
22032                        .size(LabelSize::Small)
22033                        .color(Color::Muted),
22034                    ),
22035            )
22036            // Comments list (when expanded)
22037            .when(expanded, |el| {
22038                el.children(comments.into_iter().map(|comment| {
22039                    let inline_editor = inline_editors.get(&comment.id).cloned();
22040                    Self::render_comment_row(
22041                        comment,
22042                        inline_editor,
22043                        user_avatar_uri.clone(),
22044                        avatar_size,
22045                        action_icon_size,
22046                        colors,
22047                    )
22048                }))
22049            })
22050    }
22051
22052    fn render_comment_row(
22053        comment: StoredReviewComment,
22054        inline_editor: Option<Entity<Editor>>,
22055        user_avatar_uri: Option<SharedUri>,
22056        avatar_size: Pixels,
22057        action_icon_size: IconSize,
22058        colors: &theme::ThemeColors,
22059    ) -> impl IntoElement {
22060        let comment_id = comment.id;
22061        let is_editing = inline_editor.is_some();
22062
22063        h_flex()
22064            .w_full()
22065            .items_center()
22066            .gap_2()
22067            .px_2()
22068            .py_1p5()
22069            .rounded_md()
22070            .bg(colors.surface_background)
22071            .child(
22072                div()
22073                    .size(avatar_size)
22074                    .flex_shrink_0()
22075                    .rounded_full()
22076                    .overflow_hidden()
22077                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22078                        Avatar::new(avatar_uri.clone())
22079                            .size(avatar_size)
22080                            .into_any_element()
22081                    } else {
22082                        Icon::new(IconName::Person)
22083                            .size(IconSize::Small)
22084                            .color(ui::Color::Muted)
22085                            .into_any_element()
22086                    }),
22087            )
22088            .child(if let Some(editor) = inline_editor {
22089                // Inline edit mode: show an editable text field
22090                div()
22091                    .flex_1()
22092                    .border_1()
22093                    .border_color(colors.border)
22094                    .rounded_md()
22095                    .bg(colors.editor_background)
22096                    .px_2()
22097                    .py_1()
22098                    .child(editor)
22099                    .into_any_element()
22100            } else {
22101                // Display mode: show the comment text
22102                div()
22103                    .flex_1()
22104                    .text_sm()
22105                    .text_color(colors.text)
22106                    .child(comment.comment)
22107                    .into_any_element()
22108            })
22109            .child(if is_editing {
22110                // Editing mode: show close and confirm buttons
22111                h_flex()
22112                    .gap_1()
22113                    .child(
22114                        IconButton::new(
22115                            format!("diff-review-cancel-edit-{comment_id}"),
22116                            IconName::Close,
22117                        )
22118                        .icon_color(ui::Color::Muted)
22119                        .icon_size(action_icon_size)
22120                        .tooltip(Tooltip::text("Cancel"))
22121                        .on_click(move |_, window, cx| {
22122                            window.dispatch_action(
22123                                Box::new(crate::actions::CancelEditReviewComment {
22124                                    id: comment_id,
22125                                }),
22126                                cx,
22127                            );
22128                        }),
22129                    )
22130                    .child(
22131                        IconButton::new(
22132                            format!("diff-review-confirm-edit-{comment_id}"),
22133                            IconName::Return,
22134                        )
22135                        .icon_color(ui::Color::Muted)
22136                        .icon_size(action_icon_size)
22137                        .tooltip(Tooltip::text("Confirm"))
22138                        .on_click(move |_, window, cx| {
22139                            window.dispatch_action(
22140                                Box::new(crate::actions::ConfirmEditReviewComment {
22141                                    id: comment_id,
22142                                }),
22143                                cx,
22144                            );
22145                        }),
22146                    )
22147                    .into_any_element()
22148            } else {
22149                // Display mode: no action buttons for now (edit/delete not yet implemented)
22150                gpui::Empty.into_any_element()
22151            })
22152    }
22153
22154    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22155        if self.display_map.read(cx).masked != masked {
22156            self.display_map.update(cx, |map, _| map.masked = masked);
22157        }
22158        cx.notify()
22159    }
22160
22161    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22162        self.show_wrap_guides = Some(show_wrap_guides);
22163        cx.notify();
22164    }
22165
22166    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22167        self.show_indent_guides = Some(show_indent_guides);
22168        cx.notify();
22169    }
22170
22171    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22172        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22173            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22174                && let Some(dir) = file.abs_path(cx).parent()
22175            {
22176                return Some(dir.to_owned());
22177            }
22178        }
22179
22180        None
22181    }
22182
22183    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22184        self.active_excerpt(cx)?
22185            .1
22186            .read(cx)
22187            .file()
22188            .and_then(|f| f.as_local())
22189    }
22190
22191    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22192        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22193            let buffer = buffer.read(cx);
22194            if let Some(project_path) = buffer.project_path(cx) {
22195                let project = self.project()?.read(cx);
22196                project.absolute_path(&project_path, cx)
22197            } else {
22198                buffer
22199                    .file()
22200                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22201            }
22202        })
22203    }
22204
22205    pub fn reveal_in_finder(
22206        &mut self,
22207        _: &RevealInFileManager,
22208        _window: &mut Window,
22209        cx: &mut Context<Self>,
22210    ) {
22211        if let Some(target) = self.target_file(cx) {
22212            cx.reveal_path(&target.abs_path(cx));
22213        }
22214    }
22215
22216    pub fn copy_path(
22217        &mut self,
22218        _: &zed_actions::workspace::CopyPath,
22219        _window: &mut Window,
22220        cx: &mut Context<Self>,
22221    ) {
22222        if let Some(path) = self.target_file_abs_path(cx)
22223            && let Some(path) = path.to_str()
22224        {
22225            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22226        } else {
22227            cx.propagate();
22228        }
22229    }
22230
22231    pub fn copy_relative_path(
22232        &mut self,
22233        _: &zed_actions::workspace::CopyRelativePath,
22234        _window: &mut Window,
22235        cx: &mut Context<Self>,
22236    ) {
22237        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22238            let project = self.project()?.read(cx);
22239            let path = buffer.read(cx).file()?.path();
22240            let path = path.display(project.path_style(cx));
22241            Some(path)
22242        }) {
22243            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22244        } else {
22245            cx.propagate();
22246        }
22247    }
22248
22249    /// Returns the project path for the editor's buffer, if any buffer is
22250    /// opened in the editor.
22251    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
22252        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
22253            buffer.read(cx).project_path(cx)
22254        } else {
22255            None
22256        }
22257    }
22258
22259    // Returns true if the editor handled a go-to-line request
22260    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
22261        maybe!({
22262            let breakpoint_store = self.breakpoint_store.as_ref()?;
22263
22264            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
22265            else {
22266                self.clear_row_highlights::<ActiveDebugLine>();
22267                return None;
22268            };
22269
22270            let position = active_stack_frame.position;
22271            let buffer_id = position.buffer_id?;
22272            let snapshot = self
22273                .project
22274                .as_ref()?
22275                .read(cx)
22276                .buffer_for_id(buffer_id, cx)?
22277                .read(cx)
22278                .snapshot();
22279
22280            let mut handled = false;
22281            for (id, ExcerptRange { context, .. }) in
22282                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
22283            {
22284                if context.start.cmp(&position, &snapshot).is_ge()
22285                    || context.end.cmp(&position, &snapshot).is_lt()
22286                {
22287                    continue;
22288                }
22289                let snapshot = self.buffer.read(cx).snapshot(cx);
22290                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
22291
22292                handled = true;
22293                self.clear_row_highlights::<ActiveDebugLine>();
22294
22295                self.go_to_line::<ActiveDebugLine>(
22296                    multibuffer_anchor,
22297                    Some(cx.theme().colors().editor_debugger_active_line_background),
22298                    window,
22299                    cx,
22300                );
22301
22302                cx.notify();
22303            }
22304
22305            handled.then_some(())
22306        })
22307        .is_some()
22308    }
22309
22310    pub fn copy_file_name_without_extension(
22311        &mut self,
22312        _: &CopyFileNameWithoutExtension,
22313        _: &mut Window,
22314        cx: &mut Context<Self>,
22315    ) {
22316        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22317            let file = buffer.read(cx).file()?;
22318            file.path().file_stem()
22319        }) {
22320            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
22321        }
22322    }
22323
22324    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
22325        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22326            let file = buffer.read(cx).file()?;
22327            Some(file.file_name(cx))
22328        }) {
22329            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
22330        }
22331    }
22332
22333    pub fn toggle_git_blame(
22334        &mut self,
22335        _: &::git::Blame,
22336        window: &mut Window,
22337        cx: &mut Context<Self>,
22338    ) {
22339        self.show_git_blame_gutter = !self.show_git_blame_gutter;
22340
22341        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
22342            self.start_git_blame(true, window, cx);
22343        }
22344
22345        cx.notify();
22346    }
22347
22348    pub fn toggle_git_blame_inline(
22349        &mut self,
22350        _: &ToggleGitBlameInline,
22351        window: &mut Window,
22352        cx: &mut Context<Self>,
22353    ) {
22354        self.toggle_git_blame_inline_internal(true, window, cx);
22355        cx.notify();
22356    }
22357
22358    pub fn open_git_blame_commit(
22359        &mut self,
22360        _: &OpenGitBlameCommit,
22361        window: &mut Window,
22362        cx: &mut Context<Self>,
22363    ) {
22364        self.open_git_blame_commit_internal(window, cx);
22365    }
22366
22367    fn open_git_blame_commit_internal(
22368        &mut self,
22369        window: &mut Window,
22370        cx: &mut Context<Self>,
22371    ) -> Option<()> {
22372        let blame = self.blame.as_ref()?;
22373        let snapshot = self.snapshot(window, cx);
22374        let cursor = self
22375            .selections
22376            .newest::<Point>(&snapshot.display_snapshot)
22377            .head();
22378        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
22379        let (_, blame_entry) = blame
22380            .update(cx, |blame, cx| {
22381                blame
22382                    .blame_for_rows(
22383                        &[RowInfo {
22384                            buffer_id: Some(buffer.remote_id()),
22385                            buffer_row: Some(point.row),
22386                            ..Default::default()
22387                        }],
22388                        cx,
22389                    )
22390                    .next()
22391            })
22392            .flatten()?;
22393        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22394        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
22395        let workspace = self.workspace()?.downgrade();
22396        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
22397        None
22398    }
22399
22400    pub fn git_blame_inline_enabled(&self) -> bool {
22401        self.git_blame_inline_enabled
22402    }
22403
22404    pub fn toggle_selection_menu(
22405        &mut self,
22406        _: &ToggleSelectionMenu,
22407        _: &mut Window,
22408        cx: &mut Context<Self>,
22409    ) {
22410        self.show_selection_menu = self
22411            .show_selection_menu
22412            .map(|show_selections_menu| !show_selections_menu)
22413            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
22414
22415        cx.notify();
22416    }
22417
22418    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
22419        self.show_selection_menu
22420            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
22421    }
22422
22423    fn start_git_blame(
22424        &mut self,
22425        user_triggered: bool,
22426        window: &mut Window,
22427        cx: &mut Context<Self>,
22428    ) {
22429        if let Some(project) = self.project() {
22430            if let Some(buffer) = self.buffer().read(cx).as_singleton()
22431                && buffer.read(cx).file().is_none()
22432            {
22433                return;
22434            }
22435
22436            let focused = self.focus_handle(cx).contains_focused(window, cx);
22437
22438            let project = project.clone();
22439            let blame = cx
22440                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
22441            self.blame_subscription =
22442                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
22443            self.blame = Some(blame);
22444        }
22445    }
22446
22447    fn toggle_git_blame_inline_internal(
22448        &mut self,
22449        user_triggered: bool,
22450        window: &mut Window,
22451        cx: &mut Context<Self>,
22452    ) {
22453        if self.git_blame_inline_enabled {
22454            self.git_blame_inline_enabled = false;
22455            self.show_git_blame_inline = false;
22456            self.show_git_blame_inline_delay_task.take();
22457        } else {
22458            self.git_blame_inline_enabled = true;
22459            self.start_git_blame_inline(user_triggered, window, cx);
22460        }
22461
22462        cx.notify();
22463    }
22464
22465    fn start_git_blame_inline(
22466        &mut self,
22467        user_triggered: bool,
22468        window: &mut Window,
22469        cx: &mut Context<Self>,
22470    ) {
22471        self.start_git_blame(user_triggered, window, cx);
22472
22473        if ProjectSettings::get_global(cx)
22474            .git
22475            .inline_blame_delay()
22476            .is_some()
22477        {
22478            self.start_inline_blame_timer(window, cx);
22479        } else {
22480            self.show_git_blame_inline = true
22481        }
22482    }
22483
22484    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
22485        self.blame.as_ref()
22486    }
22487
22488    pub fn show_git_blame_gutter(&self) -> bool {
22489        self.show_git_blame_gutter
22490    }
22491
22492    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
22493        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
22494    }
22495
22496    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
22497        self.show_git_blame_inline
22498            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
22499            && !self.newest_selection_head_on_empty_line(cx)
22500            && self.has_blame_entries(cx)
22501    }
22502
22503    fn has_blame_entries(&self, cx: &App) -> bool {
22504        self.blame()
22505            .is_some_and(|blame| blame.read(cx).has_generated_entries())
22506    }
22507
22508    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
22509        let cursor_anchor = self.selections.newest_anchor().head();
22510
22511        let snapshot = self.buffer.read(cx).snapshot(cx);
22512        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
22513
22514        snapshot.line_len(buffer_row) == 0
22515    }
22516
22517    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
22518        let buffer_and_selection = maybe!({
22519            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
22520            let selection_range = selection.range();
22521
22522            let multi_buffer = self.buffer().read(cx);
22523            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
22524            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
22525
22526            let (buffer, range, _) = if selection.reversed {
22527                buffer_ranges.first()
22528            } else {
22529                buffer_ranges.last()
22530            }?;
22531
22532            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
22533            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
22534
22535            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
22536                let selection = start_row_in_buffer..end_row_in_buffer;
22537
22538                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
22539            };
22540
22541            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
22542
22543            Some((
22544                multi_buffer.buffer(buffer.remote_id()).unwrap(),
22545                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, Bias::Left, buffer)
22546                    ..buffer_diff_snapshot.row_to_base_text_row(
22547                        end_row_in_buffer,
22548                        Bias::Left,
22549                        buffer,
22550                    ),
22551            ))
22552        });
22553
22554        let Some((buffer, selection)) = buffer_and_selection else {
22555            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
22556        };
22557
22558        let Some(project) = self.project() else {
22559            return Task::ready(Err(anyhow!("editor does not have project")));
22560        };
22561
22562        project.update(cx, |project, cx| {
22563            project.get_permalink_to_line(&buffer, selection, cx)
22564        })
22565    }
22566
22567    pub fn copy_permalink_to_line(
22568        &mut self,
22569        _: &CopyPermalinkToLine,
22570        window: &mut Window,
22571        cx: &mut Context<Self>,
22572    ) {
22573        let permalink_task = self.get_permalink_to_line(cx);
22574        let workspace = self.workspace();
22575
22576        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22577            Ok(permalink) => {
22578                cx.update(|_, cx| {
22579                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
22580                })
22581                .ok();
22582            }
22583            Err(err) => {
22584                let message = format!("Failed to copy permalink: {err}");
22585
22586                anyhow::Result::<()>::Err(err).log_err();
22587
22588                if let Some(workspace) = workspace {
22589                    workspace
22590                        .update_in(cx, |workspace, _, cx| {
22591                            struct CopyPermalinkToLine;
22592
22593                            workspace.show_toast(
22594                                Toast::new(
22595                                    NotificationId::unique::<CopyPermalinkToLine>(),
22596                                    message,
22597                                ),
22598                                cx,
22599                            )
22600                        })
22601                        .ok();
22602                }
22603            }
22604        })
22605        .detach();
22606    }
22607
22608    pub fn copy_file_location(
22609        &mut self,
22610        _: &CopyFileLocation,
22611        _: &mut Window,
22612        cx: &mut Context<Self>,
22613    ) {
22614        let selection = self
22615            .selections
22616            .newest::<Point>(&self.display_snapshot(cx))
22617            .start
22618            .row
22619            + 1;
22620        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22621            let project = self.project()?.read(cx);
22622            let file = buffer.read(cx).file()?;
22623            let path = file.path().display(project.path_style(cx));
22624
22625            Some(format!("{path}:{selection}"))
22626        }) {
22627            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
22628        }
22629    }
22630
22631    pub fn open_permalink_to_line(
22632        &mut self,
22633        _: &OpenPermalinkToLine,
22634        window: &mut Window,
22635        cx: &mut Context<Self>,
22636    ) {
22637        let permalink_task = self.get_permalink_to_line(cx);
22638        let workspace = self.workspace();
22639
22640        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22641            Ok(permalink) => {
22642                cx.update(|_, cx| {
22643                    cx.open_url(permalink.as_ref());
22644                })
22645                .ok();
22646            }
22647            Err(err) => {
22648                let message = format!("Failed to open permalink: {err}");
22649
22650                anyhow::Result::<()>::Err(err).log_err();
22651
22652                if let Some(workspace) = workspace {
22653                    workspace.update(cx, |workspace, cx| {
22654                        struct OpenPermalinkToLine;
22655
22656                        workspace.show_toast(
22657                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
22658                            cx,
22659                        )
22660                    });
22661                }
22662            }
22663        })
22664        .detach();
22665    }
22666
22667    pub fn insert_uuid_v4(
22668        &mut self,
22669        _: &InsertUuidV4,
22670        window: &mut Window,
22671        cx: &mut Context<Self>,
22672    ) {
22673        self.insert_uuid(UuidVersion::V4, window, cx);
22674    }
22675
22676    pub fn insert_uuid_v7(
22677        &mut self,
22678        _: &InsertUuidV7,
22679        window: &mut Window,
22680        cx: &mut Context<Self>,
22681    ) {
22682        self.insert_uuid(UuidVersion::V7, window, cx);
22683    }
22684
22685    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
22686        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
22687        self.transact(window, cx, |this, window, cx| {
22688            let edits = this
22689                .selections
22690                .all::<Point>(&this.display_snapshot(cx))
22691                .into_iter()
22692                .map(|selection| {
22693                    let uuid = match version {
22694                        UuidVersion::V4 => uuid::Uuid::new_v4(),
22695                        UuidVersion::V7 => uuid::Uuid::now_v7(),
22696                    };
22697
22698                    (selection.range(), uuid.to_string())
22699                });
22700            this.edit(edits, cx);
22701            this.refresh_edit_prediction(true, false, window, cx);
22702        });
22703    }
22704
22705    pub fn open_selections_in_multibuffer(
22706        &mut self,
22707        _: &OpenSelectionsInMultibuffer,
22708        window: &mut Window,
22709        cx: &mut Context<Self>,
22710    ) {
22711        let multibuffer = self.buffer.read(cx);
22712
22713        let Some(buffer) = multibuffer.as_singleton() else {
22714            return;
22715        };
22716
22717        let Some(workspace) = self.workspace() else {
22718            return;
22719        };
22720
22721        let title = multibuffer.title(cx).to_string();
22722
22723        let locations = self
22724            .selections
22725            .all_anchors(&self.display_snapshot(cx))
22726            .iter()
22727            .map(|selection| {
22728                (
22729                    buffer.clone(),
22730                    (selection.start.text_anchor..selection.end.text_anchor)
22731                        .to_point(buffer.read(cx)),
22732                )
22733            })
22734            .into_group_map();
22735
22736        cx.spawn_in(window, async move |_, cx| {
22737            workspace.update_in(cx, |workspace, window, cx| {
22738                Self::open_locations_in_multibuffer(
22739                    workspace,
22740                    locations,
22741                    format!("Selections for '{title}'"),
22742                    false,
22743                    false,
22744                    MultibufferSelectionMode::All,
22745                    window,
22746                    cx,
22747                );
22748            })
22749        })
22750        .detach();
22751    }
22752
22753    /// Adds a row highlight for the given range. If a row has multiple highlights, the
22754    /// last highlight added will be used.
22755    ///
22756    /// If the range ends at the beginning of a line, then that line will not be highlighted.
22757    pub fn highlight_rows<T: 'static>(
22758        &mut self,
22759        range: Range<Anchor>,
22760        color: Hsla,
22761        options: RowHighlightOptions,
22762        cx: &mut Context<Self>,
22763    ) {
22764        let snapshot = self.buffer().read(cx).snapshot(cx);
22765        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
22766        let ix = row_highlights.binary_search_by(|highlight| {
22767            Ordering::Equal
22768                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
22769                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
22770        });
22771
22772        if let Err(mut ix) = ix {
22773            let index = post_inc(&mut self.highlight_order);
22774
22775            // If this range intersects with the preceding highlight, then merge it with
22776            // the preceding highlight. Otherwise insert a new highlight.
22777            let mut merged = false;
22778            if ix > 0 {
22779                let prev_highlight = &mut row_highlights[ix - 1];
22780                if prev_highlight
22781                    .range
22782                    .end
22783                    .cmp(&range.start, &snapshot)
22784                    .is_ge()
22785                {
22786                    ix -= 1;
22787                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
22788                        prev_highlight.range.end = range.end;
22789                    }
22790                    merged = true;
22791                    prev_highlight.index = index;
22792                    prev_highlight.color = color;
22793                    prev_highlight.options = options;
22794                }
22795            }
22796
22797            if !merged {
22798                row_highlights.insert(
22799                    ix,
22800                    RowHighlight {
22801                        range,
22802                        index,
22803                        color,
22804                        options,
22805                        type_id: TypeId::of::<T>(),
22806                    },
22807                );
22808            }
22809
22810            // If any of the following highlights intersect with this one, merge them.
22811            while let Some(next_highlight) = row_highlights.get(ix + 1) {
22812                let highlight = &row_highlights[ix];
22813                if next_highlight
22814                    .range
22815                    .start
22816                    .cmp(&highlight.range.end, &snapshot)
22817                    .is_le()
22818                {
22819                    if next_highlight
22820                        .range
22821                        .end
22822                        .cmp(&highlight.range.end, &snapshot)
22823                        .is_gt()
22824                    {
22825                        row_highlights[ix].range.end = next_highlight.range.end;
22826                    }
22827                    row_highlights.remove(ix + 1);
22828                } else {
22829                    break;
22830                }
22831            }
22832        }
22833    }
22834
22835    /// Remove any highlighted row ranges of the given type that intersect the
22836    /// given ranges.
22837    pub fn remove_highlighted_rows<T: 'static>(
22838        &mut self,
22839        ranges_to_remove: Vec<Range<Anchor>>,
22840        cx: &mut Context<Self>,
22841    ) {
22842        let snapshot = self.buffer().read(cx).snapshot(cx);
22843        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
22844        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
22845        row_highlights.retain(|highlight| {
22846            while let Some(range_to_remove) = ranges_to_remove.peek() {
22847                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
22848                    Ordering::Less | Ordering::Equal => {
22849                        ranges_to_remove.next();
22850                    }
22851                    Ordering::Greater => {
22852                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
22853                            Ordering::Less | Ordering::Equal => {
22854                                return false;
22855                            }
22856                            Ordering::Greater => break,
22857                        }
22858                    }
22859                }
22860            }
22861
22862            true
22863        })
22864    }
22865
22866    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
22867    pub fn clear_row_highlights<T: 'static>(&mut self) {
22868        self.highlighted_rows.remove(&TypeId::of::<T>());
22869    }
22870
22871    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
22872    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
22873        self.highlighted_rows
22874            .get(&TypeId::of::<T>())
22875            .map_or(&[] as &[_], |vec| vec.as_slice())
22876            .iter()
22877            .map(|highlight| (highlight.range.clone(), highlight.color))
22878    }
22879
22880    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
22881    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
22882    /// Allows to ignore certain kinds of highlights.
22883    pub fn highlighted_display_rows(
22884        &self,
22885        window: &mut Window,
22886        cx: &mut App,
22887    ) -> BTreeMap<DisplayRow, LineHighlight> {
22888        let snapshot = self.snapshot(window, cx);
22889        let mut used_highlight_orders = HashMap::default();
22890        self.highlighted_rows
22891            .iter()
22892            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
22893            .fold(
22894                BTreeMap::<DisplayRow, LineHighlight>::new(),
22895                |mut unique_rows, highlight| {
22896                    let start = highlight.range.start.to_display_point(&snapshot);
22897                    let end = highlight.range.end.to_display_point(&snapshot);
22898                    let start_row = start.row().0;
22899                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
22900                    {
22901                        end.row().0.saturating_sub(1)
22902                    } else {
22903                        end.row().0
22904                    };
22905                    for row in start_row..=end_row {
22906                        let used_index =
22907                            used_highlight_orders.entry(row).or_insert(highlight.index);
22908                        if highlight.index >= *used_index {
22909                            *used_index = highlight.index;
22910                            unique_rows.insert(
22911                                DisplayRow(row),
22912                                LineHighlight {
22913                                    include_gutter: highlight.options.include_gutter,
22914                                    border: None,
22915                                    background: highlight.color.into(),
22916                                    type_id: Some(highlight.type_id),
22917                                },
22918                            );
22919                        }
22920                    }
22921                    unique_rows
22922                },
22923            )
22924    }
22925
22926    pub fn highlighted_display_row_for_autoscroll(
22927        &self,
22928        snapshot: &DisplaySnapshot,
22929    ) -> Option<DisplayRow> {
22930        self.highlighted_rows
22931            .values()
22932            .flat_map(|highlighted_rows| highlighted_rows.iter())
22933            .filter_map(|highlight| {
22934                if highlight.options.autoscroll {
22935                    Some(highlight.range.start.to_display_point(snapshot).row())
22936                } else {
22937                    None
22938                }
22939            })
22940            .min()
22941    }
22942
22943    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
22944        self.highlight_background::<SearchWithinRange>(
22945            ranges,
22946            |_, colors| colors.colors().editor_document_highlight_read_background,
22947            cx,
22948        )
22949    }
22950
22951    pub fn set_breadcrumb_header(&mut self, new_header: String) {
22952        self.breadcrumb_header = Some(new_header);
22953    }
22954
22955    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
22956        self.clear_background_highlights::<SearchWithinRange>(cx);
22957    }
22958
22959    pub fn highlight_background<T: 'static>(
22960        &mut self,
22961        ranges: &[Range<Anchor>],
22962        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
22963        cx: &mut Context<Self>,
22964    ) {
22965        self.background_highlights.insert(
22966            HighlightKey::Type(TypeId::of::<T>()),
22967            (Arc::new(color_fetcher), Arc::from(ranges)),
22968        );
22969        self.scrollbar_marker_state.dirty = true;
22970        cx.notify();
22971    }
22972
22973    pub fn highlight_background_key<T: 'static>(
22974        &mut self,
22975        key: usize,
22976        ranges: &[Range<Anchor>],
22977        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
22978        cx: &mut Context<Self>,
22979    ) {
22980        self.background_highlights.insert(
22981            HighlightKey::TypePlus(TypeId::of::<T>(), key),
22982            (Arc::new(color_fetcher), Arc::from(ranges)),
22983        );
22984        self.scrollbar_marker_state.dirty = true;
22985        cx.notify();
22986    }
22987
22988    pub fn clear_background_highlights<T: 'static>(
22989        &mut self,
22990        cx: &mut Context<Self>,
22991    ) -> Option<BackgroundHighlight> {
22992        let text_highlights = self
22993            .background_highlights
22994            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
22995        if !text_highlights.1.is_empty() {
22996            self.scrollbar_marker_state.dirty = true;
22997            cx.notify();
22998        }
22999        Some(text_highlights)
23000    }
23001
23002    pub fn highlight_gutter<T: 'static>(
23003        &mut self,
23004        ranges: impl Into<Vec<Range<Anchor>>>,
23005        color_fetcher: fn(&App) -> Hsla,
23006        cx: &mut Context<Self>,
23007    ) {
23008        self.gutter_highlights
23009            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23010        cx.notify();
23011    }
23012
23013    pub fn clear_gutter_highlights<T: 'static>(
23014        &mut self,
23015        cx: &mut Context<Self>,
23016    ) -> Option<GutterHighlight> {
23017        cx.notify();
23018        self.gutter_highlights.remove(&TypeId::of::<T>())
23019    }
23020
23021    pub fn insert_gutter_highlight<T: 'static>(
23022        &mut self,
23023        range: Range<Anchor>,
23024        color_fetcher: fn(&App) -> Hsla,
23025        cx: &mut Context<Self>,
23026    ) {
23027        let snapshot = self.buffer().read(cx).snapshot(cx);
23028        let mut highlights = self
23029            .gutter_highlights
23030            .remove(&TypeId::of::<T>())
23031            .map(|(_, highlights)| highlights)
23032            .unwrap_or_default();
23033        let ix = highlights.binary_search_by(|highlight| {
23034            Ordering::Equal
23035                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23036                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23037        });
23038        if let Err(ix) = ix {
23039            highlights.insert(ix, range);
23040        }
23041        self.gutter_highlights
23042            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23043    }
23044
23045    pub fn remove_gutter_highlights<T: 'static>(
23046        &mut self,
23047        ranges_to_remove: Vec<Range<Anchor>>,
23048        cx: &mut Context<Self>,
23049    ) {
23050        let snapshot = self.buffer().read(cx).snapshot(cx);
23051        let Some((color_fetcher, mut gutter_highlights)) =
23052            self.gutter_highlights.remove(&TypeId::of::<T>())
23053        else {
23054            return;
23055        };
23056        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23057        gutter_highlights.retain(|highlight| {
23058            while let Some(range_to_remove) = ranges_to_remove.peek() {
23059                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23060                    Ordering::Less | Ordering::Equal => {
23061                        ranges_to_remove.next();
23062                    }
23063                    Ordering::Greater => {
23064                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23065                            Ordering::Less | Ordering::Equal => {
23066                                return false;
23067                            }
23068                            Ordering::Greater => break,
23069                        }
23070                    }
23071                }
23072            }
23073
23074            true
23075        });
23076        self.gutter_highlights
23077            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23078    }
23079
23080    #[cfg(feature = "test-support")]
23081    pub fn all_text_highlights(
23082        &self,
23083        window: &mut Window,
23084        cx: &mut Context<Self>,
23085    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23086        let snapshot = self.snapshot(window, cx);
23087        self.display_map.update(cx, |display_map, _| {
23088            display_map
23089                .all_text_highlights()
23090                .map(|highlight| {
23091                    let (style, ranges) = highlight.as_ref();
23092                    (
23093                        *style,
23094                        ranges
23095                            .iter()
23096                            .map(|range| range.clone().to_display_points(&snapshot))
23097                            .collect(),
23098                    )
23099                })
23100                .collect()
23101        })
23102    }
23103
23104    #[cfg(feature = "test-support")]
23105    pub fn all_text_background_highlights(
23106        &self,
23107        window: &mut Window,
23108        cx: &mut Context<Self>,
23109    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23110        let snapshot = self.snapshot(window, cx);
23111        let buffer = &snapshot.buffer_snapshot();
23112        let start = buffer.anchor_before(MultiBufferOffset(0));
23113        let end = buffer.anchor_after(buffer.len());
23114        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23115    }
23116
23117    #[cfg(any(test, feature = "test-support"))]
23118    pub fn sorted_background_highlights_in_range(
23119        &self,
23120        search_range: Range<Anchor>,
23121        display_snapshot: &DisplaySnapshot,
23122        theme: &Theme,
23123    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23124        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23125        res.sort_by(|a, b| {
23126            a.0.start
23127                .cmp(&b.0.start)
23128                .then_with(|| a.0.end.cmp(&b.0.end))
23129                .then_with(|| a.1.cmp(&b.1))
23130        });
23131        res
23132    }
23133
23134    #[cfg(feature = "test-support")]
23135    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23136        let snapshot = self.buffer().read(cx).snapshot(cx);
23137
23138        let highlights = self
23139            .background_highlights
23140            .get(&HighlightKey::Type(TypeId::of::<
23141                items::BufferSearchHighlights,
23142            >()));
23143
23144        if let Some((_color, ranges)) = highlights {
23145            ranges
23146                .iter()
23147                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23148                .collect_vec()
23149        } else {
23150            vec![]
23151        }
23152    }
23153
23154    fn document_highlights_for_position<'a>(
23155        &'a self,
23156        position: Anchor,
23157        buffer: &'a MultiBufferSnapshot,
23158    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
23159        let read_highlights = self
23160            .background_highlights
23161            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
23162            .map(|h| &h.1);
23163        let write_highlights = self
23164            .background_highlights
23165            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
23166            .map(|h| &h.1);
23167        let left_position = position.bias_left(buffer);
23168        let right_position = position.bias_right(buffer);
23169        read_highlights
23170            .into_iter()
23171            .chain(write_highlights)
23172            .flat_map(move |ranges| {
23173                let start_ix = match ranges.binary_search_by(|probe| {
23174                    let cmp = probe.end.cmp(&left_position, buffer);
23175                    if cmp.is_ge() {
23176                        Ordering::Greater
23177                    } else {
23178                        Ordering::Less
23179                    }
23180                }) {
23181                    Ok(i) | Err(i) => i,
23182                };
23183
23184                ranges[start_ix..]
23185                    .iter()
23186                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
23187            })
23188    }
23189
23190    pub fn has_background_highlights<T: 'static>(&self) -> bool {
23191        self.background_highlights
23192            .get(&HighlightKey::Type(TypeId::of::<T>()))
23193            .is_some_and(|(_, highlights)| !highlights.is_empty())
23194    }
23195
23196    /// Returns all background highlights for a given range.
23197    ///
23198    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23199    pub fn background_highlights_in_range(
23200        &self,
23201        search_range: Range<Anchor>,
23202        display_snapshot: &DisplaySnapshot,
23203        theme: &Theme,
23204    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23205        let mut results = Vec::new();
23206        for (color_fetcher, ranges) in self.background_highlights.values() {
23207            let start_ix = match ranges.binary_search_by(|probe| {
23208                let cmp = probe
23209                    .end
23210                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23211                if cmp.is_gt() {
23212                    Ordering::Greater
23213                } else {
23214                    Ordering::Less
23215                }
23216            }) {
23217                Ok(i) | Err(i) => i,
23218            };
23219            for (index, range) in ranges[start_ix..].iter().enumerate() {
23220                if range
23221                    .start
23222                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23223                    .is_ge()
23224                {
23225                    break;
23226                }
23227
23228                let color = color_fetcher(&(start_ix + index), theme);
23229                let start = range.start.to_display_point(display_snapshot);
23230                let end = range.end.to_display_point(display_snapshot);
23231                results.push((start..end, color))
23232            }
23233        }
23234        results
23235    }
23236
23237    pub fn gutter_highlights_in_range(
23238        &self,
23239        search_range: Range<Anchor>,
23240        display_snapshot: &DisplaySnapshot,
23241        cx: &App,
23242    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23243        let mut results = Vec::new();
23244        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23245            let color = color_fetcher(cx);
23246            let start_ix = match ranges.binary_search_by(|probe| {
23247                let cmp = probe
23248                    .end
23249                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23250                if cmp.is_gt() {
23251                    Ordering::Greater
23252                } else {
23253                    Ordering::Less
23254                }
23255            }) {
23256                Ok(i) | Err(i) => i,
23257            };
23258            for range in &ranges[start_ix..] {
23259                if range
23260                    .start
23261                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23262                    .is_ge()
23263                {
23264                    break;
23265                }
23266
23267                let start = range.start.to_display_point(display_snapshot);
23268                let end = range.end.to_display_point(display_snapshot);
23269                results.push((start..end, color))
23270            }
23271        }
23272        results
23273    }
23274
23275    /// Get the text ranges corresponding to the redaction query
23276    pub fn redacted_ranges(
23277        &self,
23278        search_range: Range<Anchor>,
23279        display_snapshot: &DisplaySnapshot,
23280        cx: &App,
23281    ) -> Vec<Range<DisplayPoint>> {
23282        display_snapshot
23283            .buffer_snapshot()
23284            .redacted_ranges(search_range, |file| {
23285                if let Some(file) = file {
23286                    file.is_private()
23287                        && EditorSettings::get(
23288                            Some(SettingsLocation {
23289                                worktree_id: file.worktree_id(cx),
23290                                path: file.path().as_ref(),
23291                            }),
23292                            cx,
23293                        )
23294                        .redact_private_values
23295                } else {
23296                    false
23297                }
23298            })
23299            .map(|range| {
23300                range.start.to_display_point(display_snapshot)
23301                    ..range.end.to_display_point(display_snapshot)
23302            })
23303            .collect()
23304    }
23305
23306    pub fn highlight_text_key<T: 'static>(
23307        &mut self,
23308        key: usize,
23309        ranges: Vec<Range<Anchor>>,
23310        style: HighlightStyle,
23311        merge: bool,
23312        cx: &mut Context<Self>,
23313    ) {
23314        self.display_map.update(cx, |map, cx| {
23315            map.highlight_text(
23316                HighlightKey::TypePlus(TypeId::of::<T>(), key),
23317                ranges,
23318                style,
23319                merge,
23320                cx,
23321            );
23322        });
23323        cx.notify();
23324    }
23325
23326    pub fn highlight_text<T: 'static>(
23327        &mut self,
23328        ranges: Vec<Range<Anchor>>,
23329        style: HighlightStyle,
23330        cx: &mut Context<Self>,
23331    ) {
23332        self.display_map.update(cx, |map, cx| {
23333            map.highlight_text(
23334                HighlightKey::Type(TypeId::of::<T>()),
23335                ranges,
23336                style,
23337                false,
23338                cx,
23339            )
23340        });
23341        cx.notify();
23342    }
23343
23344    pub fn text_highlights<'a, T: 'static>(
23345        &'a self,
23346        cx: &'a App,
23347    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
23348        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
23349    }
23350
23351    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
23352        let cleared = self
23353            .display_map
23354            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
23355        if cleared {
23356            cx.notify();
23357        }
23358    }
23359
23360    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
23361        (self.read_only(cx) || self.blink_manager.read(cx).visible())
23362            && self.focus_handle.is_focused(window)
23363    }
23364
23365    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
23366        self.show_cursor_when_unfocused = is_enabled;
23367        cx.notify();
23368    }
23369
23370    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
23371        cx.notify();
23372    }
23373
23374    fn on_debug_session_event(
23375        &mut self,
23376        _session: Entity<Session>,
23377        event: &SessionEvent,
23378        cx: &mut Context<Self>,
23379    ) {
23380        if let SessionEvent::InvalidateInlineValue = event {
23381            self.refresh_inline_values(cx);
23382        }
23383    }
23384
23385    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
23386        let Some(project) = self.project.clone() else {
23387            return;
23388        };
23389
23390        if !self.inline_value_cache.enabled {
23391            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
23392            self.splice_inlays(&inlays, Vec::new(), cx);
23393            return;
23394        }
23395
23396        let current_execution_position = self
23397            .highlighted_rows
23398            .get(&TypeId::of::<ActiveDebugLine>())
23399            .and_then(|lines| lines.last().map(|line| line.range.end));
23400
23401        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
23402            let inline_values = editor
23403                .update(cx, |editor, cx| {
23404                    let Some(current_execution_position) = current_execution_position else {
23405                        return Some(Task::ready(Ok(Vec::new())));
23406                    };
23407
23408                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
23409                        let snapshot = buffer.snapshot(cx);
23410
23411                        let excerpt = snapshot.excerpt_containing(
23412                            current_execution_position..current_execution_position,
23413                        )?;
23414
23415                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
23416                    })?;
23417
23418                    let range =
23419                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
23420
23421                    project.inline_values(buffer, range, cx)
23422                })
23423                .ok()
23424                .flatten()?
23425                .await
23426                .context("refreshing debugger inlays")
23427                .log_err()?;
23428
23429            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
23430
23431            for (buffer_id, inline_value) in inline_values
23432                .into_iter()
23433                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
23434            {
23435                buffer_inline_values
23436                    .entry(buffer_id)
23437                    .or_default()
23438                    .push(inline_value);
23439            }
23440
23441            editor
23442                .update(cx, |editor, cx| {
23443                    let snapshot = editor.buffer.read(cx).snapshot(cx);
23444                    let mut new_inlays = Vec::default();
23445
23446                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
23447                        let buffer_id = buffer_snapshot.remote_id();
23448                        buffer_inline_values
23449                            .get(&buffer_id)
23450                            .into_iter()
23451                            .flatten()
23452                            .for_each(|hint| {
23453                                let inlay = Inlay::debugger(
23454                                    post_inc(&mut editor.next_inlay_id),
23455                                    Anchor::in_buffer(excerpt_id, hint.position),
23456                                    hint.text(),
23457                                );
23458                                if !inlay.text().chars().contains(&'\n') {
23459                                    new_inlays.push(inlay);
23460                                }
23461                            });
23462                    }
23463
23464                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
23465                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
23466
23467                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
23468                })
23469                .ok()?;
23470            Some(())
23471        });
23472    }
23473
23474    fn on_buffer_event(
23475        &mut self,
23476        multibuffer: &Entity<MultiBuffer>,
23477        event: &multi_buffer::Event,
23478        window: &mut Window,
23479        cx: &mut Context<Self>,
23480    ) {
23481        match event {
23482            multi_buffer::Event::Edited { edited_buffer } => {
23483                self.scrollbar_marker_state.dirty = true;
23484                self.active_indent_guides_state.dirty = true;
23485                self.refresh_active_diagnostics(cx);
23486                self.refresh_code_actions(window, cx);
23487                self.refresh_single_line_folds(window, cx);
23488                self.refresh_matching_bracket_highlights(window, cx);
23489                if self.has_active_edit_prediction() {
23490                    self.update_visible_edit_prediction(window, cx);
23491                }
23492
23493                // Clean up orphaned review comments after edits
23494                self.cleanup_orphaned_review_comments(cx);
23495
23496                if let Some(buffer) = edited_buffer {
23497                    if buffer.read(cx).file().is_none() {
23498                        cx.emit(EditorEvent::TitleChanged);
23499                    }
23500
23501                    if self.project.is_some() {
23502                        let buffer_id = buffer.read(cx).remote_id();
23503                        self.register_buffer(buffer_id, cx);
23504                        self.update_lsp_data(Some(buffer_id), window, cx);
23505                        self.refresh_inlay_hints(
23506                            InlayHintRefreshReason::BufferEdited(buffer_id),
23507                            cx,
23508                        );
23509                    }
23510                }
23511
23512                cx.emit(EditorEvent::BufferEdited);
23513                cx.emit(SearchEvent::MatchesInvalidated);
23514
23515                let Some(project) = &self.project else { return };
23516                let (telemetry, is_via_ssh) = {
23517                    let project = project.read(cx);
23518                    let telemetry = project.client().telemetry().clone();
23519                    let is_via_ssh = project.is_via_remote_server();
23520                    (telemetry, is_via_ssh)
23521                };
23522                telemetry.log_edit_event("editor", is_via_ssh);
23523            }
23524            multi_buffer::Event::ExcerptsAdded {
23525                buffer,
23526                predecessor,
23527                excerpts,
23528            } => {
23529                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23530                let buffer_id = buffer.read(cx).remote_id();
23531                if self.buffer.read(cx).diff_for(buffer_id).is_none()
23532                    && let Some(project) = &self.project
23533                {
23534                    update_uncommitted_diff_for_buffer(
23535                        cx.entity(),
23536                        project,
23537                        [buffer.clone()],
23538                        self.buffer.clone(),
23539                        cx,
23540                    )
23541                    .detach();
23542                }
23543                self.update_lsp_data(Some(buffer_id), window, cx);
23544                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23545                self.colorize_brackets(false, cx);
23546                self.refresh_selected_text_highlights(true, window, cx);
23547                cx.emit(EditorEvent::ExcerptsAdded {
23548                    buffer: buffer.clone(),
23549                    predecessor: *predecessor,
23550                    excerpts: excerpts.clone(),
23551                });
23552            }
23553            multi_buffer::Event::ExcerptsRemoved {
23554                ids,
23555                removed_buffer_ids,
23556            } => {
23557                if let Some(inlay_hints) = &mut self.inlay_hints {
23558                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
23559                }
23560                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
23561                for buffer_id in removed_buffer_ids {
23562                    self.registered_buffers.remove(buffer_id);
23563                }
23564                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23565                cx.emit(EditorEvent::ExcerptsRemoved {
23566                    ids: ids.clone(),
23567                    removed_buffer_ids: removed_buffer_ids.clone(),
23568                });
23569            }
23570            multi_buffer::Event::ExcerptsEdited {
23571                excerpt_ids,
23572                buffer_ids,
23573            } => {
23574                self.display_map.update(cx, |map, cx| {
23575                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
23576                });
23577                cx.emit(EditorEvent::ExcerptsEdited {
23578                    ids: excerpt_ids.clone(),
23579                });
23580            }
23581            multi_buffer::Event::ExcerptsExpanded { ids } => {
23582                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23583                self.refresh_document_highlights(cx);
23584                for id in ids {
23585                    self.fetched_tree_sitter_chunks.remove(id);
23586                }
23587                self.colorize_brackets(false, cx);
23588                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
23589            }
23590            multi_buffer::Event::Reparsed(buffer_id) => {
23591                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23592                self.refresh_selected_text_highlights(true, window, cx);
23593                self.colorize_brackets(true, cx);
23594                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23595
23596                cx.emit(EditorEvent::Reparsed(*buffer_id));
23597            }
23598            multi_buffer::Event::DiffHunksToggled => {
23599                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23600            }
23601            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
23602                if !is_fresh_language {
23603                    self.registered_buffers.remove(&buffer_id);
23604                }
23605                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23606                cx.emit(EditorEvent::Reparsed(*buffer_id));
23607                cx.notify();
23608            }
23609            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
23610            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
23611            multi_buffer::Event::FileHandleChanged
23612            | multi_buffer::Event::Reloaded
23613            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
23614            multi_buffer::Event::DiagnosticsUpdated => {
23615                self.update_diagnostics_state(window, cx);
23616            }
23617            _ => {}
23618        };
23619    }
23620
23621    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
23622        if !self.diagnostics_enabled() {
23623            return;
23624        }
23625        self.refresh_active_diagnostics(cx);
23626        self.refresh_inline_diagnostics(true, window, cx);
23627        self.scrollbar_marker_state.dirty = true;
23628        cx.notify();
23629    }
23630
23631    pub fn start_temporary_diff_override(&mut self) {
23632        self.load_diff_task.take();
23633        self.temporary_diff_override = true;
23634    }
23635
23636    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
23637        self.temporary_diff_override = false;
23638        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
23639        self.buffer.update(cx, |buffer, cx| {
23640            buffer.set_all_diff_hunks_collapsed(cx);
23641        });
23642
23643        if let Some(project) = self.project.clone() {
23644            self.load_diff_task = Some(
23645                update_uncommitted_diff_for_buffer(
23646                    cx.entity(),
23647                    &project,
23648                    self.buffer.read(cx).all_buffers(),
23649                    self.buffer.clone(),
23650                    cx,
23651                )
23652                .shared(),
23653            );
23654        }
23655    }
23656
23657    fn on_display_map_changed(
23658        &mut self,
23659        _: Entity<DisplayMap>,
23660        _: &mut Window,
23661        cx: &mut Context<Self>,
23662    ) {
23663        cx.notify();
23664    }
23665
23666    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
23667        if !self.mode.is_full() {
23668            return None;
23669        }
23670
23671        let theme_settings = theme::ThemeSettings::get_global(cx);
23672        let theme = cx.theme();
23673        let accent_colors = theme.accents().clone();
23674
23675        let accent_overrides = theme_settings
23676            .theme_overrides
23677            .get(theme.name.as_ref())
23678            .map(|theme_style| &theme_style.accents)
23679            .into_iter()
23680            .flatten()
23681            .chain(
23682                theme_settings
23683                    .experimental_theme_overrides
23684                    .as_ref()
23685                    .map(|overrides| &overrides.accents)
23686                    .into_iter()
23687                    .flatten(),
23688            )
23689            .flat_map(|accent| accent.0.clone().map(SharedString::from))
23690            .collect();
23691
23692        Some(AccentData {
23693            colors: accent_colors,
23694            overrides: accent_overrides,
23695        })
23696    }
23697
23698    fn fetch_applicable_language_settings(
23699        &self,
23700        cx: &App,
23701    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
23702        if !self.mode.is_full() {
23703            return HashMap::default();
23704        }
23705
23706        self.buffer().read(cx).all_buffers().into_iter().fold(
23707            HashMap::default(),
23708            |mut acc, buffer| {
23709                let buffer = buffer.read(cx);
23710                let language = buffer.language().map(|language| language.name());
23711                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
23712                    let file = buffer.file();
23713                    v.insert(language_settings(language, file, cx).into_owned());
23714                }
23715                acc
23716            },
23717        )
23718    }
23719
23720    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23721        let new_language_settings = self.fetch_applicable_language_settings(cx);
23722        let language_settings_changed = new_language_settings != self.applicable_language_settings;
23723        self.applicable_language_settings = new_language_settings;
23724
23725        let new_accents = self.fetch_accent_data(cx);
23726        let accents_changed = new_accents != self.accent_data;
23727        self.accent_data = new_accents;
23728
23729        if self.diagnostics_enabled() {
23730            let new_severity = EditorSettings::get_global(cx)
23731                .diagnostics_max_severity
23732                .unwrap_or(DiagnosticSeverity::Hint);
23733            self.set_max_diagnostics_severity(new_severity, cx);
23734        }
23735        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23736        self.update_edit_prediction_settings(cx);
23737        self.refresh_edit_prediction(true, false, window, cx);
23738        self.refresh_inline_values(cx);
23739        self.refresh_inlay_hints(
23740            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
23741                self.selections.newest_anchor().head(),
23742                &self.buffer.read(cx).snapshot(cx),
23743                cx,
23744            )),
23745            cx,
23746        );
23747
23748        let old_cursor_shape = self.cursor_shape;
23749        let old_show_breadcrumbs = self.show_breadcrumbs;
23750
23751        {
23752            let editor_settings = EditorSettings::get_global(cx);
23753            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
23754            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
23755            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
23756            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
23757        }
23758
23759        if old_cursor_shape != self.cursor_shape {
23760            cx.emit(EditorEvent::CursorShapeChanged);
23761        }
23762
23763        if old_show_breadcrumbs != self.show_breadcrumbs {
23764            cx.emit(EditorEvent::BreadcrumbsChanged);
23765        }
23766
23767        let project_settings = ProjectSettings::get_global(cx);
23768        self.buffer_serialization = self
23769            .should_serialize_buffer()
23770            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
23771
23772        if self.mode.is_full() {
23773            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
23774            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
23775            if self.show_inline_diagnostics != show_inline_diagnostics {
23776                self.show_inline_diagnostics = show_inline_diagnostics;
23777                self.refresh_inline_diagnostics(false, window, cx);
23778            }
23779
23780            if self.git_blame_inline_enabled != inline_blame_enabled {
23781                self.toggle_git_blame_inline_internal(false, window, cx);
23782            }
23783
23784            let minimap_settings = EditorSettings::get_global(cx).minimap;
23785            if self.minimap_visibility != MinimapVisibility::Disabled {
23786                if self.minimap_visibility.settings_visibility()
23787                    != minimap_settings.minimap_enabled()
23788                {
23789                    self.set_minimap_visibility(
23790                        MinimapVisibility::for_mode(self.mode(), cx),
23791                        window,
23792                        cx,
23793                    );
23794                } else if let Some(minimap_entity) = self.minimap.as_ref() {
23795                    minimap_entity.update(cx, |minimap_editor, cx| {
23796                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
23797                    })
23798                }
23799            }
23800
23801            if language_settings_changed || accents_changed {
23802                self.colorize_brackets(true, cx);
23803            }
23804
23805            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
23806                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
23807            }) {
23808                if !inlay_splice.is_empty() {
23809                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
23810                }
23811                self.refresh_colors_for_visible_range(None, window, cx);
23812            }
23813        }
23814
23815        cx.notify();
23816    }
23817
23818    pub fn set_searchable(&mut self, searchable: bool) {
23819        self.searchable = searchable;
23820    }
23821
23822    pub fn searchable(&self) -> bool {
23823        self.searchable
23824    }
23825
23826    pub fn open_excerpts_in_split(
23827        &mut self,
23828        _: &OpenExcerptsSplit,
23829        window: &mut Window,
23830        cx: &mut Context<Self>,
23831    ) {
23832        self.open_excerpts_common(None, true, window, cx)
23833    }
23834
23835    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
23836        self.open_excerpts_common(None, false, window, cx)
23837    }
23838
23839    fn open_excerpts_common(
23840        &mut self,
23841        jump_data: Option<JumpData>,
23842        split: bool,
23843        window: &mut Window,
23844        cx: &mut Context<Self>,
23845    ) {
23846        let Some(workspace) = self.workspace() else {
23847            cx.propagate();
23848            return;
23849        };
23850
23851        if self.buffer.read(cx).is_singleton() {
23852            cx.propagate();
23853            return;
23854        }
23855
23856        let mut new_selections_by_buffer = HashMap::default();
23857        match &jump_data {
23858            Some(JumpData::MultiBufferPoint {
23859                excerpt_id,
23860                position,
23861                anchor,
23862                line_offset_from_top,
23863            }) => {
23864                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
23865                if let Some(buffer) = multi_buffer_snapshot
23866                    .buffer_id_for_excerpt(*excerpt_id)
23867                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
23868                {
23869                    let buffer_snapshot = buffer.read(cx).snapshot();
23870                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
23871                        language::ToPoint::to_point(anchor, &buffer_snapshot)
23872                    } else {
23873                        buffer_snapshot.clip_point(*position, Bias::Left)
23874                    };
23875                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
23876                    new_selections_by_buffer.insert(
23877                        buffer,
23878                        (
23879                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
23880                            Some(*line_offset_from_top),
23881                        ),
23882                    );
23883                }
23884            }
23885            Some(JumpData::MultiBufferRow {
23886                row,
23887                line_offset_from_top,
23888            }) => {
23889                let point = MultiBufferPoint::new(row.0, 0);
23890                if let Some((buffer, buffer_point, _)) =
23891                    self.buffer.read(cx).point_to_buffer_point(point, cx)
23892                {
23893                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
23894                    new_selections_by_buffer
23895                        .entry(buffer)
23896                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
23897                        .0
23898                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
23899                }
23900            }
23901            None => {
23902                let selections = self
23903                    .selections
23904                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
23905                let multi_buffer = self.buffer.read(cx);
23906                for selection in selections {
23907                    for (snapshot, range, _, anchor) in multi_buffer
23908                        .snapshot(cx)
23909                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
23910                    {
23911                        if let Some(anchor) = anchor {
23912                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
23913                            else {
23914                                continue;
23915                            };
23916                            let offset = text::ToOffset::to_offset(
23917                                &anchor.text_anchor,
23918                                &buffer_handle.read(cx).snapshot(),
23919                            );
23920                            let range = BufferOffset(offset)..BufferOffset(offset);
23921                            new_selections_by_buffer
23922                                .entry(buffer_handle)
23923                                .or_insert((Vec::new(), None))
23924                                .0
23925                                .push(range)
23926                        } else {
23927                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
23928                            else {
23929                                continue;
23930                            };
23931                            new_selections_by_buffer
23932                                .entry(buffer_handle)
23933                                .or_insert((Vec::new(), None))
23934                                .0
23935                                .push(range)
23936                        }
23937                    }
23938                }
23939            }
23940        }
23941
23942        new_selections_by_buffer
23943            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
23944
23945        if new_selections_by_buffer.is_empty() {
23946            return;
23947        }
23948
23949        // We defer the pane interaction because we ourselves are a workspace item
23950        // and activating a new item causes the pane to call a method on us reentrantly,
23951        // which panics if we're on the stack.
23952        window.defer(cx, move |window, cx| {
23953            workspace.update(cx, |workspace, cx| {
23954                let pane = if split {
23955                    workspace.adjacent_pane(window, cx)
23956                } else {
23957                    workspace.active_pane().clone()
23958                };
23959
23960                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
23961                    let buffer_read = buffer.read(cx);
23962                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
23963                        (true, project::File::from_dyn(Some(file)).is_some())
23964                    } else {
23965                        (false, false)
23966                    };
23967
23968                    // If project file is none workspace.open_project_item will fail to open the excerpt
23969                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
23970                    // so we check if there's a tab match in that case first
23971                    let editor = (!has_file || !is_project_file)
23972                        .then(|| {
23973                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
23974                            // so `workspace.open_project_item` will never find them, always opening a new editor.
23975                            // Instead, we try to activate the existing editor in the pane first.
23976                            let (editor, pane_item_index, pane_item_id) =
23977                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
23978                                    let editor = item.downcast::<Editor>()?;
23979                                    let singleton_buffer =
23980                                        editor.read(cx).buffer().read(cx).as_singleton()?;
23981                                    if singleton_buffer == buffer {
23982                                        Some((editor, i, item.item_id()))
23983                                    } else {
23984                                        None
23985                                    }
23986                                })?;
23987                            pane.update(cx, |pane, cx| {
23988                                pane.activate_item(pane_item_index, true, true, window, cx);
23989                                if !PreviewTabsSettings::get_global(cx)
23990                                    .enable_preview_from_multibuffer
23991                                {
23992                                    pane.unpreview_item_if_preview(pane_item_id);
23993                                }
23994                            });
23995                            Some(editor)
23996                        })
23997                        .flatten()
23998                        .unwrap_or_else(|| {
23999                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
24000                                .enable_keep_preview_on_code_navigation;
24001                            let allow_new_preview =
24002                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
24003                            workspace.open_project_item::<Self>(
24004                                pane.clone(),
24005                                buffer,
24006                                true,
24007                                true,
24008                                keep_old_preview,
24009                                allow_new_preview,
24010                                window,
24011                                cx,
24012                            )
24013                        });
24014
24015                    editor.update(cx, |editor, cx| {
24016                        if has_file && !is_project_file {
24017                            editor.set_read_only(true);
24018                        }
24019                        let autoscroll = match scroll_offset {
24020                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
24021                            None => Autoscroll::newest(),
24022                        };
24023                        let nav_history = editor.nav_history.take();
24024                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24025                        let Some((&excerpt_id, _, buffer_snapshot)) =
24026                            multibuffer_snapshot.as_singleton()
24027                        else {
24028                            return;
24029                        };
24030                        editor.change_selections(
24031                            SelectionEffects::scroll(autoscroll),
24032                            window,
24033                            cx,
24034                            |s| {
24035                                s.select_ranges(ranges.into_iter().map(|range| {
24036                                    let range = buffer_snapshot.anchor_before(range.start)
24037                                        ..buffer_snapshot.anchor_after(range.end);
24038                                    multibuffer_snapshot
24039                                        .anchor_range_in_excerpt(excerpt_id, range)
24040                                        .unwrap()
24041                                }));
24042                            },
24043                        );
24044                        editor.nav_history = nav_history;
24045                    });
24046                }
24047            })
24048        });
24049    }
24050
24051    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24052        let snapshot = self.buffer.read(cx).read(cx);
24053        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
24054        Some(
24055            ranges
24056                .iter()
24057                .map(move |range| {
24058                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24059                })
24060                .collect(),
24061        )
24062    }
24063
24064    fn selection_replacement_ranges(
24065        &self,
24066        range: Range<MultiBufferOffsetUtf16>,
24067        cx: &mut App,
24068    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24069        let selections = self
24070            .selections
24071            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24072        let newest_selection = selections
24073            .iter()
24074            .max_by_key(|selection| selection.id)
24075            .unwrap();
24076        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24077        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24078        let snapshot = self.buffer.read(cx).read(cx);
24079        selections
24080            .into_iter()
24081            .map(|mut selection| {
24082                selection.start.0.0 =
24083                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24084                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24085                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24086                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24087            })
24088            .collect()
24089    }
24090
24091    fn report_editor_event(
24092        &self,
24093        reported_event: ReportEditorEvent,
24094        file_extension: Option<String>,
24095        cx: &App,
24096    ) {
24097        if cfg!(any(test, feature = "test-support")) {
24098            return;
24099        }
24100
24101        let Some(project) = &self.project else { return };
24102
24103        // If None, we are in a file without an extension
24104        let file = self
24105            .buffer
24106            .read(cx)
24107            .as_singleton()
24108            .and_then(|b| b.read(cx).file());
24109        let file_extension = file_extension.or(file
24110            .as_ref()
24111            .and_then(|file| Path::new(file.file_name(cx)).extension())
24112            .and_then(|e| e.to_str())
24113            .map(|a| a.to_string()));
24114
24115        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24116            .map(|vim_mode| vim_mode.0)
24117            .unwrap_or(false);
24118
24119        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24120        let copilot_enabled = edit_predictions_provider
24121            == language::language_settings::EditPredictionProvider::Copilot;
24122        let copilot_enabled_for_language = self
24123            .buffer
24124            .read(cx)
24125            .language_settings(cx)
24126            .show_edit_predictions;
24127
24128        let project = project.read(cx);
24129        let event_type = reported_event.event_type();
24130
24131        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24132            telemetry::event!(
24133                event_type,
24134                type = if auto_saved {"autosave"} else {"manual"},
24135                file_extension,
24136                vim_mode,
24137                copilot_enabled,
24138                copilot_enabled_for_language,
24139                edit_predictions_provider,
24140                is_via_ssh = project.is_via_remote_server(),
24141            );
24142        } else {
24143            telemetry::event!(
24144                event_type,
24145                file_extension,
24146                vim_mode,
24147                copilot_enabled,
24148                copilot_enabled_for_language,
24149                edit_predictions_provider,
24150                is_via_ssh = project.is_via_remote_server(),
24151            );
24152        };
24153    }
24154
24155    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24156    /// with each line being an array of {text, highlight} objects.
24157    fn copy_highlight_json(
24158        &mut self,
24159        _: &CopyHighlightJson,
24160        window: &mut Window,
24161        cx: &mut Context<Self>,
24162    ) {
24163        #[derive(Serialize)]
24164        struct Chunk<'a> {
24165            text: String,
24166            highlight: Option<&'a str>,
24167        }
24168
24169        let snapshot = self.buffer.read(cx).snapshot(cx);
24170        let range = self
24171            .selected_text_range(false, window, cx)
24172            .and_then(|selection| {
24173                if selection.range.is_empty() {
24174                    None
24175                } else {
24176                    Some(
24177                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24178                            selection.range.start,
24179                        )))
24180                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24181                                selection.range.end,
24182                            ))),
24183                    )
24184                }
24185            })
24186            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
24187
24188        let chunks = snapshot.chunks(range, true);
24189        let mut lines = Vec::new();
24190        let mut line: VecDeque<Chunk> = VecDeque::new();
24191
24192        let Some(style) = self.style.as_ref() else {
24193            return;
24194        };
24195
24196        for chunk in chunks {
24197            let highlight = chunk
24198                .syntax_highlight_id
24199                .and_then(|id| id.name(&style.syntax));
24200            let mut chunk_lines = chunk.text.split('\n').peekable();
24201            while let Some(text) = chunk_lines.next() {
24202                let mut merged_with_last_token = false;
24203                if let Some(last_token) = line.back_mut()
24204                    && last_token.highlight == highlight
24205                {
24206                    last_token.text.push_str(text);
24207                    merged_with_last_token = true;
24208                }
24209
24210                if !merged_with_last_token {
24211                    line.push_back(Chunk {
24212                        text: text.into(),
24213                        highlight,
24214                    });
24215                }
24216
24217                if chunk_lines.peek().is_some() {
24218                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
24219                        line.pop_front();
24220                    }
24221                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
24222                        line.pop_back();
24223                    }
24224
24225                    lines.push(mem::take(&mut line));
24226                }
24227            }
24228        }
24229
24230        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
24231            return;
24232        };
24233        cx.write_to_clipboard(ClipboardItem::new_string(lines));
24234    }
24235
24236    pub fn open_context_menu(
24237        &mut self,
24238        _: &OpenContextMenu,
24239        window: &mut Window,
24240        cx: &mut Context<Self>,
24241    ) {
24242        self.request_autoscroll(Autoscroll::newest(), cx);
24243        let position = self
24244            .selections
24245            .newest_display(&self.display_snapshot(cx))
24246            .start;
24247        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
24248    }
24249
24250    pub fn replay_insert_event(
24251        &mut self,
24252        text: &str,
24253        relative_utf16_range: Option<Range<isize>>,
24254        window: &mut Window,
24255        cx: &mut Context<Self>,
24256    ) {
24257        if !self.input_enabled {
24258            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24259            return;
24260        }
24261        if let Some(relative_utf16_range) = relative_utf16_range {
24262            let selections = self
24263                .selections
24264                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24265            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24266                let new_ranges = selections.into_iter().map(|range| {
24267                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
24268                        range
24269                            .head()
24270                            .0
24271                            .0
24272                            .saturating_add_signed(relative_utf16_range.start),
24273                    ));
24274                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
24275                        range
24276                            .head()
24277                            .0
24278                            .0
24279                            .saturating_add_signed(relative_utf16_range.end),
24280                    ));
24281                    start..end
24282                });
24283                s.select_ranges(new_ranges);
24284            });
24285        }
24286
24287        self.handle_input(text, window, cx);
24288    }
24289
24290    pub fn is_focused(&self, window: &Window) -> bool {
24291        self.focus_handle.is_focused(window)
24292    }
24293
24294    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24295        cx.emit(EditorEvent::Focused);
24296
24297        if let Some(descendant) = self
24298            .last_focused_descendant
24299            .take()
24300            .and_then(|descendant| descendant.upgrade())
24301        {
24302            window.focus(&descendant, cx);
24303        } else {
24304            if let Some(blame) = self.blame.as_ref() {
24305                blame.update(cx, GitBlame::focus)
24306            }
24307
24308            self.blink_manager.update(cx, BlinkManager::enable);
24309            self.show_cursor_names(window, cx);
24310            self.buffer.update(cx, |buffer, cx| {
24311                buffer.finalize_last_transaction(cx);
24312                if self.leader_id.is_none() {
24313                    buffer.set_active_selections(
24314                        &self.selections.disjoint_anchors_arc(),
24315                        self.selections.line_mode(),
24316                        self.cursor_shape,
24317                        cx,
24318                    );
24319                }
24320            });
24321
24322            if let Some(position_map) = self.last_position_map.clone() {
24323                EditorElement::mouse_moved(
24324                    self,
24325                    &MouseMoveEvent {
24326                        position: window.mouse_position(),
24327                        pressed_button: None,
24328                        modifiers: window.modifiers(),
24329                    },
24330                    &position_map,
24331                    window,
24332                    cx,
24333                );
24334            }
24335        }
24336    }
24337
24338    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24339        cx.emit(EditorEvent::FocusedIn)
24340    }
24341
24342    fn handle_focus_out(
24343        &mut self,
24344        event: FocusOutEvent,
24345        _window: &mut Window,
24346        cx: &mut Context<Self>,
24347    ) {
24348        if event.blurred != self.focus_handle {
24349            self.last_focused_descendant = Some(event.blurred);
24350        }
24351        self.selection_drag_state = SelectionDragState::None;
24352        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
24353    }
24354
24355    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24356        self.blink_manager.update(cx, BlinkManager::disable);
24357        self.buffer
24358            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
24359
24360        if let Some(blame) = self.blame.as_ref() {
24361            blame.update(cx, GitBlame::blur)
24362        }
24363        if !self.hover_state.focused(window, cx) {
24364            hide_hover(self, cx);
24365        }
24366        if !self
24367            .context_menu
24368            .borrow()
24369            .as_ref()
24370            .is_some_and(|context_menu| context_menu.focused(window, cx))
24371        {
24372            self.hide_context_menu(window, cx);
24373        }
24374        self.take_active_edit_prediction(cx);
24375        cx.emit(EditorEvent::Blurred);
24376        cx.notify();
24377    }
24378
24379    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24380        let mut pending: String = window
24381            .pending_input_keystrokes()
24382            .into_iter()
24383            .flatten()
24384            .filter_map(|keystroke| keystroke.key_char.clone())
24385            .collect();
24386
24387        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
24388            pending = "".to_string();
24389        }
24390
24391        let existing_pending = self
24392            .text_highlights::<PendingInput>(cx)
24393            .map(|(_, ranges)| ranges.to_vec());
24394        if existing_pending.is_none() && pending.is_empty() {
24395            return;
24396        }
24397        let transaction =
24398            self.transact(window, cx, |this, window, cx| {
24399                let selections = this
24400                    .selections
24401                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
24402                let edits = selections
24403                    .iter()
24404                    .map(|selection| (selection.end..selection.end, pending.clone()));
24405                this.edit(edits, cx);
24406                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24407                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
24408                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
24409                    }));
24410                });
24411                if let Some(existing_ranges) = existing_pending {
24412                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
24413                    this.edit(edits, cx);
24414                }
24415            });
24416
24417        let snapshot = self.snapshot(window, cx);
24418        let ranges = self
24419            .selections
24420            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
24421            .into_iter()
24422            .map(|selection| {
24423                snapshot.buffer_snapshot().anchor_after(selection.end)
24424                    ..snapshot
24425                        .buffer_snapshot()
24426                        .anchor_before(selection.end + pending.len())
24427            })
24428            .collect();
24429
24430        if pending.is_empty() {
24431            self.clear_highlights::<PendingInput>(cx);
24432        } else {
24433            self.highlight_text::<PendingInput>(
24434                ranges,
24435                HighlightStyle {
24436                    underline: Some(UnderlineStyle {
24437                        thickness: px(1.),
24438                        color: None,
24439                        wavy: false,
24440                    }),
24441                    ..Default::default()
24442                },
24443                cx,
24444            );
24445        }
24446
24447        self.ime_transaction = self.ime_transaction.or(transaction);
24448        if let Some(transaction) = self.ime_transaction {
24449            self.buffer.update(cx, |buffer, cx| {
24450                buffer.group_until_transaction(transaction, cx);
24451            });
24452        }
24453
24454        if self.text_highlights::<PendingInput>(cx).is_none() {
24455            self.ime_transaction.take();
24456        }
24457    }
24458
24459    pub fn register_action_renderer(
24460        &mut self,
24461        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
24462    ) -> Subscription {
24463        let id = self.next_editor_action_id.post_inc();
24464        self.editor_actions
24465            .borrow_mut()
24466            .insert(id, Box::new(listener));
24467
24468        let editor_actions = self.editor_actions.clone();
24469        Subscription::new(move || {
24470            editor_actions.borrow_mut().remove(&id);
24471        })
24472    }
24473
24474    pub fn register_action<A: Action>(
24475        &mut self,
24476        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
24477    ) -> Subscription {
24478        let id = self.next_editor_action_id.post_inc();
24479        let listener = Arc::new(listener);
24480        self.editor_actions.borrow_mut().insert(
24481            id,
24482            Box::new(move |_, window, _| {
24483                let listener = listener.clone();
24484                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
24485                    let action = action.downcast_ref().unwrap();
24486                    if phase == DispatchPhase::Bubble {
24487                        listener(action, window, cx)
24488                    }
24489                })
24490            }),
24491        );
24492
24493        let editor_actions = self.editor_actions.clone();
24494        Subscription::new(move || {
24495            editor_actions.borrow_mut().remove(&id);
24496        })
24497    }
24498
24499    pub fn file_header_size(&self) -> u32 {
24500        FILE_HEADER_HEIGHT
24501    }
24502
24503    pub fn restore(
24504        &mut self,
24505        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
24506        window: &mut Window,
24507        cx: &mut Context<Self>,
24508    ) {
24509        self.buffer().update(cx, |multi_buffer, cx| {
24510            for (buffer_id, changes) in revert_changes {
24511                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
24512                    buffer.update(cx, |buffer, cx| {
24513                        buffer.edit(
24514                            changes
24515                                .into_iter()
24516                                .map(|(range, text)| (range, text.to_string())),
24517                            None,
24518                            cx,
24519                        );
24520                    });
24521                }
24522            }
24523        });
24524        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24525            selections.refresh()
24526        });
24527    }
24528
24529    pub fn to_pixel_point(
24530        &mut self,
24531        source: multi_buffer::Anchor,
24532        editor_snapshot: &EditorSnapshot,
24533        window: &mut Window,
24534        cx: &App,
24535    ) -> Option<gpui::Point<Pixels>> {
24536        let source_point = source.to_display_point(editor_snapshot);
24537        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
24538    }
24539
24540    pub fn display_to_pixel_point(
24541        &mut self,
24542        source: DisplayPoint,
24543        editor_snapshot: &EditorSnapshot,
24544        window: &mut Window,
24545        cx: &App,
24546    ) -> Option<gpui::Point<Pixels>> {
24547        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
24548        let text_layout_details = self.text_layout_details(window);
24549        let scroll_top = text_layout_details
24550            .scroll_anchor
24551            .scroll_position(editor_snapshot)
24552            .y;
24553
24554        if source.row().as_f64() < scroll_top.floor() {
24555            return None;
24556        }
24557        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
24558        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
24559        Some(gpui::Point::new(source_x, source_y))
24560    }
24561
24562    pub fn has_visible_completions_menu(&self) -> bool {
24563        !self.edit_prediction_preview_is_active()
24564            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
24565                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
24566            })
24567    }
24568
24569    pub fn register_addon<T: Addon>(&mut self, instance: T) {
24570        if self.mode.is_minimap() {
24571            return;
24572        }
24573        self.addons
24574            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
24575    }
24576
24577    pub fn unregister_addon<T: Addon>(&mut self) {
24578        self.addons.remove(&std::any::TypeId::of::<T>());
24579    }
24580
24581    pub fn addon<T: Addon>(&self) -> Option<&T> {
24582        let type_id = std::any::TypeId::of::<T>();
24583        self.addons
24584            .get(&type_id)
24585            .and_then(|item| item.to_any().downcast_ref::<T>())
24586    }
24587
24588    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
24589        let type_id = std::any::TypeId::of::<T>();
24590        self.addons
24591            .get_mut(&type_id)
24592            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
24593    }
24594
24595    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
24596        let text_layout_details = self.text_layout_details(window);
24597        let style = &text_layout_details.editor_style;
24598        let font_id = window.text_system().resolve_font(&style.text.font());
24599        let font_size = style.text.font_size.to_pixels(window.rem_size());
24600        let line_height = style.text.line_height_in_pixels(window.rem_size());
24601        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
24602        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
24603
24604        CharacterDimensions {
24605            em_width,
24606            em_advance,
24607            line_height,
24608        }
24609    }
24610
24611    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
24612        self.load_diff_task.clone()
24613    }
24614
24615    fn read_metadata_from_db(
24616        &mut self,
24617        item_id: u64,
24618        workspace_id: WorkspaceId,
24619        window: &mut Window,
24620        cx: &mut Context<Editor>,
24621    ) {
24622        if self.buffer_kind(cx) == ItemBufferKind::Singleton
24623            && !self.mode.is_minimap()
24624            && WorkspaceSettings::get(None, cx).restore_on_startup
24625                != RestoreOnStartupBehavior::EmptyTab
24626        {
24627            let buffer_snapshot = OnceCell::new();
24628
24629            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
24630                && !folds.is_empty()
24631            {
24632                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
24633                let snapshot_len = snapshot.len().0;
24634
24635                // Helper: search for fingerprint in buffer, return offset if found
24636                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
24637                    // Ensure we start at a character boundary (defensive)
24638                    let search_start = snapshot
24639                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
24640                        .0;
24641                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
24642
24643                    let mut byte_offset = search_start;
24644                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
24645                        if byte_offset > search_end {
24646                            break;
24647                        }
24648                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
24649                            return Some(byte_offset);
24650                        }
24651                        byte_offset += ch.len_utf8();
24652                    }
24653                    None
24654                };
24655
24656                // Track search position to handle duplicate fingerprints correctly.
24657                // Folds are stored in document order, so we advance after each match.
24658                let mut search_start = 0usize;
24659
24660                let valid_folds: Vec<_> = folds
24661                    .into_iter()
24662                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
24663                        // Skip folds without fingerprints (old data before migration)
24664                        let sfp = start_fp?;
24665                        let efp = end_fp?;
24666                        let efp_len = efp.len();
24667
24668                        // Fast path: check if fingerprints match at stored offsets
24669                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
24670                        let start_matches = stored_start < snapshot_len
24671                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
24672                        let efp_check_pos = stored_end.saturating_sub(efp_len);
24673                        let end_matches = efp_check_pos >= stored_start
24674                            && stored_end <= snapshot_len
24675                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
24676
24677                        let (new_start, new_end) = if start_matches && end_matches {
24678                            // Offsets unchanged, use stored values
24679                            (stored_start, stored_end)
24680                        } else if sfp == efp {
24681                            // Short fold: identical fingerprints can only match once per search
24682                            // Use stored fold length to compute new_end
24683                            let new_start = find_fingerprint(&sfp, search_start)?;
24684                            let fold_len = stored_end - stored_start;
24685                            let new_end = new_start + fold_len;
24686                            (new_start, new_end)
24687                        } else {
24688                            // Slow path: search for fingerprints in buffer
24689                            let new_start = find_fingerprint(&sfp, search_start)?;
24690                            // Search for end_fp after start, then add efp_len to get actual fold end
24691                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
24692                            let new_end = efp_pos + efp_len;
24693                            (new_start, new_end)
24694                        };
24695
24696                        // Advance search position for next fold
24697                        search_start = new_end;
24698
24699                        // Validate fold makes sense (end must be after start)
24700                        if new_end <= new_start {
24701                            return None;
24702                        }
24703
24704                        Some(
24705                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
24706                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
24707                        )
24708                    })
24709                    .collect();
24710
24711                if !valid_folds.is_empty() {
24712                    self.fold_ranges(valid_folds, false, window, cx);
24713
24714                    // Migrate folds to current entity_id before workspace cleanup runs.
24715                    // Entity IDs change between sessions, but workspace cleanup deletes
24716                    // old editor rows (cascading to folds) based on current entity IDs.
24717                    let new_editor_id = cx.entity().entity_id().as_u64() as ItemId;
24718                    if new_editor_id != item_id {
24719                        cx.spawn(async move |_, _| {
24720                            DB.migrate_editor_folds(item_id, new_editor_id, workspace_id)
24721                                .await
24722                                .log_err();
24723                        })
24724                        .detach();
24725                    }
24726                }
24727            }
24728
24729            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
24730                && !selections.is_empty()
24731            {
24732                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
24733                // skip adding the initial selection to selection history
24734                self.selection_history.mode = SelectionHistoryMode::Skipping;
24735                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24736                    s.select_ranges(selections.into_iter().map(|(start, end)| {
24737                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
24738                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
24739                    }));
24740                });
24741                self.selection_history.mode = SelectionHistoryMode::Normal;
24742            };
24743        }
24744
24745        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
24746    }
24747
24748    fn update_lsp_data(
24749        &mut self,
24750        for_buffer: Option<BufferId>,
24751        window: &mut Window,
24752        cx: &mut Context<'_, Self>,
24753    ) {
24754        self.pull_diagnostics(for_buffer, window, cx);
24755        self.refresh_colors_for_visible_range(for_buffer, window, cx);
24756    }
24757
24758    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
24759        if self.ignore_lsp_data() {
24760            return;
24761        }
24762        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
24763            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
24764        }
24765    }
24766
24767    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
24768        if self.ignore_lsp_data() {
24769            return;
24770        }
24771
24772        if !self.registered_buffers.contains_key(&buffer_id)
24773            && let Some(project) = self.project.as_ref()
24774        {
24775            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
24776                project.update(cx, |project, cx| {
24777                    self.registered_buffers.insert(
24778                        buffer_id,
24779                        project.register_buffer_with_language_servers(&buffer, cx),
24780                    );
24781                });
24782            } else {
24783                self.registered_buffers.remove(&buffer_id);
24784            }
24785        }
24786    }
24787
24788    fn ignore_lsp_data(&self) -> bool {
24789        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
24790        // skip any LSP updates for it.
24791        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
24792    }
24793
24794    fn create_style(&self, cx: &App) -> EditorStyle {
24795        let settings = ThemeSettings::get_global(cx);
24796
24797        let mut text_style = match self.mode {
24798            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24799                color: cx.theme().colors().editor_foreground,
24800                font_family: settings.ui_font.family.clone(),
24801                font_features: settings.ui_font.features.clone(),
24802                font_fallbacks: settings.ui_font.fallbacks.clone(),
24803                font_size: rems(0.875).into(),
24804                font_weight: settings.ui_font.weight,
24805                line_height: relative(settings.buffer_line_height.value()),
24806                ..Default::default()
24807            },
24808            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24809                color: cx.theme().colors().editor_foreground,
24810                font_family: settings.buffer_font.family.clone(),
24811                font_features: settings.buffer_font.features.clone(),
24812                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24813                font_size: settings.buffer_font_size(cx).into(),
24814                font_weight: settings.buffer_font.weight,
24815                line_height: relative(settings.buffer_line_height.value()),
24816                ..Default::default()
24817            },
24818        };
24819        if let Some(text_style_refinement) = &self.text_style_refinement {
24820            text_style.refine(text_style_refinement)
24821        }
24822
24823        let background = match self.mode {
24824            EditorMode::SingleLine => cx.theme().system().transparent,
24825            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24826            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24827            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24828        };
24829
24830        EditorStyle {
24831            background,
24832            border: cx.theme().colors().border,
24833            local_player: cx.theme().players().local(),
24834            text: text_style,
24835            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24836            syntax: cx.theme().syntax().clone(),
24837            status: cx.theme().status().clone(),
24838            inlay_hints_style: make_inlay_hints_style(cx),
24839            edit_prediction_styles: make_suggestion_styles(cx),
24840            unnecessary_code_fade: settings.unnecessary_code_fade,
24841            show_underlines: self.diagnostics_enabled(),
24842        }
24843    }
24844    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
24845        let cursor = self.selections.newest_anchor().head();
24846        let multibuffer = self.buffer().read(cx);
24847        let is_singleton = multibuffer.is_singleton();
24848        let (buffer_id, symbols) = multibuffer
24849            .read(cx)
24850            .symbols_containing(cursor, Some(variant.syntax()))?;
24851        let buffer = multibuffer.buffer(buffer_id)?;
24852
24853        let buffer = buffer.read(cx);
24854        let settings = ThemeSettings::get_global(cx);
24855        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
24856        let mut breadcrumbs = if is_singleton {
24857            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
24858                buffer
24859                    .snapshot()
24860                    .resolve_file_path(
24861                        self.project
24862                            .as_ref()
24863                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
24864                            .unwrap_or_default(),
24865                        cx,
24866                    )
24867                    .unwrap_or_else(|| {
24868                        if multibuffer.is_singleton() {
24869                            multibuffer.title(cx).to_string()
24870                        } else {
24871                            "untitled".to_string()
24872                        }
24873                    })
24874            });
24875            vec![BreadcrumbText {
24876                text,
24877                highlights: None,
24878                font: Some(settings.buffer_font.clone()),
24879            }]
24880        } else {
24881            vec![]
24882        };
24883
24884        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
24885            text: symbol.text,
24886            highlights: Some(symbol.highlight_ranges),
24887            font: Some(settings.buffer_font.clone()),
24888        }));
24889        Some(breadcrumbs)
24890    }
24891}
24892
24893fn edit_for_markdown_paste<'a>(
24894    buffer: &MultiBufferSnapshot,
24895    range: Range<MultiBufferOffset>,
24896    to_insert: &'a str,
24897    url: Option<url::Url>,
24898) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
24899    if url.is_none() {
24900        return (range, Cow::Borrowed(to_insert));
24901    };
24902
24903    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
24904
24905    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
24906        Cow::Borrowed(to_insert)
24907    } else {
24908        Cow::Owned(format!("[{old_text}]({to_insert})"))
24909    };
24910    (range, new_text)
24911}
24912
24913fn process_completion_for_edit(
24914    completion: &Completion,
24915    intent: CompletionIntent,
24916    buffer: &Entity<Buffer>,
24917    cursor_position: &text::Anchor,
24918    cx: &mut Context<Editor>,
24919) -> CompletionEdit {
24920    let buffer = buffer.read(cx);
24921    let buffer_snapshot = buffer.snapshot();
24922    let (snippet, new_text) = if completion.is_snippet() {
24923        let mut snippet_source = completion.new_text.clone();
24924        // Workaround for typescript language server issues so that methods don't expand within
24925        // strings and functions with type expressions. The previous point is used because the query
24926        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
24927        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
24928        let previous_point = if previous_point.column > 0 {
24929            cursor_position.to_previous_offset(&buffer_snapshot)
24930        } else {
24931            cursor_position.to_offset(&buffer_snapshot)
24932        };
24933        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
24934            && scope.prefers_label_for_snippet_in_completion()
24935            && let Some(label) = completion.label()
24936            && matches!(
24937                completion.kind(),
24938                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
24939            )
24940        {
24941            snippet_source = label;
24942        }
24943        match Snippet::parse(&snippet_source).log_err() {
24944            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
24945            None => (None, completion.new_text.clone()),
24946        }
24947    } else {
24948        (None, completion.new_text.clone())
24949    };
24950
24951    let mut range_to_replace = {
24952        let replace_range = &completion.replace_range;
24953        if let CompletionSource::Lsp {
24954            insert_range: Some(insert_range),
24955            ..
24956        } = &completion.source
24957        {
24958            debug_assert_eq!(
24959                insert_range.start, replace_range.start,
24960                "insert_range and replace_range should start at the same position"
24961            );
24962            debug_assert!(
24963                insert_range
24964                    .start
24965                    .cmp(cursor_position, &buffer_snapshot)
24966                    .is_le(),
24967                "insert_range should start before or at cursor position"
24968            );
24969            debug_assert!(
24970                replace_range
24971                    .start
24972                    .cmp(cursor_position, &buffer_snapshot)
24973                    .is_le(),
24974                "replace_range should start before or at cursor position"
24975            );
24976
24977            let should_replace = match intent {
24978                CompletionIntent::CompleteWithInsert => false,
24979                CompletionIntent::CompleteWithReplace => true,
24980                CompletionIntent::Complete | CompletionIntent::Compose => {
24981                    let insert_mode =
24982                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
24983                            .completions
24984                            .lsp_insert_mode;
24985                    match insert_mode {
24986                        LspInsertMode::Insert => false,
24987                        LspInsertMode::Replace => true,
24988                        LspInsertMode::ReplaceSubsequence => {
24989                            let mut text_to_replace = buffer.chars_for_range(
24990                                buffer.anchor_before(replace_range.start)
24991                                    ..buffer.anchor_after(replace_range.end),
24992                            );
24993                            let mut current_needle = text_to_replace.next();
24994                            for haystack_ch in completion.label.text.chars() {
24995                                if let Some(needle_ch) = current_needle
24996                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
24997                                {
24998                                    current_needle = text_to_replace.next();
24999                                }
25000                            }
25001                            current_needle.is_none()
25002                        }
25003                        LspInsertMode::ReplaceSuffix => {
25004                            if replace_range
25005                                .end
25006                                .cmp(cursor_position, &buffer_snapshot)
25007                                .is_gt()
25008                            {
25009                                let range_after_cursor = *cursor_position..replace_range.end;
25010                                let text_after_cursor = buffer
25011                                    .text_for_range(
25012                                        buffer.anchor_before(range_after_cursor.start)
25013                                            ..buffer.anchor_after(range_after_cursor.end),
25014                                    )
25015                                    .collect::<String>()
25016                                    .to_ascii_lowercase();
25017                                completion
25018                                    .label
25019                                    .text
25020                                    .to_ascii_lowercase()
25021                                    .ends_with(&text_after_cursor)
25022                            } else {
25023                                true
25024                            }
25025                        }
25026                    }
25027                }
25028            };
25029
25030            if should_replace {
25031                replace_range.clone()
25032            } else {
25033                insert_range.clone()
25034            }
25035        } else {
25036            replace_range.clone()
25037        }
25038    };
25039
25040    if range_to_replace
25041        .end
25042        .cmp(cursor_position, &buffer_snapshot)
25043        .is_lt()
25044    {
25045        range_to_replace.end = *cursor_position;
25046    }
25047
25048    let replace_range = range_to_replace.to_offset(buffer);
25049    CompletionEdit {
25050        new_text,
25051        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
25052        snippet,
25053    }
25054}
25055
25056struct CompletionEdit {
25057    new_text: String,
25058    replace_range: Range<BufferOffset>,
25059    snippet: Option<Snippet>,
25060}
25061
25062fn comment_delimiter_for_newline(
25063    start_point: &Point,
25064    buffer: &MultiBufferSnapshot,
25065    language: &LanguageScope,
25066) -> Option<Arc<str>> {
25067    let delimiters = language.line_comment_prefixes();
25068    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
25069    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25070
25071    let num_of_whitespaces = snapshot
25072        .chars_for_range(range.clone())
25073        .take_while(|c| c.is_whitespace())
25074        .count();
25075    let comment_candidate = snapshot
25076        .chars_for_range(range.clone())
25077        .skip(num_of_whitespaces)
25078        .take(max_len_of_delimiter)
25079        .collect::<String>();
25080    let (delimiter, trimmed_len) = delimiters
25081        .iter()
25082        .filter_map(|delimiter| {
25083            let prefix = delimiter.trim_end();
25084            if comment_candidate.starts_with(prefix) {
25085                Some((delimiter, prefix.len()))
25086            } else {
25087                None
25088            }
25089        })
25090        .max_by_key(|(_, len)| *len)?;
25091
25092    if let Some(BlockCommentConfig {
25093        start: block_start, ..
25094    }) = language.block_comment()
25095    {
25096        let block_start_trimmed = block_start.trim_end();
25097        if block_start_trimmed.starts_with(delimiter.trim_end()) {
25098            let line_content = snapshot
25099                .chars_for_range(range)
25100                .skip(num_of_whitespaces)
25101                .take(block_start_trimmed.len())
25102                .collect::<String>();
25103
25104            if line_content.starts_with(block_start_trimmed) {
25105                return None;
25106            }
25107        }
25108    }
25109
25110    let cursor_is_placed_after_comment_marker =
25111        num_of_whitespaces + trimmed_len <= start_point.column as usize;
25112    if cursor_is_placed_after_comment_marker {
25113        Some(delimiter.clone())
25114    } else {
25115        None
25116    }
25117}
25118
25119fn documentation_delimiter_for_newline(
25120    start_point: &Point,
25121    buffer: &MultiBufferSnapshot,
25122    language: &LanguageScope,
25123    newline_config: &mut NewlineConfig,
25124) -> Option<Arc<str>> {
25125    let BlockCommentConfig {
25126        start: start_tag,
25127        end: end_tag,
25128        prefix: delimiter,
25129        tab_size: len,
25130    } = language.documentation_comment()?;
25131    let is_within_block_comment = buffer
25132        .language_scope_at(*start_point)
25133        .is_some_and(|scope| scope.override_name() == Some("comment"));
25134    if !is_within_block_comment {
25135        return None;
25136    }
25137
25138    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25139
25140    let num_of_whitespaces = snapshot
25141        .chars_for_range(range.clone())
25142        .take_while(|c| c.is_whitespace())
25143        .count();
25144
25145    // 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.
25146    let column = start_point.column;
25147    let cursor_is_after_start_tag = {
25148        let start_tag_len = start_tag.len();
25149        let start_tag_line = snapshot
25150            .chars_for_range(range.clone())
25151            .skip(num_of_whitespaces)
25152            .take(start_tag_len)
25153            .collect::<String>();
25154        if start_tag_line.starts_with(start_tag.as_ref()) {
25155            num_of_whitespaces + start_tag_len <= column as usize
25156        } else {
25157            false
25158        }
25159    };
25160
25161    let cursor_is_after_delimiter = {
25162        let delimiter_trim = delimiter.trim_end();
25163        let delimiter_line = snapshot
25164            .chars_for_range(range.clone())
25165            .skip(num_of_whitespaces)
25166            .take(delimiter_trim.len())
25167            .collect::<String>();
25168        if delimiter_line.starts_with(delimiter_trim) {
25169            num_of_whitespaces + delimiter_trim.len() <= column as usize
25170        } else {
25171            false
25172        }
25173    };
25174
25175    let mut needs_extra_line = false;
25176    let mut extra_line_additional_indent = IndentSize::spaces(0);
25177
25178    let cursor_is_before_end_tag_if_exists = {
25179        let mut char_position = 0u32;
25180        let mut end_tag_offset = None;
25181
25182        'outer: for chunk in snapshot.text_for_range(range) {
25183            if let Some(byte_pos) = chunk.find(&**end_tag) {
25184                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
25185                end_tag_offset = Some(char_position + chars_before_match);
25186                break 'outer;
25187            }
25188            char_position += chunk.chars().count() as u32;
25189        }
25190
25191        if let Some(end_tag_offset) = end_tag_offset {
25192            let cursor_is_before_end_tag = column <= end_tag_offset;
25193            if cursor_is_after_start_tag {
25194                if cursor_is_before_end_tag {
25195                    needs_extra_line = true;
25196                }
25197                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
25198                if cursor_is_at_start_of_end_tag {
25199                    extra_line_additional_indent.len = *len;
25200                }
25201            }
25202            cursor_is_before_end_tag
25203        } else {
25204            true
25205        }
25206    };
25207
25208    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
25209        && cursor_is_before_end_tag_if_exists
25210    {
25211        let additional_indent = if cursor_is_after_start_tag {
25212            IndentSize::spaces(*len)
25213        } else {
25214            IndentSize::spaces(0)
25215        };
25216
25217        *newline_config = NewlineConfig::Newline {
25218            additional_indent,
25219            extra_line_additional_indent: if needs_extra_line {
25220                Some(extra_line_additional_indent)
25221            } else {
25222                None
25223            },
25224            prevent_auto_indent: true,
25225        };
25226        Some(delimiter.clone())
25227    } else {
25228        None
25229    }
25230}
25231
25232const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
25233
25234fn list_delimiter_for_newline(
25235    start_point: &Point,
25236    buffer: &MultiBufferSnapshot,
25237    language: &LanguageScope,
25238    newline_config: &mut NewlineConfig,
25239) -> Option<Arc<str>> {
25240    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25241
25242    let num_of_whitespaces = snapshot
25243        .chars_for_range(range.clone())
25244        .take_while(|c| c.is_whitespace())
25245        .count();
25246
25247    let task_list_entries: Vec<_> = language
25248        .task_list()
25249        .into_iter()
25250        .flat_map(|config| {
25251            config
25252                .prefixes
25253                .iter()
25254                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
25255        })
25256        .collect();
25257    let unordered_list_entries: Vec<_> = language
25258        .unordered_list()
25259        .iter()
25260        .map(|marker| (marker.as_ref(), marker.as_ref()))
25261        .collect();
25262
25263    let all_entries: Vec<_> = task_list_entries
25264        .into_iter()
25265        .chain(unordered_list_entries)
25266        .collect();
25267
25268    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
25269        let candidate: String = snapshot
25270            .chars_for_range(range.clone())
25271            .skip(num_of_whitespaces)
25272            .take(max_prefix_len)
25273            .collect();
25274
25275        if let Some((prefix, continuation)) = all_entries
25276            .iter()
25277            .filter(|(prefix, _)| candidate.starts_with(*prefix))
25278            .max_by_key(|(prefix, _)| prefix.len())
25279        {
25280            let end_of_prefix = num_of_whitespaces + prefix.len();
25281            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25282            let has_content_after_marker = snapshot
25283                .chars_for_range(range)
25284                .skip(end_of_prefix)
25285                .any(|c| !c.is_whitespace());
25286
25287            if has_content_after_marker && cursor_is_after_prefix {
25288                return Some((*continuation).into());
25289            }
25290
25291            if start_point.column as usize == end_of_prefix {
25292                if num_of_whitespaces == 0 {
25293                    *newline_config = NewlineConfig::ClearCurrentLine;
25294                } else {
25295                    *newline_config = NewlineConfig::UnindentCurrentLine {
25296                        continuation: (*continuation).into(),
25297                    };
25298                }
25299            }
25300
25301            return None;
25302        }
25303    }
25304
25305    let candidate: String = snapshot
25306        .chars_for_range(range.clone())
25307        .skip(num_of_whitespaces)
25308        .take(ORDERED_LIST_MAX_MARKER_LEN)
25309        .collect();
25310
25311    for ordered_config in language.ordered_list() {
25312        let regex = match Regex::new(&ordered_config.pattern) {
25313            Ok(r) => r,
25314            Err(_) => continue,
25315        };
25316
25317        if let Some(captures) = regex.captures(&candidate) {
25318            let full_match = captures.get(0)?;
25319            let marker_len = full_match.len();
25320            let end_of_prefix = num_of_whitespaces + marker_len;
25321            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25322
25323            let has_content_after_marker = snapshot
25324                .chars_for_range(range)
25325                .skip(end_of_prefix)
25326                .any(|c| !c.is_whitespace());
25327
25328            if has_content_after_marker && cursor_is_after_prefix {
25329                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
25330                let continuation = ordered_config
25331                    .format
25332                    .replace("{1}", &(number + 1).to_string());
25333                return Some(continuation.into());
25334            }
25335
25336            if start_point.column as usize == end_of_prefix {
25337                let continuation = ordered_config.format.replace("{1}", "1");
25338                if num_of_whitespaces == 0 {
25339                    *newline_config = NewlineConfig::ClearCurrentLine;
25340                } else {
25341                    *newline_config = NewlineConfig::UnindentCurrentLine {
25342                        continuation: continuation.into(),
25343                    };
25344                }
25345            }
25346
25347            return None;
25348        }
25349    }
25350
25351    None
25352}
25353
25354fn is_list_prefix_row(
25355    row: MultiBufferRow,
25356    buffer: &MultiBufferSnapshot,
25357    language: &LanguageScope,
25358) -> bool {
25359    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
25360        return false;
25361    };
25362
25363    let num_of_whitespaces = snapshot
25364        .chars_for_range(range.clone())
25365        .take_while(|c| c.is_whitespace())
25366        .count();
25367
25368    let task_list_prefixes: Vec<_> = language
25369        .task_list()
25370        .into_iter()
25371        .flat_map(|config| {
25372            config
25373                .prefixes
25374                .iter()
25375                .map(|p| p.as_ref())
25376                .collect::<Vec<_>>()
25377        })
25378        .collect();
25379    let unordered_list_markers: Vec<_> = language
25380        .unordered_list()
25381        .iter()
25382        .map(|marker| marker.as_ref())
25383        .collect();
25384    let all_prefixes: Vec<_> = task_list_prefixes
25385        .into_iter()
25386        .chain(unordered_list_markers)
25387        .collect();
25388    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
25389        let candidate: String = snapshot
25390            .chars_for_range(range.clone())
25391            .skip(num_of_whitespaces)
25392            .take(max_prefix_len)
25393            .collect();
25394        if all_prefixes
25395            .iter()
25396            .any(|prefix| candidate.starts_with(*prefix))
25397        {
25398            return true;
25399        }
25400    }
25401
25402    let ordered_list_candidate: String = snapshot
25403        .chars_for_range(range)
25404        .skip(num_of_whitespaces)
25405        .take(ORDERED_LIST_MAX_MARKER_LEN)
25406        .collect();
25407    for ordered_config in language.ordered_list() {
25408        let regex = match Regex::new(&ordered_config.pattern) {
25409            Ok(r) => r,
25410            Err(_) => continue,
25411        };
25412        if let Some(captures) = regex.captures(&ordered_list_candidate) {
25413            return captures.get(0).is_some();
25414        }
25415    }
25416
25417    false
25418}
25419
25420#[derive(Debug)]
25421enum NewlineConfig {
25422    /// Insert newline with optional additional indent and optional extra blank line
25423    Newline {
25424        additional_indent: IndentSize,
25425        extra_line_additional_indent: Option<IndentSize>,
25426        prevent_auto_indent: bool,
25427    },
25428    /// Clear the current line
25429    ClearCurrentLine,
25430    /// Unindent the current line and add continuation
25431    UnindentCurrentLine { continuation: Arc<str> },
25432}
25433
25434impl NewlineConfig {
25435    fn has_extra_line(&self) -> bool {
25436        matches!(
25437            self,
25438            Self::Newline {
25439                extra_line_additional_indent: Some(_),
25440                ..
25441            }
25442        )
25443    }
25444
25445    fn insert_extra_newline_brackets(
25446        buffer: &MultiBufferSnapshot,
25447        range: Range<MultiBufferOffset>,
25448        language: &language::LanguageScope,
25449    ) -> bool {
25450        let leading_whitespace_len = buffer
25451            .reversed_chars_at(range.start)
25452            .take_while(|c| c.is_whitespace() && *c != '\n')
25453            .map(|c| c.len_utf8())
25454            .sum::<usize>();
25455        let trailing_whitespace_len = buffer
25456            .chars_at(range.end)
25457            .take_while(|c| c.is_whitespace() && *c != '\n')
25458            .map(|c| c.len_utf8())
25459            .sum::<usize>();
25460        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
25461
25462        language.brackets().any(|(pair, enabled)| {
25463            let pair_start = pair.start.trim_end();
25464            let pair_end = pair.end.trim_start();
25465
25466            enabled
25467                && pair.newline
25468                && buffer.contains_str_at(range.end, pair_end)
25469                && buffer.contains_str_at(
25470                    range.start.saturating_sub_usize(pair_start.len()),
25471                    pair_start,
25472                )
25473        })
25474    }
25475
25476    fn insert_extra_newline_tree_sitter(
25477        buffer: &MultiBufferSnapshot,
25478        range: Range<MultiBufferOffset>,
25479    ) -> bool {
25480        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
25481            [(buffer, range, _)] => (*buffer, range.clone()),
25482            _ => return false,
25483        };
25484        let pair = {
25485            let mut result: Option<BracketMatch<usize>> = None;
25486
25487            for pair in buffer
25488                .all_bracket_ranges(range.start.0..range.end.0)
25489                .filter(move |pair| {
25490                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
25491                })
25492            {
25493                let len = pair.close_range.end - pair.open_range.start;
25494
25495                if let Some(existing) = &result {
25496                    let existing_len = existing.close_range.end - existing.open_range.start;
25497                    if len > existing_len {
25498                        continue;
25499                    }
25500                }
25501
25502                result = Some(pair);
25503            }
25504
25505            result
25506        };
25507        let Some(pair) = pair else {
25508            return false;
25509        };
25510        pair.newline_only
25511            && buffer
25512                .chars_for_range(pair.open_range.end..range.start.0)
25513                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
25514                .all(|c| c.is_whitespace() && c != '\n')
25515    }
25516}
25517
25518fn update_uncommitted_diff_for_buffer(
25519    editor: Entity<Editor>,
25520    project: &Entity<Project>,
25521    buffers: impl IntoIterator<Item = Entity<Buffer>>,
25522    buffer: Entity<MultiBuffer>,
25523    cx: &mut App,
25524) -> Task<()> {
25525    let mut tasks = Vec::new();
25526    project.update(cx, |project, cx| {
25527        for buffer in buffers {
25528            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
25529                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
25530            }
25531        }
25532    });
25533    cx.spawn(async move |cx| {
25534        let diffs = future::join_all(tasks).await;
25535        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
25536            return;
25537        }
25538
25539        buffer.update(cx, |buffer, cx| {
25540            for diff in diffs.into_iter().flatten() {
25541                buffer.add_diff(diff, cx);
25542            }
25543        });
25544    })
25545}
25546
25547fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
25548    let tab_size = tab_size.get() as usize;
25549    let mut width = offset;
25550
25551    for ch in text.chars() {
25552        width += if ch == '\t' {
25553            tab_size - (width % tab_size)
25554        } else {
25555            1
25556        };
25557    }
25558
25559    width - offset
25560}
25561
25562#[cfg(test)]
25563mod tests {
25564    use super::*;
25565
25566    #[test]
25567    fn test_string_size_with_expanded_tabs() {
25568        let nz = |val| NonZeroU32::new(val).unwrap();
25569        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
25570        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
25571        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
25572        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
25573        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
25574        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
25575        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
25576        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
25577    }
25578}
25579
25580/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
25581struct WordBreakingTokenizer<'a> {
25582    input: &'a str,
25583}
25584
25585impl<'a> WordBreakingTokenizer<'a> {
25586    fn new(input: &'a str) -> Self {
25587        Self { input }
25588    }
25589}
25590
25591fn is_char_ideographic(ch: char) -> bool {
25592    use unicode_script::Script::*;
25593    use unicode_script::UnicodeScript;
25594    matches!(ch.script(), Han | Tangut | Yi)
25595}
25596
25597fn is_grapheme_ideographic(text: &str) -> bool {
25598    text.chars().any(is_char_ideographic)
25599}
25600
25601fn is_grapheme_whitespace(text: &str) -> bool {
25602    text.chars().any(|x| x.is_whitespace())
25603}
25604
25605fn should_stay_with_preceding_ideograph(text: &str) -> bool {
25606    text.chars()
25607        .next()
25608        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
25609}
25610
25611#[derive(PartialEq, Eq, Debug, Clone, Copy)]
25612enum WordBreakToken<'a> {
25613    Word { token: &'a str, grapheme_len: usize },
25614    InlineWhitespace { token: &'a str, grapheme_len: usize },
25615    Newline,
25616}
25617
25618impl<'a> Iterator for WordBreakingTokenizer<'a> {
25619    /// Yields a span, the count of graphemes in the token, and whether it was
25620    /// whitespace. Note that it also breaks at word boundaries.
25621    type Item = WordBreakToken<'a>;
25622
25623    fn next(&mut self) -> Option<Self::Item> {
25624        use unicode_segmentation::UnicodeSegmentation;
25625        if self.input.is_empty() {
25626            return None;
25627        }
25628
25629        let mut iter = self.input.graphemes(true).peekable();
25630        let mut offset = 0;
25631        let mut grapheme_len = 0;
25632        if let Some(first_grapheme) = iter.next() {
25633            let is_newline = first_grapheme == "\n";
25634            let is_whitespace = is_grapheme_whitespace(first_grapheme);
25635            offset += first_grapheme.len();
25636            grapheme_len += 1;
25637            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
25638                if let Some(grapheme) = iter.peek().copied()
25639                    && should_stay_with_preceding_ideograph(grapheme)
25640                {
25641                    offset += grapheme.len();
25642                    grapheme_len += 1;
25643                }
25644            } else {
25645                let mut words = self.input[offset..].split_word_bound_indices().peekable();
25646                let mut next_word_bound = words.peek().copied();
25647                if next_word_bound.is_some_and(|(i, _)| i == 0) {
25648                    next_word_bound = words.next();
25649                }
25650                while let Some(grapheme) = iter.peek().copied() {
25651                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
25652                        break;
25653                    };
25654                    if is_grapheme_whitespace(grapheme) != is_whitespace
25655                        || (grapheme == "\n") != is_newline
25656                    {
25657                        break;
25658                    };
25659                    offset += grapheme.len();
25660                    grapheme_len += 1;
25661                    iter.next();
25662                }
25663            }
25664            let token = &self.input[..offset];
25665            self.input = &self.input[offset..];
25666            if token == "\n" {
25667                Some(WordBreakToken::Newline)
25668            } else if is_whitespace {
25669                Some(WordBreakToken::InlineWhitespace {
25670                    token,
25671                    grapheme_len,
25672                })
25673            } else {
25674                Some(WordBreakToken::Word {
25675                    token,
25676                    grapheme_len,
25677                })
25678            }
25679        } else {
25680            None
25681        }
25682    }
25683}
25684
25685#[test]
25686fn test_word_breaking_tokenizer() {
25687    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
25688        ("", &[]),
25689        ("  ", &[whitespace("  ", 2)]),
25690        ("Ʒ", &[word("Ʒ", 1)]),
25691        ("Ǽ", &[word("Ǽ", 1)]),
25692        ("", &[word("", 1)]),
25693        ("⋑⋑", &[word("⋑⋑", 2)]),
25694        (
25695            "原理,进而",
25696            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
25697        ),
25698        (
25699            "hello world",
25700            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
25701        ),
25702        (
25703            "hello, world",
25704            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
25705        ),
25706        (
25707            "  hello world",
25708            &[
25709                whitespace("  ", 2),
25710                word("hello", 5),
25711                whitespace(" ", 1),
25712                word("world", 5),
25713            ],
25714        ),
25715        (
25716            "这是什么 \n 钢笔",
25717            &[
25718                word("", 1),
25719                word("", 1),
25720                word("", 1),
25721                word("", 1),
25722                whitespace(" ", 1),
25723                newline(),
25724                whitespace(" ", 1),
25725                word("", 1),
25726                word("", 1),
25727            ],
25728        ),
25729        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
25730    ];
25731
25732    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
25733        WordBreakToken::Word {
25734            token,
25735            grapheme_len,
25736        }
25737    }
25738
25739    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
25740        WordBreakToken::InlineWhitespace {
25741            token,
25742            grapheme_len,
25743        }
25744    }
25745
25746    fn newline() -> WordBreakToken<'static> {
25747        WordBreakToken::Newline
25748    }
25749
25750    for (input, result) in tests {
25751        assert_eq!(
25752            WordBreakingTokenizer::new(input)
25753                .collect::<Vec<_>>()
25754                .as_slice(),
25755            *result,
25756        );
25757    }
25758}
25759
25760fn wrap_with_prefix(
25761    first_line_prefix: String,
25762    subsequent_lines_prefix: String,
25763    unwrapped_text: String,
25764    wrap_column: usize,
25765    tab_size: NonZeroU32,
25766    preserve_existing_whitespace: bool,
25767) -> String {
25768    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
25769    let subsequent_lines_prefix_len =
25770        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
25771    let mut wrapped_text = String::new();
25772    let mut current_line = first_line_prefix;
25773    let mut is_first_line = true;
25774
25775    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
25776    let mut current_line_len = first_line_prefix_len;
25777    let mut in_whitespace = false;
25778    for token in tokenizer {
25779        let have_preceding_whitespace = in_whitespace;
25780        match token {
25781            WordBreakToken::Word {
25782                token,
25783                grapheme_len,
25784            } => {
25785                in_whitespace = false;
25786                let current_prefix_len = if is_first_line {
25787                    first_line_prefix_len
25788                } else {
25789                    subsequent_lines_prefix_len
25790                };
25791                if current_line_len + grapheme_len > wrap_column
25792                    && current_line_len != current_prefix_len
25793                {
25794                    wrapped_text.push_str(current_line.trim_end());
25795                    wrapped_text.push('\n');
25796                    is_first_line = false;
25797                    current_line = subsequent_lines_prefix.clone();
25798                    current_line_len = subsequent_lines_prefix_len;
25799                }
25800                current_line.push_str(token);
25801                current_line_len += grapheme_len;
25802            }
25803            WordBreakToken::InlineWhitespace {
25804                mut token,
25805                mut grapheme_len,
25806            } => {
25807                in_whitespace = true;
25808                if have_preceding_whitespace && !preserve_existing_whitespace {
25809                    continue;
25810                }
25811                if !preserve_existing_whitespace {
25812                    // Keep a single whitespace grapheme as-is
25813                    if let Some(first) =
25814                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
25815                    {
25816                        token = first;
25817                    } else {
25818                        token = " ";
25819                    }
25820                    grapheme_len = 1;
25821                }
25822                let current_prefix_len = if is_first_line {
25823                    first_line_prefix_len
25824                } else {
25825                    subsequent_lines_prefix_len
25826                };
25827                if current_line_len + grapheme_len > wrap_column {
25828                    wrapped_text.push_str(current_line.trim_end());
25829                    wrapped_text.push('\n');
25830                    is_first_line = false;
25831                    current_line = subsequent_lines_prefix.clone();
25832                    current_line_len = subsequent_lines_prefix_len;
25833                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
25834                    current_line.push_str(token);
25835                    current_line_len += grapheme_len;
25836                }
25837            }
25838            WordBreakToken::Newline => {
25839                in_whitespace = true;
25840                let current_prefix_len = if is_first_line {
25841                    first_line_prefix_len
25842                } else {
25843                    subsequent_lines_prefix_len
25844                };
25845                if preserve_existing_whitespace {
25846                    wrapped_text.push_str(current_line.trim_end());
25847                    wrapped_text.push('\n');
25848                    is_first_line = false;
25849                    current_line = subsequent_lines_prefix.clone();
25850                    current_line_len = subsequent_lines_prefix_len;
25851                } else if have_preceding_whitespace {
25852                    continue;
25853                } else if current_line_len + 1 > wrap_column
25854                    && current_line_len != current_prefix_len
25855                {
25856                    wrapped_text.push_str(current_line.trim_end());
25857                    wrapped_text.push('\n');
25858                    is_first_line = false;
25859                    current_line = subsequent_lines_prefix.clone();
25860                    current_line_len = subsequent_lines_prefix_len;
25861                } else if current_line_len != current_prefix_len {
25862                    current_line.push(' ');
25863                    current_line_len += 1;
25864                }
25865            }
25866        }
25867    }
25868
25869    if !current_line.is_empty() {
25870        wrapped_text.push_str(&current_line);
25871    }
25872    wrapped_text
25873}
25874
25875#[test]
25876fn test_wrap_with_prefix() {
25877    assert_eq!(
25878        wrap_with_prefix(
25879            "# ".to_string(),
25880            "# ".to_string(),
25881            "abcdefg".to_string(),
25882            4,
25883            NonZeroU32::new(4).unwrap(),
25884            false,
25885        ),
25886        "# abcdefg"
25887    );
25888    assert_eq!(
25889        wrap_with_prefix(
25890            "".to_string(),
25891            "".to_string(),
25892            "\thello world".to_string(),
25893            8,
25894            NonZeroU32::new(4).unwrap(),
25895            false,
25896        ),
25897        "hello\nworld"
25898    );
25899    assert_eq!(
25900        wrap_with_prefix(
25901            "// ".to_string(),
25902            "// ".to_string(),
25903            "xx \nyy zz aa bb cc".to_string(),
25904            12,
25905            NonZeroU32::new(4).unwrap(),
25906            false,
25907        ),
25908        "// xx yy zz\n// aa bb cc"
25909    );
25910    assert_eq!(
25911        wrap_with_prefix(
25912            String::new(),
25913            String::new(),
25914            "这是什么 \n 钢笔".to_string(),
25915            3,
25916            NonZeroU32::new(4).unwrap(),
25917            false,
25918        ),
25919        "这是什\n么 钢\n"
25920    );
25921    assert_eq!(
25922        wrap_with_prefix(
25923            String::new(),
25924            String::new(),
25925            format!("foo{}bar", '\u{2009}'), // thin space
25926            80,
25927            NonZeroU32::new(4).unwrap(),
25928            false,
25929        ),
25930        format!("foo{}bar", '\u{2009}')
25931    );
25932}
25933
25934pub trait CollaborationHub {
25935    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
25936    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
25937    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
25938}
25939
25940impl CollaborationHub for Entity<Project> {
25941    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
25942        self.read(cx).collaborators()
25943    }
25944
25945    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
25946        self.read(cx).user_store().read(cx).participant_indices()
25947    }
25948
25949    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
25950        let this = self.read(cx);
25951        let user_ids = this.collaborators().values().map(|c| c.user_id);
25952        this.user_store().read(cx).participant_names(user_ids, cx)
25953    }
25954}
25955
25956pub trait SemanticsProvider {
25957    fn hover(
25958        &self,
25959        buffer: &Entity<Buffer>,
25960        position: text::Anchor,
25961        cx: &mut App,
25962    ) -> Option<Task<Option<Vec<project::Hover>>>>;
25963
25964    fn inline_values(
25965        &self,
25966        buffer_handle: Entity<Buffer>,
25967        range: Range<text::Anchor>,
25968        cx: &mut App,
25969    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
25970
25971    fn applicable_inlay_chunks(
25972        &self,
25973        buffer: &Entity<Buffer>,
25974        ranges: &[Range<text::Anchor>],
25975        cx: &mut App,
25976    ) -> Vec<Range<BufferRow>>;
25977
25978    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
25979
25980    fn inlay_hints(
25981        &self,
25982        invalidate: InvalidationStrategy,
25983        buffer: Entity<Buffer>,
25984        ranges: Vec<Range<text::Anchor>>,
25985        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
25986        cx: &mut App,
25987    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
25988
25989    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
25990
25991    fn document_highlights(
25992        &self,
25993        buffer: &Entity<Buffer>,
25994        position: text::Anchor,
25995        cx: &mut App,
25996    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
25997
25998    fn definitions(
25999        &self,
26000        buffer: &Entity<Buffer>,
26001        position: text::Anchor,
26002        kind: GotoDefinitionKind,
26003        cx: &mut App,
26004    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
26005
26006    fn range_for_rename(
26007        &self,
26008        buffer: &Entity<Buffer>,
26009        position: text::Anchor,
26010        cx: &mut App,
26011    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
26012
26013    fn perform_rename(
26014        &self,
26015        buffer: &Entity<Buffer>,
26016        position: text::Anchor,
26017        new_name: String,
26018        cx: &mut App,
26019    ) -> Option<Task<Result<ProjectTransaction>>>;
26020}
26021
26022pub trait CompletionProvider {
26023    fn completions(
26024        &self,
26025        excerpt_id: ExcerptId,
26026        buffer: &Entity<Buffer>,
26027        buffer_position: text::Anchor,
26028        trigger: CompletionContext,
26029        window: &mut Window,
26030        cx: &mut Context<Editor>,
26031    ) -> Task<Result<Vec<CompletionResponse>>>;
26032
26033    fn resolve_completions(
26034        &self,
26035        _buffer: Entity<Buffer>,
26036        _completion_indices: Vec<usize>,
26037        _completions: Rc<RefCell<Box<[Completion]>>>,
26038        _cx: &mut Context<Editor>,
26039    ) -> Task<Result<bool>> {
26040        Task::ready(Ok(false))
26041    }
26042
26043    fn apply_additional_edits_for_completion(
26044        &self,
26045        _buffer: Entity<Buffer>,
26046        _completions: Rc<RefCell<Box<[Completion]>>>,
26047        _completion_index: usize,
26048        _push_to_history: bool,
26049        _cx: &mut Context<Editor>,
26050    ) -> Task<Result<Option<language::Transaction>>> {
26051        Task::ready(Ok(None))
26052    }
26053
26054    fn is_completion_trigger(
26055        &self,
26056        buffer: &Entity<Buffer>,
26057        position: language::Anchor,
26058        text: &str,
26059        trigger_in_words: bool,
26060        cx: &mut Context<Editor>,
26061    ) -> bool;
26062
26063    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
26064
26065    fn sort_completions(&self) -> bool {
26066        true
26067    }
26068
26069    fn filter_completions(&self) -> bool {
26070        true
26071    }
26072
26073    fn show_snippets(&self) -> bool {
26074        false
26075    }
26076}
26077
26078pub trait CodeActionProvider {
26079    fn id(&self) -> Arc<str>;
26080
26081    fn code_actions(
26082        &self,
26083        buffer: &Entity<Buffer>,
26084        range: Range<text::Anchor>,
26085        window: &mut Window,
26086        cx: &mut App,
26087    ) -> Task<Result<Vec<CodeAction>>>;
26088
26089    fn apply_code_action(
26090        &self,
26091        buffer_handle: Entity<Buffer>,
26092        action: CodeAction,
26093        excerpt_id: ExcerptId,
26094        push_to_history: bool,
26095        window: &mut Window,
26096        cx: &mut App,
26097    ) -> Task<Result<ProjectTransaction>>;
26098}
26099
26100impl CodeActionProvider for Entity<Project> {
26101    fn id(&self) -> Arc<str> {
26102        "project".into()
26103    }
26104
26105    fn code_actions(
26106        &self,
26107        buffer: &Entity<Buffer>,
26108        range: Range<text::Anchor>,
26109        _window: &mut Window,
26110        cx: &mut App,
26111    ) -> Task<Result<Vec<CodeAction>>> {
26112        self.update(cx, |project, cx| {
26113            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
26114            let code_actions = project.code_actions(buffer, range, None, cx);
26115            cx.background_spawn(async move {
26116                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
26117                Ok(code_lens_actions
26118                    .context("code lens fetch")?
26119                    .into_iter()
26120                    .flatten()
26121                    .chain(
26122                        code_actions
26123                            .context("code action fetch")?
26124                            .into_iter()
26125                            .flatten(),
26126                    )
26127                    .collect())
26128            })
26129        })
26130    }
26131
26132    fn apply_code_action(
26133        &self,
26134        buffer_handle: Entity<Buffer>,
26135        action: CodeAction,
26136        _excerpt_id: ExcerptId,
26137        push_to_history: bool,
26138        _window: &mut Window,
26139        cx: &mut App,
26140    ) -> Task<Result<ProjectTransaction>> {
26141        self.update(cx, |project, cx| {
26142            project.apply_code_action(buffer_handle, action, push_to_history, cx)
26143        })
26144    }
26145}
26146
26147fn snippet_completions(
26148    project: &Project,
26149    buffer: &Entity<Buffer>,
26150    buffer_anchor: text::Anchor,
26151    classifier: CharClassifier,
26152    cx: &mut App,
26153) -> Task<Result<CompletionResponse>> {
26154    let languages = buffer.read(cx).languages_at(buffer_anchor);
26155    let snippet_store = project.snippets().read(cx);
26156
26157    let scopes: Vec<_> = languages
26158        .iter()
26159        .filter_map(|language| {
26160            let language_name = language.lsp_id();
26161            let snippets = snippet_store.snippets_for(Some(language_name), cx);
26162
26163            if snippets.is_empty() {
26164                None
26165            } else {
26166                Some((language.default_scope(), snippets))
26167            }
26168        })
26169        .collect();
26170
26171    if scopes.is_empty() {
26172        return Task::ready(Ok(CompletionResponse {
26173            completions: vec![],
26174            display_options: CompletionDisplayOptions::default(),
26175            is_incomplete: false,
26176        }));
26177    }
26178
26179    let snapshot = buffer.read(cx).text_snapshot();
26180    let executor = cx.background_executor().clone();
26181
26182    cx.background_spawn(async move {
26183        let is_word_char = |c| classifier.is_word(c);
26184
26185        let mut is_incomplete = false;
26186        let mut completions: Vec<Completion> = Vec::new();
26187
26188        const MAX_PREFIX_LEN: usize = 128;
26189        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
26190        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
26191        let window_start = snapshot.clip_offset(window_start, Bias::Left);
26192
26193        let max_buffer_window: String = snapshot
26194            .text_for_range(window_start..buffer_offset)
26195            .collect();
26196
26197        if max_buffer_window.is_empty() {
26198            return Ok(CompletionResponse {
26199                completions: vec![],
26200                display_options: CompletionDisplayOptions::default(),
26201                is_incomplete: true,
26202            });
26203        }
26204
26205        for (_scope, snippets) in scopes.into_iter() {
26206            // Sort snippets by word count to match longer snippet prefixes first.
26207            let mut sorted_snippet_candidates = snippets
26208                .iter()
26209                .enumerate()
26210                .flat_map(|(snippet_ix, snippet)| {
26211                    snippet
26212                        .prefix
26213                        .iter()
26214                        .enumerate()
26215                        .map(move |(prefix_ix, prefix)| {
26216                            let word_count =
26217                                snippet_candidate_suffixes(prefix, is_word_char).count();
26218                            ((snippet_ix, prefix_ix), prefix, word_count)
26219                        })
26220                })
26221                .collect_vec();
26222            sorted_snippet_candidates
26223                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
26224
26225            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
26226
26227            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
26228                .take(
26229                    sorted_snippet_candidates
26230                        .first()
26231                        .map(|(_, _, word_count)| *word_count)
26232                        .unwrap_or_default(),
26233                )
26234                .collect_vec();
26235
26236            const MAX_RESULTS: usize = 100;
26237            // Each match also remembers how many characters from the buffer it consumed
26238            let mut matches: Vec<(StringMatch, usize)> = vec![];
26239
26240            let mut snippet_list_cutoff_index = 0;
26241            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
26242                let word_count = buffer_index + 1;
26243                // Increase `snippet_list_cutoff_index` until we have all of the
26244                // snippets with sufficiently many words.
26245                while sorted_snippet_candidates
26246                    .get(snippet_list_cutoff_index)
26247                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
26248                        *snippet_word_count >= word_count
26249                    })
26250                {
26251                    snippet_list_cutoff_index += 1;
26252                }
26253
26254                // Take only the candidates with at least `word_count` many words
26255                let snippet_candidates_at_word_len =
26256                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
26257
26258                let candidates = snippet_candidates_at_word_len
26259                    .iter()
26260                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
26261                    .enumerate() // index in `sorted_snippet_candidates`
26262                    // First char must match
26263                    .filter(|(_ix, prefix)| {
26264                        itertools::equal(
26265                            prefix
26266                                .chars()
26267                                .next()
26268                                .into_iter()
26269                                .flat_map(|c| c.to_lowercase()),
26270                            buffer_window
26271                                .chars()
26272                                .next()
26273                                .into_iter()
26274                                .flat_map(|c| c.to_lowercase()),
26275                        )
26276                    })
26277                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
26278                    .collect::<Vec<StringMatchCandidate>>();
26279
26280                matches.extend(
26281                    fuzzy::match_strings(
26282                        &candidates,
26283                        &buffer_window,
26284                        buffer_window.chars().any(|c| c.is_uppercase()),
26285                        true,
26286                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
26287                        &Default::default(),
26288                        executor.clone(),
26289                    )
26290                    .await
26291                    .into_iter()
26292                    .map(|string_match| (string_match, buffer_window.len())),
26293                );
26294
26295                if matches.len() >= MAX_RESULTS {
26296                    break;
26297                }
26298            }
26299
26300            let to_lsp = |point: &text::Anchor| {
26301                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
26302                point_to_lsp(end)
26303            };
26304            let lsp_end = to_lsp(&buffer_anchor);
26305
26306            if matches.len() >= MAX_RESULTS {
26307                is_incomplete = true;
26308            }
26309
26310            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
26311                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
26312                    sorted_snippet_candidates[string_match.candidate_id];
26313                let snippet = &snippets[snippet_index];
26314                let start = buffer_offset - buffer_window_len;
26315                let start = snapshot.anchor_before(start);
26316                let range = start..buffer_anchor;
26317                let lsp_start = to_lsp(&start);
26318                let lsp_range = lsp::Range {
26319                    start: lsp_start,
26320                    end: lsp_end,
26321                };
26322                Completion {
26323                    replace_range: range,
26324                    new_text: snippet.body.clone(),
26325                    source: CompletionSource::Lsp {
26326                        insert_range: None,
26327                        server_id: LanguageServerId(usize::MAX),
26328                        resolved: true,
26329                        lsp_completion: Box::new(lsp::CompletionItem {
26330                            label: snippet.prefix.first().unwrap().clone(),
26331                            kind: Some(CompletionItemKind::SNIPPET),
26332                            label_details: snippet.description.as_ref().map(|description| {
26333                                lsp::CompletionItemLabelDetails {
26334                                    detail: Some(description.clone()),
26335                                    description: None,
26336                                }
26337                            }),
26338                            insert_text_format: Some(InsertTextFormat::SNIPPET),
26339                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
26340                                lsp::InsertReplaceEdit {
26341                                    new_text: snippet.body.clone(),
26342                                    insert: lsp_range,
26343                                    replace: lsp_range,
26344                                },
26345                            )),
26346                            filter_text: Some(snippet.body.clone()),
26347                            sort_text: Some(char::MAX.to_string()),
26348                            ..lsp::CompletionItem::default()
26349                        }),
26350                        lsp_defaults: None,
26351                    },
26352                    label: CodeLabel {
26353                        text: matching_prefix.clone(),
26354                        runs: Vec::new(),
26355                        filter_range: 0..matching_prefix.len(),
26356                    },
26357                    icon_path: None,
26358                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
26359                        single_line: snippet.name.clone().into(),
26360                        plain_text: snippet
26361                            .description
26362                            .clone()
26363                            .map(|description| description.into()),
26364                    }),
26365                    insert_text_mode: None,
26366                    confirm: None,
26367                    match_start: Some(start),
26368                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
26369                }
26370            }));
26371        }
26372
26373        Ok(CompletionResponse {
26374            completions,
26375            display_options: CompletionDisplayOptions::default(),
26376            is_incomplete,
26377        })
26378    })
26379}
26380
26381impl CompletionProvider for Entity<Project> {
26382    fn completions(
26383        &self,
26384        _excerpt_id: ExcerptId,
26385        buffer: &Entity<Buffer>,
26386        buffer_position: text::Anchor,
26387        options: CompletionContext,
26388        _window: &mut Window,
26389        cx: &mut Context<Editor>,
26390    ) -> Task<Result<Vec<CompletionResponse>>> {
26391        self.update(cx, |project, cx| {
26392            let task = project.completions(buffer, buffer_position, options, cx);
26393            cx.background_spawn(task)
26394        })
26395    }
26396
26397    fn resolve_completions(
26398        &self,
26399        buffer: Entity<Buffer>,
26400        completion_indices: Vec<usize>,
26401        completions: Rc<RefCell<Box<[Completion]>>>,
26402        cx: &mut Context<Editor>,
26403    ) -> Task<Result<bool>> {
26404        self.update(cx, |project, cx| {
26405            project.lsp_store().update(cx, |lsp_store, cx| {
26406                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
26407            })
26408        })
26409    }
26410
26411    fn apply_additional_edits_for_completion(
26412        &self,
26413        buffer: Entity<Buffer>,
26414        completions: Rc<RefCell<Box<[Completion]>>>,
26415        completion_index: usize,
26416        push_to_history: bool,
26417        cx: &mut Context<Editor>,
26418    ) -> Task<Result<Option<language::Transaction>>> {
26419        self.update(cx, |project, cx| {
26420            project.lsp_store().update(cx, |lsp_store, cx| {
26421                lsp_store.apply_additional_edits_for_completion(
26422                    buffer,
26423                    completions,
26424                    completion_index,
26425                    push_to_history,
26426                    cx,
26427                )
26428            })
26429        })
26430    }
26431
26432    fn is_completion_trigger(
26433        &self,
26434        buffer: &Entity<Buffer>,
26435        position: language::Anchor,
26436        text: &str,
26437        trigger_in_words: bool,
26438        cx: &mut Context<Editor>,
26439    ) -> bool {
26440        let mut chars = text.chars();
26441        let char = if let Some(char) = chars.next() {
26442            char
26443        } else {
26444            return false;
26445        };
26446        if chars.next().is_some() {
26447            return false;
26448        }
26449
26450        let buffer = buffer.read(cx);
26451        let snapshot = buffer.snapshot();
26452        let classifier = snapshot
26453            .char_classifier_at(position)
26454            .scope_context(Some(CharScopeContext::Completion));
26455        if trigger_in_words && classifier.is_word(char) {
26456            return true;
26457        }
26458
26459        buffer.completion_triggers().contains(text)
26460    }
26461
26462    fn show_snippets(&self) -> bool {
26463        true
26464    }
26465}
26466
26467impl SemanticsProvider for Entity<Project> {
26468    fn hover(
26469        &self,
26470        buffer: &Entity<Buffer>,
26471        position: text::Anchor,
26472        cx: &mut App,
26473    ) -> Option<Task<Option<Vec<project::Hover>>>> {
26474        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
26475    }
26476
26477    fn document_highlights(
26478        &self,
26479        buffer: &Entity<Buffer>,
26480        position: text::Anchor,
26481        cx: &mut App,
26482    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
26483        Some(self.update(cx, |project, cx| {
26484            project.document_highlights(buffer, position, cx)
26485        }))
26486    }
26487
26488    fn definitions(
26489        &self,
26490        buffer: &Entity<Buffer>,
26491        position: text::Anchor,
26492        kind: GotoDefinitionKind,
26493        cx: &mut App,
26494    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
26495        Some(self.update(cx, |project, cx| match kind {
26496            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
26497            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
26498            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
26499            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
26500        }))
26501    }
26502
26503    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
26504        self.update(cx, |project, cx| {
26505            if project
26506                .active_debug_session(cx)
26507                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
26508            {
26509                return true;
26510            }
26511
26512            buffer.update(cx, |buffer, cx| {
26513                project.any_language_server_supports_inlay_hints(buffer, cx)
26514            })
26515        })
26516    }
26517
26518    fn inline_values(
26519        &self,
26520        buffer_handle: Entity<Buffer>,
26521        range: Range<text::Anchor>,
26522        cx: &mut App,
26523    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
26524        self.update(cx, |project, cx| {
26525            let (session, active_stack_frame) = project.active_debug_session(cx)?;
26526
26527            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
26528        })
26529    }
26530
26531    fn applicable_inlay_chunks(
26532        &self,
26533        buffer: &Entity<Buffer>,
26534        ranges: &[Range<text::Anchor>],
26535        cx: &mut App,
26536    ) -> Vec<Range<BufferRow>> {
26537        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
26538            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
26539        })
26540    }
26541
26542    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
26543        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
26544            lsp_store.invalidate_inlay_hints(for_buffers)
26545        });
26546    }
26547
26548    fn inlay_hints(
26549        &self,
26550        invalidate: InvalidationStrategy,
26551        buffer: Entity<Buffer>,
26552        ranges: Vec<Range<text::Anchor>>,
26553        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26554        cx: &mut App,
26555    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
26556        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
26557            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
26558        }))
26559    }
26560
26561    fn range_for_rename(
26562        &self,
26563        buffer: &Entity<Buffer>,
26564        position: text::Anchor,
26565        cx: &mut App,
26566    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
26567        Some(self.update(cx, |project, cx| {
26568            let buffer = buffer.clone();
26569            let task = project.prepare_rename(buffer.clone(), position, cx);
26570            cx.spawn(async move |_, cx| {
26571                Ok(match task.await? {
26572                    PrepareRenameResponse::Success(range) => Some(range),
26573                    PrepareRenameResponse::InvalidPosition => None,
26574                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
26575                        // Fallback on using TreeSitter info to determine identifier range
26576                        buffer.read_with(cx, |buffer, _| {
26577                            let snapshot = buffer.snapshot();
26578                            let (range, kind) = snapshot.surrounding_word(position, None);
26579                            if kind != Some(CharKind::Word) {
26580                                return None;
26581                            }
26582                            Some(
26583                                snapshot.anchor_before(range.start)
26584                                    ..snapshot.anchor_after(range.end),
26585                            )
26586                        })
26587                    }
26588                })
26589            })
26590        }))
26591    }
26592
26593    fn perform_rename(
26594        &self,
26595        buffer: &Entity<Buffer>,
26596        position: text::Anchor,
26597        new_name: String,
26598        cx: &mut App,
26599    ) -> Option<Task<Result<ProjectTransaction>>> {
26600        Some(self.update(cx, |project, cx| {
26601            project.perform_rename(buffer.clone(), position, new_name, cx)
26602        }))
26603    }
26604}
26605
26606fn consume_contiguous_rows(
26607    contiguous_row_selections: &mut Vec<Selection<Point>>,
26608    selection: &Selection<Point>,
26609    display_map: &DisplaySnapshot,
26610    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
26611) -> (MultiBufferRow, MultiBufferRow) {
26612    contiguous_row_selections.push(selection.clone());
26613    let start_row = starting_row(selection, display_map);
26614    let mut end_row = ending_row(selection, display_map);
26615
26616    while let Some(next_selection) = selections.peek() {
26617        if next_selection.start.row <= end_row.0 {
26618            end_row = ending_row(next_selection, display_map);
26619            contiguous_row_selections.push(selections.next().unwrap().clone());
26620        } else {
26621            break;
26622        }
26623    }
26624    (start_row, end_row)
26625}
26626
26627fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
26628    if selection.start.column > 0 {
26629        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
26630    } else {
26631        MultiBufferRow(selection.start.row)
26632    }
26633}
26634
26635fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
26636    if next_selection.end.column > 0 || next_selection.is_empty() {
26637        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
26638    } else {
26639        MultiBufferRow(next_selection.end.row)
26640    }
26641}
26642
26643impl EditorSnapshot {
26644    pub fn remote_selections_in_range<'a>(
26645        &'a self,
26646        range: &'a Range<Anchor>,
26647        collaboration_hub: &dyn CollaborationHub,
26648        cx: &'a App,
26649    ) -> impl 'a + Iterator<Item = RemoteSelection> {
26650        let participant_names = collaboration_hub.user_names(cx);
26651        let participant_indices = collaboration_hub.user_participant_indices(cx);
26652        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
26653        let collaborators_by_replica_id = collaborators_by_peer_id
26654            .values()
26655            .map(|collaborator| (collaborator.replica_id, collaborator))
26656            .collect::<HashMap<_, _>>();
26657        self.buffer_snapshot()
26658            .selections_in_range(range, false)
26659            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
26660                if replica_id == ReplicaId::AGENT {
26661                    Some(RemoteSelection {
26662                        replica_id,
26663                        selection,
26664                        cursor_shape,
26665                        line_mode,
26666                        collaborator_id: CollaboratorId::Agent,
26667                        user_name: Some("Agent".into()),
26668                        color: cx.theme().players().agent(),
26669                    })
26670                } else {
26671                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
26672                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
26673                    let user_name = participant_names.get(&collaborator.user_id).cloned();
26674                    Some(RemoteSelection {
26675                        replica_id,
26676                        selection,
26677                        cursor_shape,
26678                        line_mode,
26679                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
26680                        user_name,
26681                        color: if let Some(index) = participant_index {
26682                            cx.theme().players().color_for_participant(index.0)
26683                        } else {
26684                            cx.theme().players().absent()
26685                        },
26686                    })
26687                }
26688            })
26689    }
26690
26691    pub fn hunks_for_ranges(
26692        &self,
26693        ranges: impl IntoIterator<Item = Range<Point>>,
26694    ) -> Vec<MultiBufferDiffHunk> {
26695        let mut hunks = Vec::new();
26696        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
26697            HashMap::default();
26698        for query_range in ranges {
26699            let query_rows =
26700                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
26701            for hunk in self.buffer_snapshot().diff_hunks_in_range(
26702                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
26703            ) {
26704                // Include deleted hunks that are adjacent to the query range, because
26705                // otherwise they would be missed.
26706                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
26707                if hunk.status().is_deleted() {
26708                    intersects_range |= hunk.row_range.start == query_rows.end;
26709                    intersects_range |= hunk.row_range.end == query_rows.start;
26710                }
26711                if intersects_range {
26712                    if !processed_buffer_rows
26713                        .entry(hunk.buffer_id)
26714                        .or_default()
26715                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
26716                    {
26717                        continue;
26718                    }
26719                    hunks.push(hunk);
26720                }
26721            }
26722        }
26723
26724        hunks
26725    }
26726
26727    fn display_diff_hunks_for_rows<'a>(
26728        &'a self,
26729        display_rows: Range<DisplayRow>,
26730        folded_buffers: &'a HashSet<BufferId>,
26731    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
26732        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
26733        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
26734
26735        self.buffer_snapshot()
26736            .diff_hunks_in_range(buffer_start..buffer_end)
26737            .filter_map(|hunk| {
26738                if folded_buffers.contains(&hunk.buffer_id) {
26739                    return None;
26740                }
26741
26742                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
26743                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
26744
26745                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
26746                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
26747
26748                let display_hunk = if hunk_display_start.column() != 0 {
26749                    DisplayDiffHunk::Folded {
26750                        display_row: hunk_display_start.row(),
26751                    }
26752                } else {
26753                    let mut end_row = hunk_display_end.row();
26754                    if hunk_display_end.column() > 0 {
26755                        end_row.0 += 1;
26756                    }
26757                    let is_created_file = hunk.is_created_file();
26758
26759                    DisplayDiffHunk::Unfolded {
26760                        status: hunk.status(),
26761                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
26762                            ..hunk.diff_base_byte_range.end.0,
26763                        word_diffs: hunk.word_diffs,
26764                        display_row_range: hunk_display_start.row()..end_row,
26765                        multi_buffer_range: Anchor::range_in_buffer(
26766                            hunk.excerpt_id,
26767                            hunk.buffer_range,
26768                        ),
26769                        is_created_file,
26770                    }
26771                };
26772
26773                Some(display_hunk)
26774            })
26775    }
26776
26777    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
26778        self.display_snapshot
26779            .buffer_snapshot()
26780            .language_at(position)
26781    }
26782
26783    pub fn is_focused(&self) -> bool {
26784        self.is_focused
26785    }
26786
26787    pub fn placeholder_text(&self) -> Option<String> {
26788        self.placeholder_display_snapshot
26789            .as_ref()
26790            .map(|display_map| display_map.text())
26791    }
26792
26793    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
26794        self.scroll_anchor.scroll_position(&self.display_snapshot)
26795    }
26796
26797    pub fn gutter_dimensions(
26798        &self,
26799        font_id: FontId,
26800        font_size: Pixels,
26801        style: &EditorStyle,
26802        window: &mut Window,
26803        cx: &App,
26804    ) -> GutterDimensions {
26805        if self.show_gutter
26806            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
26807            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
26808        {
26809            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
26810                matches!(
26811                    ProjectSettings::get_global(cx).git.git_gutter,
26812                    GitGutterSetting::TrackedFiles
26813                )
26814            });
26815            let gutter_settings = EditorSettings::get_global(cx).gutter;
26816            let show_line_numbers = self
26817                .show_line_numbers
26818                .unwrap_or(gutter_settings.line_numbers);
26819            let line_gutter_width = if show_line_numbers {
26820                // Avoid flicker-like gutter resizes when the line number gains another digit by
26821                // only resizing the gutter on files with > 10**min_line_number_digits lines.
26822                let min_width_for_number_on_gutter =
26823                    ch_advance * gutter_settings.min_line_number_digits as f32;
26824                self.max_line_number_width(style, window)
26825                    .max(min_width_for_number_on_gutter)
26826            } else {
26827                0.0.into()
26828            };
26829
26830            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
26831            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
26832
26833            let git_blame_entries_width =
26834                self.git_blame_gutter_max_author_length
26835                    .map(|max_author_length| {
26836                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
26837                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
26838
26839                        /// The number of characters to dedicate to gaps and margins.
26840                        const SPACING_WIDTH: usize = 4;
26841
26842                        let max_char_count = max_author_length.min(renderer.max_author_length())
26843                            + ::git::SHORT_SHA_LENGTH
26844                            + MAX_RELATIVE_TIMESTAMP.len()
26845                            + SPACING_WIDTH;
26846
26847                        ch_advance * max_char_count
26848                    });
26849
26850            let is_singleton = self.buffer_snapshot().is_singleton();
26851
26852            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
26853            left_padding += if !is_singleton {
26854                ch_width * 4.0
26855            } else if show_runnables || show_breakpoints {
26856                ch_width * 3.0
26857            } else if show_git_gutter && show_line_numbers {
26858                ch_width * 2.0
26859            } else if show_git_gutter || show_line_numbers {
26860                ch_width
26861            } else {
26862                px(0.)
26863            };
26864
26865            let shows_folds = is_singleton && gutter_settings.folds;
26866
26867            let right_padding = if shows_folds && show_line_numbers {
26868                ch_width * 4.0
26869            } else if shows_folds || (!is_singleton && show_line_numbers) {
26870                ch_width * 3.0
26871            } else if show_line_numbers {
26872                ch_width
26873            } else {
26874                px(0.)
26875            };
26876
26877            GutterDimensions {
26878                left_padding,
26879                right_padding,
26880                width: line_gutter_width + left_padding + right_padding,
26881                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
26882                git_blame_entries_width,
26883            }
26884        } else if self.offset_content {
26885            GutterDimensions::default_with_margin(font_id, font_size, cx)
26886        } else {
26887            GutterDimensions::default()
26888        }
26889    }
26890
26891    pub fn render_crease_toggle(
26892        &self,
26893        buffer_row: MultiBufferRow,
26894        row_contains_cursor: bool,
26895        editor: Entity<Editor>,
26896        window: &mut Window,
26897        cx: &mut App,
26898    ) -> Option<AnyElement> {
26899        let folded = self.is_line_folded(buffer_row);
26900        let mut is_foldable = false;
26901
26902        if let Some(crease) = self
26903            .crease_snapshot
26904            .query_row(buffer_row, self.buffer_snapshot())
26905        {
26906            is_foldable = true;
26907            match crease {
26908                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
26909                    if let Some(render_toggle) = render_toggle {
26910                        let toggle_callback =
26911                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
26912                                if folded {
26913                                    editor.update(cx, |editor, cx| {
26914                                        editor.fold_at(buffer_row, window, cx)
26915                                    });
26916                                } else {
26917                                    editor.update(cx, |editor, cx| {
26918                                        editor.unfold_at(buffer_row, window, cx)
26919                                    });
26920                                }
26921                            });
26922                        return Some((render_toggle)(
26923                            buffer_row,
26924                            folded,
26925                            toggle_callback,
26926                            window,
26927                            cx,
26928                        ));
26929                    }
26930                }
26931            }
26932        }
26933
26934        is_foldable |= self.starts_indent(buffer_row);
26935
26936        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
26937            Some(
26938                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
26939                    .toggle_state(folded)
26940                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
26941                        if folded {
26942                            this.unfold_at(buffer_row, window, cx);
26943                        } else {
26944                            this.fold_at(buffer_row, window, cx);
26945                        }
26946                    }))
26947                    .into_any_element(),
26948            )
26949        } else {
26950            None
26951        }
26952    }
26953
26954    pub fn render_crease_trailer(
26955        &self,
26956        buffer_row: MultiBufferRow,
26957        window: &mut Window,
26958        cx: &mut App,
26959    ) -> Option<AnyElement> {
26960        let folded = self.is_line_folded(buffer_row);
26961        if let Crease::Inline { render_trailer, .. } = self
26962            .crease_snapshot
26963            .query_row(buffer_row, self.buffer_snapshot())?
26964        {
26965            let render_trailer = render_trailer.as_ref()?;
26966            Some(render_trailer(buffer_row, folded, window, cx))
26967        } else {
26968            None
26969        }
26970    }
26971
26972    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
26973        let digit_count = self.widest_line_number().ilog10() + 1;
26974        column_pixels(style, digit_count as usize, window)
26975    }
26976
26977    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
26978    ///
26979    /// This is positive if `base` is before `line`.
26980    fn relative_line_delta(
26981        &self,
26982        current_selection_head: DisplayRow,
26983        first_visible_row: DisplayRow,
26984        consider_wrapped_lines: bool,
26985    ) -> i64 {
26986        let current_selection_head = current_selection_head.as_display_point().to_point(self);
26987        let first_visible_row = first_visible_row.as_display_point().to_point(self);
26988
26989        if consider_wrapped_lines {
26990            let wrap_snapshot = self.wrap_snapshot();
26991            let base_wrap_row = wrap_snapshot
26992                .make_wrap_point(current_selection_head, Bias::Left)
26993                .row();
26994            let wrap_row = wrap_snapshot
26995                .make_wrap_point(first_visible_row, Bias::Left)
26996                .row();
26997
26998            wrap_row.0 as i64 - base_wrap_row.0 as i64
26999        } else {
27000            let fold_snapshot = self.fold_snapshot();
27001            let base_fold_row = fold_snapshot
27002                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
27003                .row();
27004            let fold_row = fold_snapshot
27005                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
27006                .row();
27007
27008            fold_row as i64 - base_fold_row as i64
27009        }
27010    }
27011
27012    /// Returns the unsigned relative line number to display for each row in `rows`.
27013    ///
27014    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
27015    pub fn calculate_relative_line_numbers(
27016        &self,
27017        rows: &Range<DisplayRow>,
27018        current_selection_head: DisplayRow,
27019        count_wrapped_lines: bool,
27020    ) -> HashMap<DisplayRow, u32> {
27021        let initial_offset =
27022            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
27023        let current_selection_point = current_selection_head.as_display_point().to_point(self);
27024
27025        self.row_infos(rows.start)
27026            .take(rows.len())
27027            .enumerate()
27028            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
27029            .filter(|(_row, row_info)| {
27030                row_info.buffer_row.is_some()
27031                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
27032            })
27033            .enumerate()
27034            .filter(|(_, (row, row_info))| {
27035                // We want to check here that
27036                // - the row is not the current selection head to ensure the current
27037                // line has absolute numbering
27038                // - similarly, should the selection head live in a soft-wrapped line
27039                // and we are not counting those, that the parent line keeps its
27040                // absolute number
27041                // - lastly, if we are in a deleted line, it is fine to number this
27042                // relative with 0, as otherwise it would have no line number at all
27043                (*row != current_selection_head
27044                    && (count_wrapped_lines
27045                        || row_info.buffer_row != Some(current_selection_point.row)))
27046                    || row_info
27047                        .diff_status
27048                        .is_some_and(|status| status.is_deleted())
27049            })
27050            .map(|(i, (row, _))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
27051            .collect()
27052    }
27053}
27054
27055pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
27056    let font_size = style.text.font_size.to_pixels(window.rem_size());
27057    let layout = window.text_system().shape_line(
27058        SharedString::from(" ".repeat(column)),
27059        font_size,
27060        &[TextRun {
27061            len: column,
27062            font: style.text.font(),
27063            color: Hsla::default(),
27064            ..Default::default()
27065        }],
27066        None,
27067    );
27068
27069    layout.width
27070}
27071
27072impl Deref for EditorSnapshot {
27073    type Target = DisplaySnapshot;
27074
27075    fn deref(&self) -> &Self::Target {
27076        &self.display_snapshot
27077    }
27078}
27079
27080#[derive(Clone, Debug, PartialEq, Eq)]
27081pub enum EditorEvent {
27082    /// Emitted when the stored review comments change (added, removed, or updated).
27083    ReviewCommentsChanged {
27084        /// The new total count of review comments.
27085        total_count: usize,
27086    },
27087    InputIgnored {
27088        text: Arc<str>,
27089    },
27090    InputHandled {
27091        utf16_range_to_replace: Option<Range<isize>>,
27092        text: Arc<str>,
27093    },
27094    ExcerptsAdded {
27095        buffer: Entity<Buffer>,
27096        predecessor: ExcerptId,
27097        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
27098    },
27099    ExcerptsRemoved {
27100        ids: Vec<ExcerptId>,
27101        removed_buffer_ids: Vec<BufferId>,
27102    },
27103    BufferFoldToggled {
27104        ids: Vec<ExcerptId>,
27105        folded: bool,
27106    },
27107    ExcerptsEdited {
27108        ids: Vec<ExcerptId>,
27109    },
27110    ExcerptsExpanded {
27111        ids: Vec<ExcerptId>,
27112    },
27113    ExpandExcerptsRequested {
27114        excerpt_ids: Vec<ExcerptId>,
27115        lines: u32,
27116        direction: ExpandExcerptDirection,
27117    },
27118    BufferEdited,
27119    Edited {
27120        transaction_id: clock::Lamport,
27121    },
27122    Reparsed(BufferId),
27123    Focused,
27124    FocusedIn,
27125    Blurred,
27126    DirtyChanged,
27127    Saved,
27128    TitleChanged,
27129    SelectionsChanged {
27130        local: bool,
27131    },
27132    ScrollPositionChanged {
27133        local: bool,
27134        autoscroll: bool,
27135    },
27136    TransactionUndone {
27137        transaction_id: clock::Lamport,
27138    },
27139    TransactionBegun {
27140        transaction_id: clock::Lamport,
27141    },
27142    CursorShapeChanged,
27143    BreadcrumbsChanged,
27144    PushedToNavHistory {
27145        anchor: Anchor,
27146        is_deactivate: bool,
27147    },
27148}
27149
27150impl EventEmitter<EditorEvent> for Editor {}
27151
27152impl Focusable for Editor {
27153    fn focus_handle(&self, _cx: &App) -> FocusHandle {
27154        self.focus_handle.clone()
27155    }
27156}
27157
27158impl Render for Editor {
27159    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
27160        EditorElement::new(&cx.entity(), self.create_style(cx))
27161    }
27162}
27163
27164impl EntityInputHandler for Editor {
27165    fn text_for_range(
27166        &mut self,
27167        range_utf16: Range<usize>,
27168        adjusted_range: &mut Option<Range<usize>>,
27169        _: &mut Window,
27170        cx: &mut Context<Self>,
27171    ) -> Option<String> {
27172        let snapshot = self.buffer.read(cx).read(cx);
27173        let start = snapshot.clip_offset_utf16(
27174            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
27175            Bias::Left,
27176        );
27177        let end = snapshot.clip_offset_utf16(
27178            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
27179            Bias::Right,
27180        );
27181        if (start.0.0..end.0.0) != range_utf16 {
27182            adjusted_range.replace(start.0.0..end.0.0);
27183        }
27184        Some(snapshot.text_for_range(start..end).collect())
27185    }
27186
27187    fn selected_text_range(
27188        &mut self,
27189        ignore_disabled_input: bool,
27190        _: &mut Window,
27191        cx: &mut Context<Self>,
27192    ) -> Option<UTF16Selection> {
27193        // Prevent the IME menu from appearing when holding down an alphabetic key
27194        // while input is disabled.
27195        if !ignore_disabled_input && !self.input_enabled {
27196            return None;
27197        }
27198
27199        let selection = self
27200            .selections
27201            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
27202        let range = selection.range();
27203
27204        Some(UTF16Selection {
27205            range: range.start.0.0..range.end.0.0,
27206            reversed: selection.reversed,
27207        })
27208    }
27209
27210    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
27211        let snapshot = self.buffer.read(cx).read(cx);
27212        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
27213        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
27214    }
27215
27216    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
27217        self.clear_highlights::<InputComposition>(cx);
27218        self.ime_transaction.take();
27219    }
27220
27221    fn replace_text_in_range(
27222        &mut self,
27223        range_utf16: Option<Range<usize>>,
27224        text: &str,
27225        window: &mut Window,
27226        cx: &mut Context<Self>,
27227    ) {
27228        if !self.input_enabled {
27229            cx.emit(EditorEvent::InputIgnored { text: text.into() });
27230            return;
27231        }
27232
27233        self.transact(window, cx, |this, window, cx| {
27234            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
27235                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27236                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27237                Some(this.selection_replacement_ranges(range_utf16, cx))
27238            } else {
27239                this.marked_text_ranges(cx)
27240            };
27241
27242            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
27243                let newest_selection_id = this.selections.newest_anchor().id;
27244                this.selections
27245                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27246                    .iter()
27247                    .zip(ranges_to_replace.iter())
27248                    .find_map(|(selection, range)| {
27249                        if selection.id == newest_selection_id {
27250                            Some(
27251                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27252                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27253                            )
27254                        } else {
27255                            None
27256                        }
27257                    })
27258            });
27259
27260            cx.emit(EditorEvent::InputHandled {
27261                utf16_range_to_replace: range_to_replace,
27262                text: text.into(),
27263            });
27264
27265            if let Some(new_selected_ranges) = new_selected_ranges {
27266                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27267                    selections.select_ranges(new_selected_ranges)
27268                });
27269                this.backspace(&Default::default(), window, cx);
27270            }
27271
27272            this.handle_input(text, window, cx);
27273        });
27274
27275        if let Some(transaction) = self.ime_transaction {
27276            self.buffer.update(cx, |buffer, cx| {
27277                buffer.group_until_transaction(transaction, cx);
27278            });
27279        }
27280
27281        self.unmark_text(window, cx);
27282    }
27283
27284    fn replace_and_mark_text_in_range(
27285        &mut self,
27286        range_utf16: Option<Range<usize>>,
27287        text: &str,
27288        new_selected_range_utf16: Option<Range<usize>>,
27289        window: &mut Window,
27290        cx: &mut Context<Self>,
27291    ) {
27292        if !self.input_enabled {
27293            return;
27294        }
27295
27296        let transaction = self.transact(window, cx, |this, window, cx| {
27297            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
27298                let snapshot = this.buffer.read(cx).read(cx);
27299                if let Some(relative_range_utf16) = range_utf16.as_ref() {
27300                    for marked_range in &mut marked_ranges {
27301                        marked_range.end = marked_range.start + relative_range_utf16.end;
27302                        marked_range.start += relative_range_utf16.start;
27303                        marked_range.start =
27304                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
27305                        marked_range.end =
27306                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
27307                    }
27308                }
27309                Some(marked_ranges)
27310            } else if let Some(range_utf16) = range_utf16 {
27311                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27312                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27313                Some(this.selection_replacement_ranges(range_utf16, cx))
27314            } else {
27315                None
27316            };
27317
27318            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
27319                let newest_selection_id = this.selections.newest_anchor().id;
27320                this.selections
27321                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27322                    .iter()
27323                    .zip(ranges_to_replace.iter())
27324                    .find_map(|(selection, range)| {
27325                        if selection.id == newest_selection_id {
27326                            Some(
27327                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27328                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27329                            )
27330                        } else {
27331                            None
27332                        }
27333                    })
27334            });
27335
27336            cx.emit(EditorEvent::InputHandled {
27337                utf16_range_to_replace: range_to_replace,
27338                text: text.into(),
27339            });
27340
27341            if let Some(ranges) = ranges_to_replace {
27342                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
27343                    s.select_ranges(ranges)
27344                });
27345            }
27346
27347            let marked_ranges = {
27348                let snapshot = this.buffer.read(cx).read(cx);
27349                this.selections
27350                    .disjoint_anchors_arc()
27351                    .iter()
27352                    .map(|selection| {
27353                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
27354                    })
27355                    .collect::<Vec<_>>()
27356            };
27357
27358            if text.is_empty() {
27359                this.unmark_text(window, cx);
27360            } else {
27361                this.highlight_text::<InputComposition>(
27362                    marked_ranges.clone(),
27363                    HighlightStyle {
27364                        underline: Some(UnderlineStyle {
27365                            thickness: px(1.),
27366                            color: None,
27367                            wavy: false,
27368                        }),
27369                        ..Default::default()
27370                    },
27371                    cx,
27372                );
27373            }
27374
27375            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
27376            let use_autoclose = this.use_autoclose;
27377            let use_auto_surround = this.use_auto_surround;
27378            this.set_use_autoclose(false);
27379            this.set_use_auto_surround(false);
27380            this.handle_input(text, window, cx);
27381            this.set_use_autoclose(use_autoclose);
27382            this.set_use_auto_surround(use_auto_surround);
27383
27384            if let Some(new_selected_range) = new_selected_range_utf16 {
27385                let snapshot = this.buffer.read(cx).read(cx);
27386                let new_selected_ranges = marked_ranges
27387                    .into_iter()
27388                    .map(|marked_range| {
27389                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
27390                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
27391                            insertion_start.0 + new_selected_range.start,
27392                        ));
27393                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
27394                            insertion_start.0 + new_selected_range.end,
27395                        ));
27396                        snapshot.clip_offset_utf16(new_start, Bias::Left)
27397                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
27398                    })
27399                    .collect::<Vec<_>>();
27400
27401                drop(snapshot);
27402                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27403                    selections.select_ranges(new_selected_ranges)
27404                });
27405            }
27406        });
27407
27408        self.ime_transaction = self.ime_transaction.or(transaction);
27409        if let Some(transaction) = self.ime_transaction {
27410            self.buffer.update(cx, |buffer, cx| {
27411                buffer.group_until_transaction(transaction, cx);
27412            });
27413        }
27414
27415        if self.text_highlights::<InputComposition>(cx).is_none() {
27416            self.ime_transaction.take();
27417        }
27418    }
27419
27420    fn bounds_for_range(
27421        &mut self,
27422        range_utf16: Range<usize>,
27423        element_bounds: gpui::Bounds<Pixels>,
27424        window: &mut Window,
27425        cx: &mut Context<Self>,
27426    ) -> Option<gpui::Bounds<Pixels>> {
27427        let text_layout_details = self.text_layout_details(window);
27428        let CharacterDimensions {
27429            em_width,
27430            em_advance,
27431            line_height,
27432        } = self.character_dimensions(window);
27433
27434        let snapshot = self.snapshot(window, cx);
27435        let scroll_position = snapshot.scroll_position();
27436        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
27437
27438        let start =
27439            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
27440        let x = Pixels::from(
27441            ScrollOffset::from(
27442                snapshot.x_for_display_point(start, &text_layout_details)
27443                    + self.gutter_dimensions.full_width(),
27444            ) - scroll_left,
27445        );
27446        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
27447
27448        Some(Bounds {
27449            origin: element_bounds.origin + point(x, y),
27450            size: size(em_width, line_height),
27451        })
27452    }
27453
27454    fn character_index_for_point(
27455        &mut self,
27456        point: gpui::Point<Pixels>,
27457        _window: &mut Window,
27458        _cx: &mut Context<Self>,
27459    ) -> Option<usize> {
27460        let position_map = self.last_position_map.as_ref()?;
27461        if !position_map.text_hitbox.contains(&point) {
27462            return None;
27463        }
27464        let display_point = position_map.point_for_position(point).previous_valid;
27465        let anchor = position_map
27466            .snapshot
27467            .display_point_to_anchor(display_point, Bias::Left);
27468        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
27469        Some(utf16_offset.0.0)
27470    }
27471
27472    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
27473        self.input_enabled
27474    }
27475}
27476
27477trait SelectionExt {
27478    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
27479    fn spanned_rows(
27480        &self,
27481        include_end_if_at_line_start: bool,
27482        map: &DisplaySnapshot,
27483    ) -> Range<MultiBufferRow>;
27484}
27485
27486impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
27487    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
27488        let start = self
27489            .start
27490            .to_point(map.buffer_snapshot())
27491            .to_display_point(map);
27492        let end = self
27493            .end
27494            .to_point(map.buffer_snapshot())
27495            .to_display_point(map);
27496        if self.reversed {
27497            end..start
27498        } else {
27499            start..end
27500        }
27501    }
27502
27503    fn spanned_rows(
27504        &self,
27505        include_end_if_at_line_start: bool,
27506        map: &DisplaySnapshot,
27507    ) -> Range<MultiBufferRow> {
27508        let start = self.start.to_point(map.buffer_snapshot());
27509        let mut end = self.end.to_point(map.buffer_snapshot());
27510        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
27511            end.row -= 1;
27512        }
27513
27514        let buffer_start = map.prev_line_boundary(start).0;
27515        let buffer_end = map.next_line_boundary(end).0;
27516        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
27517    }
27518}
27519
27520impl<T: InvalidationRegion> InvalidationStack<T> {
27521    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
27522    where
27523        S: Clone + ToOffset,
27524    {
27525        while let Some(region) = self.last() {
27526            let all_selections_inside_invalidation_ranges =
27527                if selections.len() == region.ranges().len() {
27528                    selections
27529                        .iter()
27530                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
27531                        .all(|(selection, invalidation_range)| {
27532                            let head = selection.head().to_offset(buffer);
27533                            invalidation_range.start <= head && invalidation_range.end >= head
27534                        })
27535                } else {
27536                    false
27537                };
27538
27539            if all_selections_inside_invalidation_ranges {
27540                break;
27541            } else {
27542                self.pop();
27543            }
27544        }
27545    }
27546}
27547
27548impl<T> Default for InvalidationStack<T> {
27549    fn default() -> Self {
27550        Self(Default::default())
27551    }
27552}
27553
27554impl<T> Deref for InvalidationStack<T> {
27555    type Target = Vec<T>;
27556
27557    fn deref(&self) -> &Self::Target {
27558        &self.0
27559    }
27560}
27561
27562impl<T> DerefMut for InvalidationStack<T> {
27563    fn deref_mut(&mut self) -> &mut Self::Target {
27564        &mut self.0
27565    }
27566}
27567
27568impl InvalidationRegion for SnippetState {
27569    fn ranges(&self) -> &[Range<Anchor>] {
27570        &self.ranges[self.active_index]
27571    }
27572}
27573
27574fn edit_prediction_edit_text(
27575    current_snapshot: &BufferSnapshot,
27576    edits: &[(Range<Anchor>, impl AsRef<str>)],
27577    edit_preview: &EditPreview,
27578    include_deletions: bool,
27579    cx: &App,
27580) -> HighlightedText {
27581    let edits = edits
27582        .iter()
27583        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
27584        .collect::<Vec<_>>();
27585
27586    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
27587}
27588
27589fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
27590    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
27591    // Just show the raw edit text with basic styling
27592    let mut text = String::new();
27593    let mut highlights = Vec::new();
27594
27595    let insertion_highlight_style = HighlightStyle {
27596        color: Some(cx.theme().colors().text),
27597        ..Default::default()
27598    };
27599
27600    for (_, edit_text) in edits {
27601        let start_offset = text.len();
27602        text.push_str(edit_text);
27603        let end_offset = text.len();
27604
27605        if start_offset < end_offset {
27606            highlights.push((start_offset..end_offset, insertion_highlight_style));
27607        }
27608    }
27609
27610    HighlightedText {
27611        text: text.into(),
27612        highlights,
27613    }
27614}
27615
27616pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
27617    match severity {
27618        lsp::DiagnosticSeverity::ERROR => colors.error,
27619        lsp::DiagnosticSeverity::WARNING => colors.warning,
27620        lsp::DiagnosticSeverity::INFORMATION => colors.info,
27621        lsp::DiagnosticSeverity::HINT => colors.info,
27622        _ => colors.ignored,
27623    }
27624}
27625
27626pub fn styled_runs_for_code_label<'a>(
27627    label: &'a CodeLabel,
27628    syntax_theme: &'a theme::SyntaxTheme,
27629    local_player: &'a theme::PlayerColor,
27630) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
27631    let fade_out = HighlightStyle {
27632        fade_out: Some(0.35),
27633        ..Default::default()
27634    };
27635
27636    let mut prev_end = label.filter_range.end;
27637    label
27638        .runs
27639        .iter()
27640        .enumerate()
27641        .flat_map(move |(ix, (range, highlight_id))| {
27642            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
27643                HighlightStyle {
27644                    color: Some(local_player.cursor),
27645                    ..Default::default()
27646                }
27647            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
27648                HighlightStyle {
27649                    background_color: Some(local_player.selection),
27650                    ..Default::default()
27651                }
27652            } else if let Some(style) = highlight_id.style(syntax_theme) {
27653                style
27654            } else {
27655                return Default::default();
27656            };
27657            let muted_style = style.highlight(fade_out);
27658
27659            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
27660            if range.start >= label.filter_range.end {
27661                if range.start > prev_end {
27662                    runs.push((prev_end..range.start, fade_out));
27663                }
27664                runs.push((range.clone(), muted_style));
27665            } else if range.end <= label.filter_range.end {
27666                runs.push((range.clone(), style));
27667            } else {
27668                runs.push((range.start..label.filter_range.end, style));
27669                runs.push((label.filter_range.end..range.end, muted_style));
27670            }
27671            prev_end = cmp::max(prev_end, range.end);
27672
27673            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
27674                runs.push((prev_end..label.text.len(), fade_out));
27675            }
27676
27677            runs
27678        })
27679}
27680
27681pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
27682    let mut prev_index = 0;
27683    let mut prev_codepoint: Option<char> = None;
27684    text.char_indices()
27685        .chain([(text.len(), '\0')])
27686        .filter_map(move |(index, codepoint)| {
27687            let prev_codepoint = prev_codepoint.replace(codepoint)?;
27688            let is_boundary = index == text.len()
27689                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
27690                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
27691            if is_boundary {
27692                let chunk = &text[prev_index..index];
27693                prev_index = index;
27694                Some(chunk)
27695            } else {
27696                None
27697            }
27698        })
27699}
27700
27701/// Given a string of text immediately before the cursor, iterates over possible
27702/// strings a snippet could match to. More precisely: returns an iterator over
27703/// suffixes of `text` created by splitting at word boundaries (before & after
27704/// every non-word character).
27705///
27706/// Shorter suffixes are returned first.
27707pub(crate) fn snippet_candidate_suffixes(
27708    text: &str,
27709    is_word_char: impl Fn(char) -> bool,
27710) -> impl std::iter::Iterator<Item = &str> {
27711    let mut prev_index = text.len();
27712    let mut prev_codepoint = None;
27713    text.char_indices()
27714        .rev()
27715        .chain([(0, '\0')])
27716        .filter_map(move |(index, codepoint)| {
27717            let prev_index = std::mem::replace(&mut prev_index, index);
27718            let prev_codepoint = prev_codepoint.replace(codepoint)?;
27719            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
27720                None
27721            } else {
27722                let chunk = &text[prev_index..]; // go to end of string
27723                Some(chunk)
27724            }
27725        })
27726}
27727
27728pub trait RangeToAnchorExt: Sized {
27729    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
27730
27731    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
27732        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
27733        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
27734    }
27735}
27736
27737impl<T: ToOffset> RangeToAnchorExt for Range<T> {
27738    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
27739        let start_offset = self.start.to_offset(snapshot);
27740        let end_offset = self.end.to_offset(snapshot);
27741        if start_offset == end_offset {
27742            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
27743        } else {
27744            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
27745        }
27746    }
27747}
27748
27749pub trait RowExt {
27750    fn as_f64(&self) -> f64;
27751
27752    fn next_row(&self) -> Self;
27753
27754    fn previous_row(&self) -> Self;
27755
27756    fn minus(&self, other: Self) -> u32;
27757}
27758
27759impl RowExt for DisplayRow {
27760    fn as_f64(&self) -> f64 {
27761        self.0 as _
27762    }
27763
27764    fn next_row(&self) -> Self {
27765        Self(self.0 + 1)
27766    }
27767
27768    fn previous_row(&self) -> Self {
27769        Self(self.0.saturating_sub(1))
27770    }
27771
27772    fn minus(&self, other: Self) -> u32 {
27773        self.0 - other.0
27774    }
27775}
27776
27777impl RowExt for MultiBufferRow {
27778    fn as_f64(&self) -> f64 {
27779        self.0 as _
27780    }
27781
27782    fn next_row(&self) -> Self {
27783        Self(self.0 + 1)
27784    }
27785
27786    fn previous_row(&self) -> Self {
27787        Self(self.0.saturating_sub(1))
27788    }
27789
27790    fn minus(&self, other: Self) -> u32 {
27791        self.0 - other.0
27792    }
27793}
27794
27795trait RowRangeExt {
27796    type Row;
27797
27798    fn len(&self) -> usize;
27799
27800    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
27801}
27802
27803impl RowRangeExt for Range<MultiBufferRow> {
27804    type Row = MultiBufferRow;
27805
27806    fn len(&self) -> usize {
27807        (self.end.0 - self.start.0) as usize
27808    }
27809
27810    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
27811        (self.start.0..self.end.0).map(MultiBufferRow)
27812    }
27813}
27814
27815impl RowRangeExt for Range<DisplayRow> {
27816    type Row = DisplayRow;
27817
27818    fn len(&self) -> usize {
27819        (self.end.0 - self.start.0) as usize
27820    }
27821
27822    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
27823        (self.start.0..self.end.0).map(DisplayRow)
27824    }
27825}
27826
27827/// If select range has more than one line, we
27828/// just point the cursor to range.start.
27829fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
27830    if range.start.row == range.end.row {
27831        range
27832    } else {
27833        range.start..range.start
27834    }
27835}
27836pub struct KillRing(ClipboardItem);
27837impl Global for KillRing {}
27838
27839const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
27840
27841enum BreakpointPromptEditAction {
27842    Log,
27843    Condition,
27844    HitCondition,
27845}
27846
27847struct BreakpointPromptEditor {
27848    pub(crate) prompt: Entity<Editor>,
27849    editor: WeakEntity<Editor>,
27850    breakpoint_anchor: Anchor,
27851    breakpoint: Breakpoint,
27852    edit_action: BreakpointPromptEditAction,
27853    block_ids: HashSet<CustomBlockId>,
27854    editor_margins: Arc<Mutex<EditorMargins>>,
27855    _subscriptions: Vec<Subscription>,
27856}
27857
27858impl BreakpointPromptEditor {
27859    const MAX_LINES: u8 = 4;
27860
27861    fn new(
27862        editor: WeakEntity<Editor>,
27863        breakpoint_anchor: Anchor,
27864        breakpoint: Breakpoint,
27865        edit_action: BreakpointPromptEditAction,
27866        window: &mut Window,
27867        cx: &mut Context<Self>,
27868    ) -> Self {
27869        let base_text = match edit_action {
27870            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
27871            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
27872            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
27873        }
27874        .map(|msg| msg.to_string())
27875        .unwrap_or_default();
27876
27877        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
27878        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
27879
27880        let prompt = cx.new(|cx| {
27881            let mut prompt = Editor::new(
27882                EditorMode::AutoHeight {
27883                    min_lines: 1,
27884                    max_lines: Some(Self::MAX_LINES as usize),
27885                },
27886                buffer,
27887                None,
27888                window,
27889                cx,
27890            );
27891            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
27892            prompt.set_show_cursor_when_unfocused(false, cx);
27893            prompt.set_placeholder_text(
27894                match edit_action {
27895                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
27896                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
27897                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
27898                },
27899                window,
27900                cx,
27901            );
27902
27903            prompt
27904        });
27905
27906        Self {
27907            prompt,
27908            editor,
27909            breakpoint_anchor,
27910            breakpoint,
27911            edit_action,
27912            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
27913            block_ids: Default::default(),
27914            _subscriptions: vec![],
27915        }
27916    }
27917
27918    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
27919        self.block_ids.extend(block_ids)
27920    }
27921
27922    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
27923        if let Some(editor) = self.editor.upgrade() {
27924            let message = self
27925                .prompt
27926                .read(cx)
27927                .buffer
27928                .read(cx)
27929                .as_singleton()
27930                .expect("A multi buffer in breakpoint prompt isn't possible")
27931                .read(cx)
27932                .as_rope()
27933                .to_string();
27934
27935            editor.update(cx, |editor, cx| {
27936                editor.edit_breakpoint_at_anchor(
27937                    self.breakpoint_anchor,
27938                    self.breakpoint.clone(),
27939                    match self.edit_action {
27940                        BreakpointPromptEditAction::Log => {
27941                            BreakpointEditAction::EditLogMessage(message.into())
27942                        }
27943                        BreakpointPromptEditAction::Condition => {
27944                            BreakpointEditAction::EditCondition(message.into())
27945                        }
27946                        BreakpointPromptEditAction::HitCondition => {
27947                            BreakpointEditAction::EditHitCondition(message.into())
27948                        }
27949                    },
27950                    cx,
27951                );
27952
27953                editor.remove_blocks(self.block_ids.clone(), None, cx);
27954                cx.focus_self(window);
27955            });
27956        }
27957    }
27958
27959    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
27960        self.editor
27961            .update(cx, |editor, cx| {
27962                editor.remove_blocks(self.block_ids.clone(), None, cx);
27963                window.focus(&editor.focus_handle, cx);
27964            })
27965            .log_err();
27966    }
27967
27968    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
27969        let settings = ThemeSettings::get_global(cx);
27970        let text_style = TextStyle {
27971            color: if self.prompt.read(cx).read_only(cx) {
27972                cx.theme().colors().text_disabled
27973            } else {
27974                cx.theme().colors().text
27975            },
27976            font_family: settings.buffer_font.family.clone(),
27977            font_fallbacks: settings.buffer_font.fallbacks.clone(),
27978            font_size: settings.buffer_font_size(cx).into(),
27979            font_weight: settings.buffer_font.weight,
27980            line_height: relative(settings.buffer_line_height.value()),
27981            ..Default::default()
27982        };
27983        EditorElement::new(
27984            &self.prompt,
27985            EditorStyle {
27986                background: cx.theme().colors().editor_background,
27987                local_player: cx.theme().players().local(),
27988                text: text_style,
27989                ..Default::default()
27990            },
27991        )
27992    }
27993}
27994
27995impl Render for BreakpointPromptEditor {
27996    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
27997        let editor_margins = *self.editor_margins.lock();
27998        let gutter_dimensions = editor_margins.gutter;
27999        h_flex()
28000            .key_context("Editor")
28001            .bg(cx.theme().colors().editor_background)
28002            .border_y_1()
28003            .border_color(cx.theme().status().info_border)
28004            .size_full()
28005            .py(window.line_height() / 2.5)
28006            .on_action(cx.listener(Self::confirm))
28007            .on_action(cx.listener(Self::cancel))
28008            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
28009            .child(div().flex_1().child(self.render_prompt_editor(cx)))
28010    }
28011}
28012
28013impl Focusable for BreakpointPromptEditor {
28014    fn focus_handle(&self, cx: &App) -> FocusHandle {
28015        self.prompt.focus_handle(cx)
28016    }
28017}
28018
28019fn all_edits_insertions_or_deletions(
28020    edits: &Vec<(Range<Anchor>, Arc<str>)>,
28021    snapshot: &MultiBufferSnapshot,
28022) -> bool {
28023    let mut all_insertions = true;
28024    let mut all_deletions = true;
28025
28026    for (range, new_text) in edits.iter() {
28027        let range_is_empty = range.to_offset(snapshot).is_empty();
28028        let text_is_empty = new_text.is_empty();
28029
28030        if range_is_empty != text_is_empty {
28031            if range_is_empty {
28032                all_deletions = false;
28033            } else {
28034                all_insertions = false;
28035            }
28036        } else {
28037            return false;
28038        }
28039
28040        if !all_insertions && !all_deletions {
28041            return false;
28042        }
28043    }
28044    all_insertions || all_deletions
28045}
28046
28047struct MissingEditPredictionKeybindingTooltip;
28048
28049impl Render for MissingEditPredictionKeybindingTooltip {
28050    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28051        ui::tooltip_container(cx, |container, cx| {
28052            container
28053                .flex_shrink_0()
28054                .max_w_80()
28055                .min_h(rems_from_px(124.))
28056                .justify_between()
28057                .child(
28058                    v_flex()
28059                        .flex_1()
28060                        .text_ui_sm(cx)
28061                        .child(Label::new("Conflict with Accept Keybinding"))
28062                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
28063                )
28064                .child(
28065                    h_flex()
28066                        .pb_1()
28067                        .gap_1()
28068                        .items_end()
28069                        .w_full()
28070                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
28071                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
28072                        }))
28073                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
28074                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
28075                        })),
28076                )
28077        })
28078    }
28079}
28080
28081#[derive(Debug, Clone, Copy, PartialEq)]
28082pub struct LineHighlight {
28083    pub background: Background,
28084    pub border: Option<gpui::Hsla>,
28085    pub include_gutter: bool,
28086    pub type_id: Option<TypeId>,
28087}
28088
28089struct LineManipulationResult {
28090    pub new_text: String,
28091    pub line_count_before: usize,
28092    pub line_count_after: usize,
28093}
28094
28095fn render_diff_hunk_controls(
28096    row: u32,
28097    status: &DiffHunkStatus,
28098    hunk_range: Range<Anchor>,
28099    is_created_file: bool,
28100    line_height: Pixels,
28101    editor: &Entity<Editor>,
28102    _window: &mut Window,
28103    cx: &mut App,
28104) -> AnyElement {
28105    h_flex()
28106        .h(line_height)
28107        .mr_1()
28108        .gap_1()
28109        .px_0p5()
28110        .pb_1()
28111        .border_x_1()
28112        .border_b_1()
28113        .border_color(cx.theme().colors().border_variant)
28114        .rounded_b_lg()
28115        .bg(cx.theme().colors().editor_background)
28116        .gap_1()
28117        .block_mouse_except_scroll()
28118        .shadow_md()
28119        .child(if status.has_secondary_hunk() {
28120            Button::new(("stage", row as u64), "Stage")
28121                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28122                .tooltip({
28123                    let focus_handle = editor.focus_handle(cx);
28124                    move |_window, cx| {
28125                        Tooltip::for_action_in(
28126                            "Stage Hunk",
28127                            &::git::ToggleStaged,
28128                            &focus_handle,
28129                            cx,
28130                        )
28131                    }
28132                })
28133                .on_click({
28134                    let editor = editor.clone();
28135                    move |_event, _window, cx| {
28136                        editor.update(cx, |editor, cx| {
28137                            editor.stage_or_unstage_diff_hunks(
28138                                true,
28139                                vec![hunk_range.start..hunk_range.start],
28140                                cx,
28141                            );
28142                        });
28143                    }
28144                })
28145        } else {
28146            Button::new(("unstage", row as u64), "Unstage")
28147                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28148                .tooltip({
28149                    let focus_handle = editor.focus_handle(cx);
28150                    move |_window, cx| {
28151                        Tooltip::for_action_in(
28152                            "Unstage Hunk",
28153                            &::git::ToggleStaged,
28154                            &focus_handle,
28155                            cx,
28156                        )
28157                    }
28158                })
28159                .on_click({
28160                    let editor = editor.clone();
28161                    move |_event, _window, cx| {
28162                        editor.update(cx, |editor, cx| {
28163                            editor.stage_or_unstage_diff_hunks(
28164                                false,
28165                                vec![hunk_range.start..hunk_range.start],
28166                                cx,
28167                            );
28168                        });
28169                    }
28170                })
28171        })
28172        .child(
28173            Button::new(("restore", row as u64), "Restore")
28174                .tooltip({
28175                    let focus_handle = editor.focus_handle(cx);
28176                    move |_window, cx| {
28177                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
28178                    }
28179                })
28180                .on_click({
28181                    let editor = editor.clone();
28182                    move |_event, window, cx| {
28183                        editor.update(cx, |editor, cx| {
28184                            let snapshot = editor.snapshot(window, cx);
28185                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
28186                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
28187                        });
28188                    }
28189                })
28190                .disabled(is_created_file),
28191        )
28192        .when(
28193            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
28194            |el| {
28195                el.child(
28196                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
28197                        .shape(IconButtonShape::Square)
28198                        .icon_size(IconSize::Small)
28199                        // .disabled(!has_multiple_hunks)
28200                        .tooltip({
28201                            let focus_handle = editor.focus_handle(cx);
28202                            move |_window, cx| {
28203                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
28204                            }
28205                        })
28206                        .on_click({
28207                            let editor = editor.clone();
28208                            move |_event, window, cx| {
28209                                editor.update(cx, |editor, cx| {
28210                                    let snapshot = editor.snapshot(window, cx);
28211                                    let position =
28212                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
28213                                    editor.go_to_hunk_before_or_after_position(
28214                                        &snapshot,
28215                                        position,
28216                                        Direction::Next,
28217                                        window,
28218                                        cx,
28219                                    );
28220                                    editor.expand_selected_diff_hunks(cx);
28221                                });
28222                            }
28223                        }),
28224                )
28225                .child(
28226                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
28227                        .shape(IconButtonShape::Square)
28228                        .icon_size(IconSize::Small)
28229                        // .disabled(!has_multiple_hunks)
28230                        .tooltip({
28231                            let focus_handle = editor.focus_handle(cx);
28232                            move |_window, cx| {
28233                                Tooltip::for_action_in(
28234                                    "Previous Hunk",
28235                                    &GoToPreviousHunk,
28236                                    &focus_handle,
28237                                    cx,
28238                                )
28239                            }
28240                        })
28241                        .on_click({
28242                            let editor = editor.clone();
28243                            move |_event, window, cx| {
28244                                editor.update(cx, |editor, cx| {
28245                                    let snapshot = editor.snapshot(window, cx);
28246                                    let point =
28247                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
28248                                    editor.go_to_hunk_before_or_after_position(
28249                                        &snapshot,
28250                                        point,
28251                                        Direction::Prev,
28252                                        window,
28253                                        cx,
28254                                    );
28255                                    editor.expand_selected_diff_hunks(cx);
28256                                });
28257                            }
28258                        }),
28259                )
28260            },
28261        )
28262        .into_any_element()
28263}
28264
28265pub fn multibuffer_context_lines(cx: &App) -> u32 {
28266    EditorSettings::try_get(cx)
28267        .map(|settings| settings.excerpt_context_lines)
28268        .unwrap_or(2)
28269        .min(32)
28270}