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    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow, bail};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction_types::{
   96    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   97};
   98use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   99use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
  100use futures::{
  101    FutureExt, StreamExt as _,
  102    future::{self, Shared, join},
  103    stream::FuturesUnordered,
  104};
  105use fuzzy::{StringMatch, StringMatchCandidate};
  106use git::blame::{GitBlame, GlobalBlameRenderer};
  107use gpui::{
  108    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  109    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  110    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  111    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  112    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  113    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  114    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  115    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  116    size,
  117};
  118use hover_links::{HoverLink, HoveredLinkState, find_file};
  119use hover_popover::{HoverState, hide_hover};
  120use indent_guides::ActiveIndentGuidesState;
  121use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  122use itertools::{Either, Itertools};
  123use language::{
  124    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  125    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  126    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  127    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  128    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  129    language_settings::{
  130        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  131        all_language_settings, language_settings,
  132    },
  133    point_from_lsp, point_to_lsp, text_diff_with_options,
  134};
  135use linked_editing_ranges::refresh_linked_ranges;
  136use lsp::{
  137    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  138    LanguageServerId,
  139};
  140use lsp_colors::LspColorData;
  141use markdown::Markdown;
  142use mouse_context_menu::MouseContextMenu;
  143use movement::TextLayoutDetails;
  144use multi_buffer::{
  145    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  152    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  153    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::GitStoreEvent,
  162    lsp_store::{
  163        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  164        OpenLspBufferHandle,
  165    },
  166    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  167};
  168use rand::seq::SliceRandom;
  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    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    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, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::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/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1025///
 1026/// See the [module level documentation](self) for more information.
 1027pub struct Editor {
 1028    focus_handle: FocusHandle,
 1029    last_focused_descendant: Option<WeakFocusHandle>,
 1030    /// The text buffer being edited
 1031    buffer: Entity<MultiBuffer>,
 1032    /// Map of how text in the buffer should be displayed.
 1033    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1034    pub display_map: Entity<DisplayMap>,
 1035    placeholder_display_map: Option<Entity<DisplayMap>>,
 1036    pub selections: SelectionsCollection,
 1037    pub scroll_manager: ScrollManager,
 1038    /// When inline assist editors are linked, they all render cursors because
 1039    /// typing enters text into each of them, even the ones that aren't focused.
 1040    pub(crate) show_cursor_when_unfocused: bool,
 1041    columnar_selection_state: Option<ColumnarSelectionState>,
 1042    add_selections_state: Option<AddSelectionsState>,
 1043    select_next_state: Option<SelectNextState>,
 1044    select_prev_state: Option<SelectNextState>,
 1045    selection_history: SelectionHistory,
 1046    defer_selection_effects: bool,
 1047    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1048    autoclose_regions: Vec<AutocloseRegion>,
 1049    snippet_stack: InvalidationStack<SnippetState>,
 1050    select_syntax_node_history: SelectSyntaxNodeHistory,
 1051    ime_transaction: Option<TransactionId>,
 1052    pub diagnostics_max_severity: DiagnosticSeverity,
 1053    active_diagnostics: ActiveDiagnostic,
 1054    show_inline_diagnostics: bool,
 1055    inline_diagnostics_update: Task<()>,
 1056    inline_diagnostics_enabled: bool,
 1057    diagnostics_enabled: bool,
 1058    word_completions_enabled: bool,
 1059    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1060    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1061    hard_wrap: Option<usize>,
 1062    project: Option<Entity<Project>>,
 1063    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1064    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1065    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1066    blink_manager: Entity<BlinkManager>,
 1067    show_cursor_names: bool,
 1068    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1069    pub show_local_selections: bool,
 1070    mode: EditorMode,
 1071    show_breadcrumbs: bool,
 1072    show_gutter: bool,
 1073    show_scrollbars: ScrollbarAxes,
 1074    minimap_visibility: MinimapVisibility,
 1075    offset_content: bool,
 1076    disable_expand_excerpt_buttons: bool,
 1077    show_line_numbers: Option<bool>,
 1078    use_relative_line_numbers: Option<bool>,
 1079    show_git_diff_gutter: Option<bool>,
 1080    show_code_actions: Option<bool>,
 1081    show_runnables: Option<bool>,
 1082    show_breakpoints: Option<bool>,
 1083    show_wrap_guides: Option<bool>,
 1084    show_indent_guides: Option<bool>,
 1085    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1086    highlight_order: usize,
 1087    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1088    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1089    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1090    scrollbar_marker_state: ScrollbarMarkerState,
 1091    active_indent_guides_state: ActiveIndentGuidesState,
 1092    nav_history: Option<ItemNavHistory>,
 1093    context_menu: RefCell<Option<CodeContextMenu>>,
 1094    context_menu_options: Option<ContextMenuOptions>,
 1095    mouse_context_menu: Option<MouseContextMenu>,
 1096    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1097    inline_blame_popover: Option<InlineBlamePopover>,
 1098    inline_blame_popover_show_task: Option<Task<()>>,
 1099    signature_help_state: SignatureHelpState,
 1100    auto_signature_help: Option<bool>,
 1101    find_all_references_task_sources: Vec<Anchor>,
 1102    next_completion_id: CompletionId,
 1103    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1104    code_actions_task: Option<Task<Result<()>>>,
 1105    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1106    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1107    document_highlights_task: Option<Task<()>>,
 1108    linked_editing_range_task: Option<Task<Option<()>>>,
 1109    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1110    pending_rename: Option<RenameState>,
 1111    searchable: bool,
 1112    cursor_shape: CursorShape,
 1113    /// Whether the cursor is offset one character to the left when something is
 1114    /// selected (needed for vim visual mode)
 1115    cursor_offset_on_selection: bool,
 1116    current_line_highlight: Option<CurrentLineHighlight>,
 1117    pub collapse_matches: bool,
 1118    autoindent_mode: Option<AutoindentMode>,
 1119    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1120    input_enabled: bool,
 1121    use_modal_editing: bool,
 1122    read_only: bool,
 1123    leader_id: Option<CollaboratorId>,
 1124    remote_id: Option<ViewId>,
 1125    pub hover_state: HoverState,
 1126    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1127    prev_pressure_stage: Option<PressureStage>,
 1128    gutter_hovered: bool,
 1129    hovered_link_state: Option<HoveredLinkState>,
 1130    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1131    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1132    active_edit_prediction: Option<EditPredictionState>,
 1133    /// Used to prevent flickering as the user types while the menu is open
 1134    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1135    edit_prediction_settings: EditPredictionSettings,
 1136    edit_predictions_hidden_for_vim_mode: bool,
 1137    show_edit_predictions_override: Option<bool>,
 1138    show_completions_on_input_override: Option<bool>,
 1139    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1140    edit_prediction_preview: EditPredictionPreview,
 1141    edit_prediction_indent_conflict: bool,
 1142    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1143    next_inlay_id: usize,
 1144    next_color_inlay_id: usize,
 1145    _subscriptions: Vec<Subscription>,
 1146    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1147    gutter_dimensions: GutterDimensions,
 1148    style: Option<EditorStyle>,
 1149    text_style_refinement: Option<TextStyleRefinement>,
 1150    next_editor_action_id: EditorActionId,
 1151    editor_actions: Rc<
 1152        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1153    >,
 1154    use_autoclose: bool,
 1155    use_auto_surround: bool,
 1156    auto_replace_emoji_shortcode: bool,
 1157    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1158    show_git_blame_gutter: bool,
 1159    show_git_blame_inline: bool,
 1160    show_git_blame_inline_delay_task: Option<Task<()>>,
 1161    git_blame_inline_enabled: bool,
 1162    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1163    buffer_serialization: Option<BufferSerialization>,
 1164    show_selection_menu: Option<bool>,
 1165    blame: Option<Entity<GitBlame>>,
 1166    blame_subscription: Option<Subscription>,
 1167    custom_context_menu: Option<
 1168        Box<
 1169            dyn 'static
 1170                + Fn(
 1171                    &mut Self,
 1172                    DisplayPoint,
 1173                    &mut Window,
 1174                    &mut Context<Self>,
 1175                ) -> Option<Entity<ui::ContextMenu>>,
 1176        >,
 1177    >,
 1178    last_bounds: Option<Bounds<Pixels>>,
 1179    last_position_map: Option<Rc<PositionMap>>,
 1180    expect_bounds_change: Option<Bounds<Pixels>>,
 1181    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1182    tasks_update_task: Option<Task<()>>,
 1183    breakpoint_store: Option<Entity<BreakpointStore>>,
 1184    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1185    hovered_diff_hunk_row: Option<DisplayRow>,
 1186    pull_diagnostics_task: Task<()>,
 1187    pull_diagnostics_background_task: Task<()>,
 1188    in_project_search: bool,
 1189    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1190    breadcrumb_header: Option<String>,
 1191    focused_block: Option<FocusedBlock>,
 1192    next_scroll_position: NextScrollCursorCenterTopBottom,
 1193    addons: HashMap<TypeId, Box<dyn Addon>>,
 1194    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1195    load_diff_task: Option<Shared<Task<()>>>,
 1196    /// Whether we are temporarily displaying a diff other than git's
 1197    temporary_diff_override: bool,
 1198    selection_mark_mode: bool,
 1199    toggle_fold_multiple_buffers: Task<()>,
 1200    _scroll_cursor_center_top_bottom_task: Task<()>,
 1201    serialize_selections: Task<()>,
 1202    serialize_folds: Task<()>,
 1203    mouse_cursor_hidden: bool,
 1204    minimap: Option<Entity<Self>>,
 1205    hide_mouse_mode: HideMouseMode,
 1206    pub change_list: ChangeList,
 1207    inline_value_cache: InlineValueCache,
 1208
 1209    selection_drag_state: SelectionDragState,
 1210    colors: Option<LspColorData>,
 1211    post_scroll_update: Task<()>,
 1212    refresh_colors_task: Task<()>,
 1213    inlay_hints: Option<LspInlayHintData>,
 1214    folding_newlines: Task<()>,
 1215    select_next_is_case_sensitive: Option<bool>,
 1216    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1217    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1218    accent_data: Option<AccentData>,
 1219    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1220    use_base_text_line_numbers: bool,
 1221}
 1222
 1223#[derive(Debug, PartialEq)]
 1224struct AccentData {
 1225    colors: AccentColors,
 1226    overrides: Vec<SharedString>,
 1227}
 1228
 1229fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1230    if debounce_ms > 0 {
 1231        Some(Duration::from_millis(debounce_ms))
 1232    } else {
 1233        None
 1234    }
 1235}
 1236
 1237#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1238enum NextScrollCursorCenterTopBottom {
 1239    #[default]
 1240    Center,
 1241    Top,
 1242    Bottom,
 1243}
 1244
 1245impl NextScrollCursorCenterTopBottom {
 1246    fn next(&self) -> Self {
 1247        match self {
 1248            Self::Center => Self::Top,
 1249            Self::Top => Self::Bottom,
 1250            Self::Bottom => Self::Center,
 1251        }
 1252    }
 1253}
 1254
 1255#[derive(Clone)]
 1256pub struct EditorSnapshot {
 1257    pub mode: EditorMode,
 1258    show_gutter: bool,
 1259    offset_content: bool,
 1260    show_line_numbers: Option<bool>,
 1261    show_git_diff_gutter: Option<bool>,
 1262    show_code_actions: Option<bool>,
 1263    show_runnables: Option<bool>,
 1264    show_breakpoints: Option<bool>,
 1265    git_blame_gutter_max_author_length: Option<usize>,
 1266    pub display_snapshot: DisplaySnapshot,
 1267    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1268    is_focused: bool,
 1269    scroll_anchor: ScrollAnchor,
 1270    ongoing_scroll: OngoingScroll,
 1271    current_line_highlight: CurrentLineHighlight,
 1272    gutter_hovered: bool,
 1273}
 1274
 1275#[derive(Default, Debug, Clone, Copy)]
 1276pub struct GutterDimensions {
 1277    pub left_padding: Pixels,
 1278    pub right_padding: Pixels,
 1279    pub width: Pixels,
 1280    pub margin: Pixels,
 1281    pub git_blame_entries_width: Option<Pixels>,
 1282}
 1283
 1284impl GutterDimensions {
 1285    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1286        Self {
 1287            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1288            ..Default::default()
 1289        }
 1290    }
 1291
 1292    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1293        -cx.text_system().descent(font_id, font_size)
 1294    }
 1295    /// The full width of the space taken up by the gutter.
 1296    pub fn full_width(&self) -> Pixels {
 1297        self.margin + self.width
 1298    }
 1299
 1300    /// The width of the space reserved for the fold indicators,
 1301    /// use alongside 'justify_end' and `gutter_width` to
 1302    /// right align content with the line numbers
 1303    pub fn fold_area_width(&self) -> Pixels {
 1304        self.margin + self.right_padding
 1305    }
 1306}
 1307
 1308struct CharacterDimensions {
 1309    em_width: Pixels,
 1310    em_advance: Pixels,
 1311    line_height: Pixels,
 1312}
 1313
 1314#[derive(Debug)]
 1315pub struct RemoteSelection {
 1316    pub replica_id: ReplicaId,
 1317    pub selection: Selection<Anchor>,
 1318    pub cursor_shape: CursorShape,
 1319    pub collaborator_id: CollaboratorId,
 1320    pub line_mode: bool,
 1321    pub user_name: Option<SharedString>,
 1322    pub color: PlayerColor,
 1323}
 1324
 1325#[derive(Clone, Debug)]
 1326struct SelectionHistoryEntry {
 1327    selections: Arc<[Selection<Anchor>]>,
 1328    select_next_state: Option<SelectNextState>,
 1329    select_prev_state: Option<SelectNextState>,
 1330    add_selections_state: Option<AddSelectionsState>,
 1331}
 1332
 1333#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1334enum SelectionHistoryMode {
 1335    #[default]
 1336    Normal,
 1337    Undoing,
 1338    Redoing,
 1339    Skipping,
 1340}
 1341
 1342#[derive(Clone, PartialEq, Eq, Hash)]
 1343struct HoveredCursor {
 1344    replica_id: ReplicaId,
 1345    selection_id: usize,
 1346}
 1347
 1348#[derive(Debug)]
 1349/// SelectionEffects controls the side-effects of updating the selection.
 1350///
 1351/// The default behaviour does "what you mostly want":
 1352/// - it pushes to the nav history if the cursor moved by >10 lines
 1353/// - it re-triggers completion requests
 1354/// - it scrolls to fit
 1355///
 1356/// You might want to modify these behaviours. For example when doing a "jump"
 1357/// like go to definition, we always want to add to nav history; but when scrolling
 1358/// in vim mode we never do.
 1359///
 1360/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1361/// move.
 1362#[derive(Clone)]
 1363pub struct SelectionEffects {
 1364    nav_history: Option<bool>,
 1365    completions: bool,
 1366    scroll: Option<Autoscroll>,
 1367}
 1368
 1369impl Default for SelectionEffects {
 1370    fn default() -> Self {
 1371        Self {
 1372            nav_history: None,
 1373            completions: true,
 1374            scroll: Some(Autoscroll::fit()),
 1375        }
 1376    }
 1377}
 1378impl SelectionEffects {
 1379    pub fn scroll(scroll: Autoscroll) -> Self {
 1380        Self {
 1381            scroll: Some(scroll),
 1382            ..Default::default()
 1383        }
 1384    }
 1385
 1386    pub fn no_scroll() -> Self {
 1387        Self {
 1388            scroll: None,
 1389            ..Default::default()
 1390        }
 1391    }
 1392
 1393    pub fn completions(self, completions: bool) -> Self {
 1394        Self {
 1395            completions,
 1396            ..self
 1397        }
 1398    }
 1399
 1400    pub fn nav_history(self, nav_history: bool) -> Self {
 1401        Self {
 1402            nav_history: Some(nav_history),
 1403            ..self
 1404        }
 1405    }
 1406}
 1407
 1408struct DeferredSelectionEffectsState {
 1409    changed: bool,
 1410    effects: SelectionEffects,
 1411    old_cursor_position: Anchor,
 1412    history_entry: SelectionHistoryEntry,
 1413}
 1414
 1415#[derive(Default)]
 1416struct SelectionHistory {
 1417    #[allow(clippy::type_complexity)]
 1418    selections_by_transaction:
 1419        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1420    mode: SelectionHistoryMode,
 1421    undo_stack: VecDeque<SelectionHistoryEntry>,
 1422    redo_stack: VecDeque<SelectionHistoryEntry>,
 1423}
 1424
 1425impl SelectionHistory {
 1426    #[track_caller]
 1427    fn insert_transaction(
 1428        &mut self,
 1429        transaction_id: TransactionId,
 1430        selections: Arc<[Selection<Anchor>]>,
 1431    ) {
 1432        if selections.is_empty() {
 1433            log::error!(
 1434                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1435                std::panic::Location::caller()
 1436            );
 1437            return;
 1438        }
 1439        self.selections_by_transaction
 1440            .insert(transaction_id, (selections, None));
 1441    }
 1442
 1443    #[allow(clippy::type_complexity)]
 1444    fn transaction(
 1445        &self,
 1446        transaction_id: TransactionId,
 1447    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1448        self.selections_by_transaction.get(&transaction_id)
 1449    }
 1450
 1451    #[allow(clippy::type_complexity)]
 1452    fn transaction_mut(
 1453        &mut self,
 1454        transaction_id: TransactionId,
 1455    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1456        self.selections_by_transaction.get_mut(&transaction_id)
 1457    }
 1458
 1459    fn push(&mut self, entry: SelectionHistoryEntry) {
 1460        if !entry.selections.is_empty() {
 1461            match self.mode {
 1462                SelectionHistoryMode::Normal => {
 1463                    self.push_undo(entry);
 1464                    self.redo_stack.clear();
 1465                }
 1466                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1467                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1468                SelectionHistoryMode::Skipping => {}
 1469            }
 1470        }
 1471    }
 1472
 1473    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1474        if self
 1475            .undo_stack
 1476            .back()
 1477            .is_none_or(|e| e.selections != entry.selections)
 1478        {
 1479            self.undo_stack.push_back(entry);
 1480            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1481                self.undo_stack.pop_front();
 1482            }
 1483        }
 1484    }
 1485
 1486    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1487        if self
 1488            .redo_stack
 1489            .back()
 1490            .is_none_or(|e| e.selections != entry.selections)
 1491        {
 1492            self.redo_stack.push_back(entry);
 1493            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1494                self.redo_stack.pop_front();
 1495            }
 1496        }
 1497    }
 1498}
 1499
 1500#[derive(Clone, Copy)]
 1501pub struct RowHighlightOptions {
 1502    pub autoscroll: bool,
 1503    pub include_gutter: bool,
 1504}
 1505
 1506impl Default for RowHighlightOptions {
 1507    fn default() -> Self {
 1508        Self {
 1509            autoscroll: Default::default(),
 1510            include_gutter: true,
 1511        }
 1512    }
 1513}
 1514
 1515struct RowHighlight {
 1516    index: usize,
 1517    range: Range<Anchor>,
 1518    color: Hsla,
 1519    options: RowHighlightOptions,
 1520    type_id: TypeId,
 1521}
 1522
 1523#[derive(Clone, Debug)]
 1524struct AddSelectionsState {
 1525    groups: Vec<AddSelectionsGroup>,
 1526}
 1527
 1528#[derive(Clone, Debug)]
 1529struct AddSelectionsGroup {
 1530    above: bool,
 1531    stack: Vec<usize>,
 1532}
 1533
 1534#[derive(Clone)]
 1535struct SelectNextState {
 1536    query: AhoCorasick,
 1537    wordwise: bool,
 1538    done: bool,
 1539}
 1540
 1541impl std::fmt::Debug for SelectNextState {
 1542    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1543        f.debug_struct(std::any::type_name::<Self>())
 1544            .field("wordwise", &self.wordwise)
 1545            .field("done", &self.done)
 1546            .finish()
 1547    }
 1548}
 1549
 1550#[derive(Debug)]
 1551struct AutocloseRegion {
 1552    selection_id: usize,
 1553    range: Range<Anchor>,
 1554    pair: BracketPair,
 1555}
 1556
 1557#[derive(Debug)]
 1558struct SnippetState {
 1559    ranges: Vec<Vec<Range<Anchor>>>,
 1560    active_index: usize,
 1561    choices: Vec<Option<Vec<String>>>,
 1562}
 1563
 1564#[doc(hidden)]
 1565pub struct RenameState {
 1566    pub range: Range<Anchor>,
 1567    pub old_name: Arc<str>,
 1568    pub editor: Entity<Editor>,
 1569    block_id: CustomBlockId,
 1570}
 1571
 1572struct InvalidationStack<T>(Vec<T>);
 1573
 1574struct RegisteredEditPredictionDelegate {
 1575    provider: Arc<dyn EditPredictionDelegateHandle>,
 1576    _subscription: Subscription,
 1577}
 1578
 1579#[derive(Debug, PartialEq, Eq)]
 1580pub struct ActiveDiagnosticGroup {
 1581    pub active_range: Range<Anchor>,
 1582    pub active_message: String,
 1583    pub group_id: usize,
 1584    pub blocks: HashSet<CustomBlockId>,
 1585}
 1586
 1587#[derive(Debug, PartialEq, Eq)]
 1588
 1589pub(crate) enum ActiveDiagnostic {
 1590    None,
 1591    All,
 1592    Group(ActiveDiagnosticGroup),
 1593}
 1594
 1595#[derive(Serialize, Deserialize, Clone, Debug)]
 1596pub struct ClipboardSelection {
 1597    /// The number of bytes in this selection.
 1598    pub len: usize,
 1599    /// Whether this was a full-line selection.
 1600    pub is_entire_line: bool,
 1601    /// The indentation of the first line when this content was originally copied.
 1602    pub first_line_indent: u32,
 1603    #[serde(default)]
 1604    pub file_path: Option<PathBuf>,
 1605    #[serde(default)]
 1606    pub line_range: Option<RangeInclusive<u32>>,
 1607}
 1608
 1609impl ClipboardSelection {
 1610    pub fn for_buffer(
 1611        len: usize,
 1612        is_entire_line: bool,
 1613        range: Range<Point>,
 1614        buffer: &MultiBufferSnapshot,
 1615        project: Option<&Entity<Project>>,
 1616        cx: &App,
 1617    ) -> Self {
 1618        let first_line_indent = buffer
 1619            .indent_size_for_line(MultiBufferRow(range.start.row))
 1620            .len;
 1621
 1622        let file_path = util::maybe!({
 1623            let project = project?.read(cx);
 1624            let file = buffer.file_at(range.start)?;
 1625            let project_path = ProjectPath {
 1626                worktree_id: file.worktree_id(cx),
 1627                path: file.path().clone(),
 1628            };
 1629            project.absolute_path(&project_path, cx)
 1630        });
 1631
 1632        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1633
 1634        Self {
 1635            len,
 1636            is_entire_line,
 1637            first_line_indent,
 1638            file_path,
 1639            line_range,
 1640        }
 1641    }
 1642}
 1643
 1644// selections, scroll behavior, was newest selection reversed
 1645type SelectSyntaxNodeHistoryState = (
 1646    Box<[Selection<MultiBufferOffset>]>,
 1647    SelectSyntaxNodeScrollBehavior,
 1648    bool,
 1649);
 1650
 1651#[derive(Default)]
 1652struct SelectSyntaxNodeHistory {
 1653    stack: Vec<SelectSyntaxNodeHistoryState>,
 1654    // disable temporarily to allow changing selections without losing the stack
 1655    pub disable_clearing: bool,
 1656}
 1657
 1658impl SelectSyntaxNodeHistory {
 1659    pub fn try_clear(&mut self) {
 1660        if !self.disable_clearing {
 1661            self.stack.clear();
 1662        }
 1663    }
 1664
 1665    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1666        self.stack.push(selection);
 1667    }
 1668
 1669    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1670        self.stack.pop()
 1671    }
 1672}
 1673
 1674enum SelectSyntaxNodeScrollBehavior {
 1675    CursorTop,
 1676    FitSelection,
 1677    CursorBottom,
 1678}
 1679
 1680#[derive(Debug)]
 1681pub(crate) struct NavigationData {
 1682    cursor_anchor: Anchor,
 1683    cursor_position: Point,
 1684    scroll_anchor: ScrollAnchor,
 1685    scroll_top_row: u32,
 1686}
 1687
 1688#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1689pub enum GotoDefinitionKind {
 1690    Symbol,
 1691    Declaration,
 1692    Type,
 1693    Implementation,
 1694}
 1695
 1696pub enum FormatTarget {
 1697    Buffers(HashSet<Entity<Buffer>>),
 1698    Ranges(Vec<Range<MultiBufferPoint>>),
 1699}
 1700
 1701pub(crate) struct FocusedBlock {
 1702    id: BlockId,
 1703    focus_handle: WeakFocusHandle,
 1704}
 1705
 1706#[derive(Clone, Debug)]
 1707enum JumpData {
 1708    MultiBufferRow {
 1709        row: MultiBufferRow,
 1710        line_offset_from_top: u32,
 1711    },
 1712    MultiBufferPoint {
 1713        excerpt_id: ExcerptId,
 1714        position: Point,
 1715        anchor: text::Anchor,
 1716        line_offset_from_top: u32,
 1717    },
 1718}
 1719
 1720pub enum MultibufferSelectionMode {
 1721    First,
 1722    All,
 1723}
 1724
 1725#[derive(Clone, Copy, Debug, Default)]
 1726pub struct RewrapOptions {
 1727    pub override_language_settings: bool,
 1728    pub preserve_existing_whitespace: bool,
 1729}
 1730
 1731impl Editor {
 1732    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1733        let buffer = cx.new(|cx| Buffer::local("", cx));
 1734        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1735        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1736    }
 1737
 1738    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1739        let buffer = cx.new(|cx| Buffer::local("", cx));
 1740        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1741        Self::new(EditorMode::full(), buffer, None, window, cx)
 1742    }
 1743
 1744    pub fn auto_height(
 1745        min_lines: usize,
 1746        max_lines: usize,
 1747        window: &mut Window,
 1748        cx: &mut Context<Self>,
 1749    ) -> Self {
 1750        let buffer = cx.new(|cx| Buffer::local("", cx));
 1751        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1752        Self::new(
 1753            EditorMode::AutoHeight {
 1754                min_lines,
 1755                max_lines: Some(max_lines),
 1756            },
 1757            buffer,
 1758            None,
 1759            window,
 1760            cx,
 1761        )
 1762    }
 1763
 1764    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1765    /// The editor grows as tall as needed to fit its content.
 1766    pub fn auto_height_unbounded(
 1767        min_lines: usize,
 1768        window: &mut Window,
 1769        cx: &mut Context<Self>,
 1770    ) -> Self {
 1771        let buffer = cx.new(|cx| Buffer::local("", cx));
 1772        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1773        Self::new(
 1774            EditorMode::AutoHeight {
 1775                min_lines,
 1776                max_lines: None,
 1777            },
 1778            buffer,
 1779            None,
 1780            window,
 1781            cx,
 1782        )
 1783    }
 1784
 1785    pub fn for_buffer(
 1786        buffer: Entity<Buffer>,
 1787        project: Option<Entity<Project>>,
 1788        window: &mut Window,
 1789        cx: &mut Context<Self>,
 1790    ) -> Self {
 1791        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1792        Self::new(EditorMode::full(), buffer, project, window, cx)
 1793    }
 1794
 1795    pub fn for_multibuffer(
 1796        buffer: Entity<MultiBuffer>,
 1797        project: Option<Entity<Project>>,
 1798        window: &mut Window,
 1799        cx: &mut Context<Self>,
 1800    ) -> Self {
 1801        Self::new(EditorMode::full(), buffer, project, window, cx)
 1802    }
 1803
 1804    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1805        let mut clone = Self::new(
 1806            self.mode.clone(),
 1807            self.buffer.clone(),
 1808            self.project.clone(),
 1809            window,
 1810            cx,
 1811        );
 1812        self.display_map.update(cx, |display_map, cx| {
 1813            let snapshot = display_map.snapshot(cx);
 1814            clone.display_map.update(cx, |display_map, cx| {
 1815                display_map.set_state(&snapshot, cx);
 1816            });
 1817        });
 1818        clone.folds_did_change(cx);
 1819        clone.selections.clone_state(&self.selections);
 1820        clone.scroll_manager.clone_state(&self.scroll_manager);
 1821        clone.searchable = self.searchable;
 1822        clone.read_only = self.read_only;
 1823        clone
 1824    }
 1825
 1826    pub fn new(
 1827        mode: EditorMode,
 1828        buffer: Entity<MultiBuffer>,
 1829        project: Option<Entity<Project>>,
 1830        window: &mut Window,
 1831        cx: &mut Context<Self>,
 1832    ) -> Self {
 1833        Editor::new_internal(mode, buffer, project, None, window, cx)
 1834    }
 1835
 1836    pub fn sticky_headers(
 1837        &self,
 1838        style: &EditorStyle,
 1839        cx: &App,
 1840    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1841        let multi_buffer = self.buffer().read(cx);
 1842        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1843        let multi_buffer_visible_start = self
 1844            .scroll_manager
 1845            .anchor()
 1846            .anchor
 1847            .to_point(&multi_buffer_snapshot);
 1848        let max_row = multi_buffer_snapshot.max_point().row;
 1849
 1850        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1851        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1852
 1853        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1854            let outline_items = buffer
 1855                .outline_items_containing(
 1856                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1857                    true,
 1858                    Some(style.syntax.as_ref()),
 1859                )
 1860                .into_iter()
 1861                .map(|outline_item| OutlineItem {
 1862                    depth: outline_item.depth,
 1863                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1864                    source_range_for_text: Anchor::range_in_buffer(
 1865                        *excerpt_id,
 1866                        outline_item.source_range_for_text,
 1867                    ),
 1868                    text: outline_item.text,
 1869                    highlight_ranges: outline_item.highlight_ranges,
 1870                    name_ranges: outline_item.name_ranges,
 1871                    body_range: outline_item
 1872                        .body_range
 1873                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1874                    annotation_range: outline_item
 1875                        .annotation_range
 1876                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1877                });
 1878            return Some(outline_items.collect());
 1879        }
 1880
 1881        None
 1882    }
 1883
 1884    fn new_internal(
 1885        mode: EditorMode,
 1886        multi_buffer: Entity<MultiBuffer>,
 1887        project: Option<Entity<Project>>,
 1888        display_map: Option<Entity<DisplayMap>>,
 1889        window: &mut Window,
 1890        cx: &mut Context<Self>,
 1891    ) -> Self {
 1892        debug_assert!(
 1893            display_map.is_none() || mode.is_minimap(),
 1894            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1895        );
 1896
 1897        let full_mode = mode.is_full();
 1898        let is_minimap = mode.is_minimap();
 1899        let diagnostics_max_severity = if full_mode {
 1900            EditorSettings::get_global(cx)
 1901                .diagnostics_max_severity
 1902                .unwrap_or(DiagnosticSeverity::Hint)
 1903        } else {
 1904            DiagnosticSeverity::Off
 1905        };
 1906        let style = window.text_style();
 1907        let font_size = style.font_size.to_pixels(window.rem_size());
 1908        let editor = cx.entity().downgrade();
 1909        let fold_placeholder = FoldPlaceholder {
 1910            constrain_width: false,
 1911            render: Arc::new(move |fold_id, fold_range, cx| {
 1912                let editor = editor.clone();
 1913                div()
 1914                    .id(fold_id)
 1915                    .bg(cx.theme().colors().ghost_element_background)
 1916                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1917                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1918                    .rounded_xs()
 1919                    .size_full()
 1920                    .cursor_pointer()
 1921                    .child("")
 1922                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1923                    .on_click(move |_, _window, cx| {
 1924                        editor
 1925                            .update(cx, |editor, cx| {
 1926                                editor.unfold_ranges(
 1927                                    &[fold_range.start..fold_range.end],
 1928                                    true,
 1929                                    false,
 1930                                    cx,
 1931                                );
 1932                                cx.stop_propagation();
 1933                            })
 1934                            .ok();
 1935                    })
 1936                    .into_any()
 1937            }),
 1938            merge_adjacent: true,
 1939            ..FoldPlaceholder::default()
 1940        };
 1941        let display_map = display_map.unwrap_or_else(|| {
 1942            cx.new(|cx| {
 1943                DisplayMap::new(
 1944                    multi_buffer.clone(),
 1945                    style.font(),
 1946                    font_size,
 1947                    None,
 1948                    FILE_HEADER_HEIGHT,
 1949                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1950                    fold_placeholder,
 1951                    diagnostics_max_severity,
 1952                    cx,
 1953                )
 1954            })
 1955        });
 1956
 1957        let selections = SelectionsCollection::new();
 1958
 1959        let blink_manager = cx.new(|cx| {
 1960            let mut blink_manager = BlinkManager::new(
 1961                CURSOR_BLINK_INTERVAL,
 1962                |cx| EditorSettings::get_global(cx).cursor_blink,
 1963                cx,
 1964            );
 1965            if is_minimap {
 1966                blink_manager.disable(cx);
 1967            }
 1968            blink_manager
 1969        });
 1970
 1971        let soft_wrap_mode_override =
 1972            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1973
 1974        let mut project_subscriptions = Vec::new();
 1975        if full_mode && let Some(project) = project.as_ref() {
 1976            project_subscriptions.push(cx.subscribe_in(
 1977                project,
 1978                window,
 1979                |editor, _, event, window, cx| match event {
 1980                    project::Event::RefreshCodeLens => {
 1981                        // we always query lens with actions, without storing them, always refreshing them
 1982                    }
 1983                    project::Event::RefreshInlayHints {
 1984                        server_id,
 1985                        request_id,
 1986                    } => {
 1987                        editor.refresh_inlay_hints(
 1988                            InlayHintRefreshReason::RefreshRequested {
 1989                                server_id: *server_id,
 1990                                request_id: *request_id,
 1991                            },
 1992                            cx,
 1993                        );
 1994                    }
 1995                    project::Event::LanguageServerRemoved(..) => {
 1996                        if editor.tasks_update_task.is_none() {
 1997                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1998                        }
 1999                        editor.registered_buffers.clear();
 2000                        editor.register_visible_buffers(cx);
 2001                    }
 2002                    project::Event::LanguageServerAdded(..) => {
 2003                        if editor.tasks_update_task.is_none() {
 2004                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2005                        }
 2006                    }
 2007                    project::Event::SnippetEdit(id, snippet_edits) => {
 2008                        // todo(lw): Non singletons
 2009                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2010                            let snapshot = buffer.read(cx).snapshot();
 2011                            let focus_handle = editor.focus_handle(cx);
 2012                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2013                                for (range, snippet) in snippet_edits {
 2014                                    let buffer_range =
 2015                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2016                                    editor
 2017                                        .insert_snippet(
 2018                                            &[MultiBufferOffset(buffer_range.start)
 2019                                                ..MultiBufferOffset(buffer_range.end)],
 2020                                            snippet.clone(),
 2021                                            window,
 2022                                            cx,
 2023                                        )
 2024                                        .ok();
 2025                                }
 2026                            }
 2027                        }
 2028                    }
 2029                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2030                        let buffer_id = *buffer_id;
 2031                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2032                            editor.register_buffer(buffer_id, cx);
 2033                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2034                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2035                            refresh_linked_ranges(editor, window, cx);
 2036                            editor.refresh_code_actions(window, cx);
 2037                            editor.refresh_document_highlights(cx);
 2038                        }
 2039                    }
 2040
 2041                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2042                        let Some(workspace) = editor.workspace() else {
 2043                            return;
 2044                        };
 2045                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2046                        else {
 2047                            return;
 2048                        };
 2049
 2050                        if active_editor.entity_id() == cx.entity_id() {
 2051                            let entity_id = cx.entity_id();
 2052                            workspace.update(cx, |this, cx| {
 2053                                this.panes_mut()
 2054                                    .iter_mut()
 2055                                    .filter(|pane| pane.entity_id() != entity_id)
 2056                                    .for_each(|p| {
 2057                                        p.update(cx, |pane, _| {
 2058                                            pane.nav_history_mut().rename_item(
 2059                                                entity_id,
 2060                                                project_path.clone(),
 2061                                                abs_path.clone().into(),
 2062                                            );
 2063                                        })
 2064                                    });
 2065                            });
 2066                            let edited_buffers_already_open = {
 2067                                let other_editors: Vec<Entity<Editor>> = workspace
 2068                                    .read(cx)
 2069                                    .panes()
 2070                                    .iter()
 2071                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2072                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2073                                    .collect();
 2074
 2075                                transaction.0.keys().all(|buffer| {
 2076                                    other_editors.iter().any(|editor| {
 2077                                        let multi_buffer = editor.read(cx).buffer();
 2078                                        multi_buffer.read(cx).is_singleton()
 2079                                            && multi_buffer.read(cx).as_singleton().map_or(
 2080                                                false,
 2081                                                |singleton| {
 2082                                                    singleton.entity_id() == buffer.entity_id()
 2083                                                },
 2084                                            )
 2085                                    })
 2086                                })
 2087                            };
 2088                            if !edited_buffers_already_open {
 2089                                let workspace = workspace.downgrade();
 2090                                let transaction = transaction.clone();
 2091                                cx.defer_in(window, move |_, window, cx| {
 2092                                    cx.spawn_in(window, async move |editor, cx| {
 2093                                        Self::open_project_transaction(
 2094                                            &editor,
 2095                                            workspace,
 2096                                            transaction,
 2097                                            "Rename".to_string(),
 2098                                            cx,
 2099                                        )
 2100                                        .await
 2101                                        .ok()
 2102                                    })
 2103                                    .detach();
 2104                                });
 2105                            }
 2106                        }
 2107                    }
 2108
 2109                    _ => {}
 2110                },
 2111            ));
 2112            if let Some(task_inventory) = project
 2113                .read(cx)
 2114                .task_store()
 2115                .read(cx)
 2116                .task_inventory()
 2117                .cloned()
 2118            {
 2119                project_subscriptions.push(cx.observe_in(
 2120                    &task_inventory,
 2121                    window,
 2122                    |editor, _, window, cx| {
 2123                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2124                    },
 2125                ));
 2126            };
 2127
 2128            project_subscriptions.push(cx.subscribe_in(
 2129                &project.read(cx).breakpoint_store(),
 2130                window,
 2131                |editor, _, event, window, cx| match event {
 2132                    BreakpointStoreEvent::ClearDebugLines => {
 2133                        editor.clear_row_highlights::<ActiveDebugLine>();
 2134                        editor.refresh_inline_values(cx);
 2135                    }
 2136                    BreakpointStoreEvent::SetDebugLine => {
 2137                        if editor.go_to_active_debug_line(window, cx) {
 2138                            cx.stop_propagation();
 2139                        }
 2140
 2141                        editor.refresh_inline_values(cx);
 2142                    }
 2143                    _ => {}
 2144                },
 2145            ));
 2146            let git_store = project.read(cx).git_store().clone();
 2147            let project = project.clone();
 2148            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2149                if let GitStoreEvent::RepositoryAdded = event {
 2150                    this.load_diff_task = Some(
 2151                        update_uncommitted_diff_for_buffer(
 2152                            cx.entity(),
 2153                            &project,
 2154                            this.buffer.read(cx).all_buffers(),
 2155                            this.buffer.clone(),
 2156                            cx,
 2157                        )
 2158                        .shared(),
 2159                    );
 2160                }
 2161            }));
 2162        }
 2163
 2164        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2165
 2166        let inlay_hint_settings =
 2167            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2168        let focus_handle = cx.focus_handle();
 2169        if !is_minimap {
 2170            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2171                .detach();
 2172            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2173                .detach();
 2174            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2175                .detach();
 2176            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2177                .detach();
 2178            cx.observe_pending_input(window, Self::observe_pending_input)
 2179                .detach();
 2180        }
 2181
 2182        let show_indent_guides =
 2183            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2184                Some(false)
 2185            } else {
 2186                None
 2187            };
 2188
 2189        let breakpoint_store = match (&mode, project.as_ref()) {
 2190            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2191            _ => None,
 2192        };
 2193
 2194        let mut code_action_providers = Vec::new();
 2195        let mut load_uncommitted_diff = None;
 2196        if let Some(project) = project.clone() {
 2197            load_uncommitted_diff = Some(
 2198                update_uncommitted_diff_for_buffer(
 2199                    cx.entity(),
 2200                    &project,
 2201                    multi_buffer.read(cx).all_buffers(),
 2202                    multi_buffer.clone(),
 2203                    cx,
 2204                )
 2205                .shared(),
 2206            );
 2207            code_action_providers.push(Rc::new(project) as Rc<_>);
 2208        }
 2209
 2210        let mut editor = Self {
 2211            focus_handle,
 2212            show_cursor_when_unfocused: false,
 2213            last_focused_descendant: None,
 2214            buffer: multi_buffer.clone(),
 2215            display_map: display_map.clone(),
 2216            placeholder_display_map: None,
 2217            selections,
 2218            scroll_manager: ScrollManager::new(cx),
 2219            columnar_selection_state: None,
 2220            add_selections_state: None,
 2221            select_next_state: None,
 2222            select_prev_state: None,
 2223            selection_history: SelectionHistory::default(),
 2224            defer_selection_effects: false,
 2225            deferred_selection_effects_state: None,
 2226            autoclose_regions: Vec::new(),
 2227            snippet_stack: InvalidationStack::default(),
 2228            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2229            ime_transaction: None,
 2230            active_diagnostics: ActiveDiagnostic::None,
 2231            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2232            inline_diagnostics_update: Task::ready(()),
 2233            inline_diagnostics: Vec::new(),
 2234            soft_wrap_mode_override,
 2235            diagnostics_max_severity,
 2236            hard_wrap: None,
 2237            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2238            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2239            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2240            project,
 2241            blink_manager: blink_manager.clone(),
 2242            show_local_selections: true,
 2243            show_scrollbars: ScrollbarAxes {
 2244                horizontal: full_mode,
 2245                vertical: full_mode,
 2246            },
 2247            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2248            offset_content: !matches!(mode, EditorMode::SingleLine),
 2249            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2250            show_gutter: full_mode,
 2251            show_line_numbers: (!full_mode).then_some(false),
 2252            use_relative_line_numbers: None,
 2253            disable_expand_excerpt_buttons: !full_mode,
 2254            show_git_diff_gutter: None,
 2255            show_code_actions: None,
 2256            show_runnables: None,
 2257            show_breakpoints: None,
 2258            show_wrap_guides: None,
 2259            show_indent_guides,
 2260            buffers_with_disabled_indent_guides: HashSet::default(),
 2261            highlight_order: 0,
 2262            highlighted_rows: HashMap::default(),
 2263            background_highlights: HashMap::default(),
 2264            gutter_highlights: HashMap::default(),
 2265            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2266            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2267            nav_history: None,
 2268            context_menu: RefCell::new(None),
 2269            context_menu_options: None,
 2270            mouse_context_menu: None,
 2271            completion_tasks: Vec::new(),
 2272            inline_blame_popover: None,
 2273            inline_blame_popover_show_task: None,
 2274            signature_help_state: SignatureHelpState::default(),
 2275            auto_signature_help: None,
 2276            find_all_references_task_sources: Vec::new(),
 2277            next_completion_id: 0,
 2278            next_inlay_id: 0,
 2279            code_action_providers,
 2280            available_code_actions: None,
 2281            code_actions_task: None,
 2282            quick_selection_highlight_task: None,
 2283            debounced_selection_highlight_task: None,
 2284            document_highlights_task: None,
 2285            linked_editing_range_task: None,
 2286            pending_rename: None,
 2287            searchable: !is_minimap,
 2288            cursor_shape: EditorSettings::get_global(cx)
 2289                .cursor_shape
 2290                .unwrap_or_default(),
 2291            cursor_offset_on_selection: false,
 2292            current_line_highlight: None,
 2293            autoindent_mode: Some(AutoindentMode::EachLine),
 2294            collapse_matches: false,
 2295            workspace: None,
 2296            input_enabled: !is_minimap,
 2297            use_modal_editing: full_mode,
 2298            read_only: is_minimap,
 2299            use_autoclose: true,
 2300            use_auto_surround: true,
 2301            auto_replace_emoji_shortcode: false,
 2302            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2303            leader_id: None,
 2304            remote_id: None,
 2305            hover_state: HoverState::default(),
 2306            pending_mouse_down: None,
 2307            prev_pressure_stage: None,
 2308            hovered_link_state: None,
 2309            edit_prediction_provider: None,
 2310            active_edit_prediction: None,
 2311            stale_edit_prediction_in_menu: None,
 2312            edit_prediction_preview: EditPredictionPreview::Inactive {
 2313                released_too_fast: false,
 2314            },
 2315            inline_diagnostics_enabled: full_mode,
 2316            diagnostics_enabled: full_mode,
 2317            word_completions_enabled: full_mode,
 2318            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2319            gutter_hovered: false,
 2320            pixel_position_of_newest_cursor: None,
 2321            last_bounds: None,
 2322            last_position_map: None,
 2323            expect_bounds_change: None,
 2324            gutter_dimensions: GutterDimensions::default(),
 2325            style: None,
 2326            show_cursor_names: false,
 2327            hovered_cursors: HashMap::default(),
 2328            next_editor_action_id: EditorActionId::default(),
 2329            editor_actions: Rc::default(),
 2330            edit_predictions_hidden_for_vim_mode: false,
 2331            show_edit_predictions_override: None,
 2332            show_completions_on_input_override: None,
 2333            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2334            edit_prediction_settings: EditPredictionSettings::Disabled,
 2335            edit_prediction_indent_conflict: false,
 2336            edit_prediction_requires_modifier_in_indent_conflict: true,
 2337            custom_context_menu: None,
 2338            show_git_blame_gutter: false,
 2339            show_git_blame_inline: false,
 2340            show_selection_menu: None,
 2341            show_git_blame_inline_delay_task: None,
 2342            git_blame_inline_enabled: full_mode
 2343                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2344            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2345            buffer_serialization: is_minimap.not().then(|| {
 2346                BufferSerialization::new(
 2347                    ProjectSettings::get_global(cx)
 2348                        .session
 2349                        .restore_unsaved_buffers,
 2350                )
 2351            }),
 2352            blame: None,
 2353            blame_subscription: None,
 2354            tasks: BTreeMap::default(),
 2355
 2356            breakpoint_store,
 2357            gutter_breakpoint_indicator: (None, None),
 2358            hovered_diff_hunk_row: None,
 2359            _subscriptions: (!is_minimap)
 2360                .then(|| {
 2361                    vec![
 2362                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2363                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2364                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2365                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2366                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2367                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2368                        cx.observe_window_activation(window, |editor, window, cx| {
 2369                            let active = window.is_window_active();
 2370                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2371                                if active {
 2372                                    blink_manager.enable(cx);
 2373                                } else {
 2374                                    blink_manager.disable(cx);
 2375                                }
 2376                            });
 2377                            if active {
 2378                                editor.show_mouse_cursor(cx);
 2379                            }
 2380                        }),
 2381                    ]
 2382                })
 2383                .unwrap_or_default(),
 2384            tasks_update_task: None,
 2385            pull_diagnostics_task: Task::ready(()),
 2386            pull_diagnostics_background_task: Task::ready(()),
 2387            colors: None,
 2388            refresh_colors_task: Task::ready(()),
 2389            inlay_hints: None,
 2390            next_color_inlay_id: 0,
 2391            post_scroll_update: Task::ready(()),
 2392            linked_edit_ranges: Default::default(),
 2393            in_project_search: false,
 2394            previous_search_ranges: None,
 2395            breadcrumb_header: None,
 2396            focused_block: None,
 2397            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2398            addons: HashMap::default(),
 2399            registered_buffers: HashMap::default(),
 2400            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2401            selection_mark_mode: false,
 2402            toggle_fold_multiple_buffers: Task::ready(()),
 2403            serialize_selections: Task::ready(()),
 2404            serialize_folds: Task::ready(()),
 2405            text_style_refinement: None,
 2406            load_diff_task: load_uncommitted_diff,
 2407            temporary_diff_override: false,
 2408            mouse_cursor_hidden: false,
 2409            minimap: None,
 2410            hide_mouse_mode: EditorSettings::get_global(cx)
 2411                .hide_mouse
 2412                .unwrap_or_default(),
 2413            change_list: ChangeList::new(),
 2414            mode,
 2415            selection_drag_state: SelectionDragState::None,
 2416            folding_newlines: Task::ready(()),
 2417            lookup_key: None,
 2418            select_next_is_case_sensitive: None,
 2419            applicable_language_settings: HashMap::default(),
 2420            accent_data: None,
 2421            fetched_tree_sitter_chunks: HashMap::default(),
 2422            use_base_text_line_numbers: false,
 2423        };
 2424
 2425        if is_minimap {
 2426            return editor;
 2427        }
 2428
 2429        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2430        editor.accent_data = editor.fetch_accent_data(cx);
 2431
 2432        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2433            editor
 2434                ._subscriptions
 2435                .push(cx.observe(breakpoints, |_, _, cx| {
 2436                    cx.notify();
 2437                }));
 2438        }
 2439        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2440        editor._subscriptions.extend(project_subscriptions);
 2441
 2442        editor._subscriptions.push(cx.subscribe_in(
 2443            &cx.entity(),
 2444            window,
 2445            |editor, _, e: &EditorEvent, window, cx| match e {
 2446                EditorEvent::ScrollPositionChanged { local, .. } => {
 2447                    if *local {
 2448                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2449                        editor.inline_blame_popover.take();
 2450                        let new_anchor = editor.scroll_manager.anchor();
 2451                        let snapshot = editor.snapshot(window, cx);
 2452                        editor.update_restoration_data(cx, move |data| {
 2453                            data.scroll_position = (
 2454                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2455                                new_anchor.offset,
 2456                            );
 2457                        });
 2458
 2459                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2460                            cx.background_executor()
 2461                                .timer(Duration::from_millis(50))
 2462                                .await;
 2463                            editor
 2464                                .update_in(cx, |editor, window, cx| {
 2465                                    editor.register_visible_buffers(cx);
 2466                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2467                                    editor.refresh_inlay_hints(
 2468                                        InlayHintRefreshReason::NewLinesShown,
 2469                                        cx,
 2470                                    );
 2471                                    editor.colorize_brackets(false, cx);
 2472                                })
 2473                                .ok();
 2474                        });
 2475                    }
 2476                }
 2477                EditorEvent::Edited { .. } => {
 2478                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2479                        .map(|vim_mode| vim_mode.0)
 2480                        .unwrap_or(false);
 2481                    if !vim_mode {
 2482                        let display_map = editor.display_snapshot(cx);
 2483                        let selections = editor.selections.all_adjusted_display(&display_map);
 2484                        let pop_state = editor
 2485                            .change_list
 2486                            .last()
 2487                            .map(|previous| {
 2488                                previous.len() == selections.len()
 2489                                    && previous.iter().enumerate().all(|(ix, p)| {
 2490                                        p.to_display_point(&display_map).row()
 2491                                            == selections[ix].head().row()
 2492                                    })
 2493                            })
 2494                            .unwrap_or(false);
 2495                        let new_positions = selections
 2496                            .into_iter()
 2497                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2498                            .collect();
 2499                        editor
 2500                            .change_list
 2501                            .push_to_change_list(pop_state, new_positions);
 2502                    }
 2503                }
 2504                _ => (),
 2505            },
 2506        ));
 2507
 2508        if let Some(dap_store) = editor
 2509            .project
 2510            .as_ref()
 2511            .map(|project| project.read(cx).dap_store())
 2512        {
 2513            let weak_editor = cx.weak_entity();
 2514
 2515            editor
 2516                ._subscriptions
 2517                .push(
 2518                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2519                        let session_entity = cx.entity();
 2520                        weak_editor
 2521                            .update(cx, |editor, cx| {
 2522                                editor._subscriptions.push(
 2523                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2524                                );
 2525                            })
 2526                            .ok();
 2527                    }),
 2528                );
 2529
 2530            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2531                editor
 2532                    ._subscriptions
 2533                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2534            }
 2535        }
 2536
 2537        // skip adding the initial selection to selection history
 2538        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2539        editor.end_selection(window, cx);
 2540        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2541
 2542        editor.scroll_manager.show_scrollbars(window, cx);
 2543        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2544
 2545        if full_mode {
 2546            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2547            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2548
 2549            if editor.git_blame_inline_enabled {
 2550                editor.start_git_blame_inline(false, window, cx);
 2551            }
 2552
 2553            editor.go_to_active_debug_line(window, cx);
 2554
 2555            editor.minimap =
 2556                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2557            editor.colors = Some(LspColorData::new(cx));
 2558            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2559
 2560            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2561                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2562            }
 2563            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2564        }
 2565
 2566        editor
 2567    }
 2568
 2569    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2570        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2571    }
 2572
 2573    pub fn deploy_mouse_context_menu(
 2574        &mut self,
 2575        position: gpui::Point<Pixels>,
 2576        context_menu: Entity<ContextMenu>,
 2577        window: &mut Window,
 2578        cx: &mut Context<Self>,
 2579    ) {
 2580        self.mouse_context_menu = Some(MouseContextMenu::new(
 2581            self,
 2582            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2583            context_menu,
 2584            window,
 2585            cx,
 2586        ));
 2587    }
 2588
 2589    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2590        self.mouse_context_menu
 2591            .as_ref()
 2592            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2593    }
 2594
 2595    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2596        if self
 2597            .selections
 2598            .pending_anchor()
 2599            .is_some_and(|pending_selection| {
 2600                let snapshot = self.buffer().read(cx).snapshot(cx);
 2601                pending_selection.range().includes(range, &snapshot)
 2602            })
 2603        {
 2604            return true;
 2605        }
 2606
 2607        self.selections
 2608            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2609            .into_iter()
 2610            .any(|selection| {
 2611                // This is needed to cover a corner case, if we just check for an existing
 2612                // selection in the fold range, having a cursor at the start of the fold
 2613                // marks it as selected. Non-empty selections don't cause this.
 2614                let length = selection.end - selection.start;
 2615                length > 0
 2616            })
 2617    }
 2618
 2619    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2620        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2621    }
 2622
 2623    fn key_context_internal(
 2624        &self,
 2625        has_active_edit_prediction: bool,
 2626        window: &mut Window,
 2627        cx: &mut App,
 2628    ) -> KeyContext {
 2629        let mut key_context = KeyContext::new_with_defaults();
 2630        key_context.add("Editor");
 2631        let mode = match self.mode {
 2632            EditorMode::SingleLine => "single_line",
 2633            EditorMode::AutoHeight { .. } => "auto_height",
 2634            EditorMode::Minimap { .. } => "minimap",
 2635            EditorMode::Full { .. } => "full",
 2636        };
 2637
 2638        if EditorSettings::jupyter_enabled(cx) {
 2639            key_context.add("jupyter");
 2640        }
 2641
 2642        key_context.set("mode", mode);
 2643        if self.pending_rename.is_some() {
 2644            key_context.add("renaming");
 2645        }
 2646
 2647        if let Some(snippet_stack) = self.snippet_stack.last() {
 2648            key_context.add("in_snippet");
 2649
 2650            if snippet_stack.active_index > 0 {
 2651                key_context.add("has_previous_tabstop");
 2652            }
 2653
 2654            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2655                key_context.add("has_next_tabstop");
 2656            }
 2657        }
 2658
 2659        match self.context_menu.borrow().as_ref() {
 2660            Some(CodeContextMenu::Completions(menu)) => {
 2661                if menu.visible() {
 2662                    key_context.add("menu");
 2663                    key_context.add("showing_completions");
 2664                }
 2665            }
 2666            Some(CodeContextMenu::CodeActions(menu)) => {
 2667                if menu.visible() {
 2668                    key_context.add("menu");
 2669                    key_context.add("showing_code_actions")
 2670                }
 2671            }
 2672            None => {}
 2673        }
 2674
 2675        if self.signature_help_state.has_multiple_signatures() {
 2676            key_context.add("showing_signature_help");
 2677        }
 2678
 2679        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2680        if !self.focus_handle(cx).contains_focused(window, cx)
 2681            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2682        {
 2683            for addon in self.addons.values() {
 2684                addon.extend_key_context(&mut key_context, cx)
 2685            }
 2686        }
 2687
 2688        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2689            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2690                Some(
 2691                    file.full_path(cx)
 2692                        .extension()?
 2693                        .to_string_lossy()
 2694                        .into_owned(),
 2695                )
 2696            }) {
 2697                key_context.set("extension", extension);
 2698            }
 2699        } else {
 2700            key_context.add("multibuffer");
 2701        }
 2702
 2703        if has_active_edit_prediction {
 2704            if self.edit_prediction_in_conflict() {
 2705                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2706            } else {
 2707                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2708                key_context.add("copilot_suggestion");
 2709            }
 2710        }
 2711
 2712        if self.selection_mark_mode {
 2713            key_context.add("selection_mode");
 2714        }
 2715
 2716        let disjoint = self.selections.disjoint_anchors();
 2717        let snapshot = self.snapshot(window, cx);
 2718        let snapshot = snapshot.buffer_snapshot();
 2719        if self.mode == EditorMode::SingleLine
 2720            && let [selection] = disjoint
 2721            && selection.start == selection.end
 2722            && selection.end.to_offset(snapshot) == snapshot.len()
 2723        {
 2724            key_context.add("end_of_input");
 2725        }
 2726
 2727        if self.has_any_expanded_diff_hunks(cx) {
 2728            key_context.add("diffs_expanded");
 2729        }
 2730
 2731        key_context
 2732    }
 2733
 2734    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2735        self.last_bounds.as_ref()
 2736    }
 2737
 2738    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2739        if self.mouse_cursor_hidden {
 2740            self.mouse_cursor_hidden = false;
 2741            cx.notify();
 2742        }
 2743    }
 2744
 2745    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2746        let hide_mouse_cursor = match origin {
 2747            HideMouseCursorOrigin::TypingAction => {
 2748                matches!(
 2749                    self.hide_mouse_mode,
 2750                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2751                )
 2752            }
 2753            HideMouseCursorOrigin::MovementAction => {
 2754                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2755            }
 2756        };
 2757        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2758            self.mouse_cursor_hidden = hide_mouse_cursor;
 2759            cx.notify();
 2760        }
 2761    }
 2762
 2763    pub fn edit_prediction_in_conflict(&self) -> bool {
 2764        if !self.show_edit_predictions_in_menu() {
 2765            return false;
 2766        }
 2767
 2768        let showing_completions = self
 2769            .context_menu
 2770            .borrow()
 2771            .as_ref()
 2772            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2773
 2774        showing_completions
 2775            || self.edit_prediction_requires_modifier()
 2776            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2777            // bindings to insert tab characters.
 2778            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2779    }
 2780
 2781    pub fn accept_edit_prediction_keybind(
 2782        &self,
 2783        granularity: EditPredictionGranularity,
 2784        window: &mut Window,
 2785        cx: &mut App,
 2786    ) -> AcceptEditPredictionBinding {
 2787        let key_context = self.key_context_internal(true, window, cx);
 2788        let in_conflict = self.edit_prediction_in_conflict();
 2789
 2790        let bindings =
 2791            match granularity {
 2792                EditPredictionGranularity::Word => window
 2793                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2794                EditPredictionGranularity::Line => window
 2795                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2796                EditPredictionGranularity::Full => {
 2797                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2798                }
 2799            };
 2800
 2801        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2802            !in_conflict
 2803                || binding
 2804                    .keystrokes()
 2805                    .first()
 2806                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2807        }))
 2808    }
 2809
 2810    pub fn new_file(
 2811        workspace: &mut Workspace,
 2812        _: &workspace::NewFile,
 2813        window: &mut Window,
 2814        cx: &mut Context<Workspace>,
 2815    ) {
 2816        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2817            "Failed to create buffer",
 2818            window,
 2819            cx,
 2820            |e, _, _| match e.error_code() {
 2821                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2822                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2823                e.error_tag("required").unwrap_or("the latest version")
 2824            )),
 2825                _ => None,
 2826            },
 2827        );
 2828    }
 2829
 2830    pub fn new_in_workspace(
 2831        workspace: &mut Workspace,
 2832        window: &mut Window,
 2833        cx: &mut Context<Workspace>,
 2834    ) -> Task<Result<Entity<Editor>>> {
 2835        let project = workspace.project().clone();
 2836        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2837
 2838        cx.spawn_in(window, async move |workspace, cx| {
 2839            let buffer = create.await?;
 2840            workspace.update_in(cx, |workspace, window, cx| {
 2841                let editor =
 2842                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2843                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2844                editor
 2845            })
 2846        })
 2847    }
 2848
 2849    fn new_file_vertical(
 2850        workspace: &mut Workspace,
 2851        _: &workspace::NewFileSplitVertical,
 2852        window: &mut Window,
 2853        cx: &mut Context<Workspace>,
 2854    ) {
 2855        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2856    }
 2857
 2858    fn new_file_horizontal(
 2859        workspace: &mut Workspace,
 2860        _: &workspace::NewFileSplitHorizontal,
 2861        window: &mut Window,
 2862        cx: &mut Context<Workspace>,
 2863    ) {
 2864        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2865    }
 2866
 2867    fn new_file_split(
 2868        workspace: &mut Workspace,
 2869        action: &workspace::NewFileSplit,
 2870        window: &mut Window,
 2871        cx: &mut Context<Workspace>,
 2872    ) {
 2873        Self::new_file_in_direction(workspace, action.0, window, cx)
 2874    }
 2875
 2876    fn new_file_in_direction(
 2877        workspace: &mut Workspace,
 2878        direction: SplitDirection,
 2879        window: &mut Window,
 2880        cx: &mut Context<Workspace>,
 2881    ) {
 2882        let project = workspace.project().clone();
 2883        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2884
 2885        cx.spawn_in(window, async move |workspace, cx| {
 2886            let buffer = create.await?;
 2887            workspace.update_in(cx, move |workspace, window, cx| {
 2888                workspace.split_item(
 2889                    direction,
 2890                    Box::new(
 2891                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2892                    ),
 2893                    window,
 2894                    cx,
 2895                )
 2896            })?;
 2897            anyhow::Ok(())
 2898        })
 2899        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2900            match e.error_code() {
 2901                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2902                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2903                e.error_tag("required").unwrap_or("the latest version")
 2904            )),
 2905                _ => None,
 2906            }
 2907        });
 2908    }
 2909
 2910    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2911        self.leader_id
 2912    }
 2913
 2914    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2915        &self.buffer
 2916    }
 2917
 2918    pub fn project(&self) -> Option<&Entity<Project>> {
 2919        self.project.as_ref()
 2920    }
 2921
 2922    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2923        self.workspace.as_ref()?.0.upgrade()
 2924    }
 2925
 2926    /// Returns the workspace serialization ID if this editor should be serialized.
 2927    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2928        self.workspace
 2929            .as_ref()
 2930            .filter(|_| self.should_serialize_buffer())
 2931            .and_then(|workspace| workspace.1)
 2932    }
 2933
 2934    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2935        self.buffer().read(cx).title(cx)
 2936    }
 2937
 2938    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2939        let git_blame_gutter_max_author_length = self
 2940            .render_git_blame_gutter(cx)
 2941            .then(|| {
 2942                if let Some(blame) = self.blame.as_ref() {
 2943                    let max_author_length =
 2944                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2945                    Some(max_author_length)
 2946                } else {
 2947                    None
 2948                }
 2949            })
 2950            .flatten();
 2951
 2952        EditorSnapshot {
 2953            mode: self.mode.clone(),
 2954            show_gutter: self.show_gutter,
 2955            offset_content: self.offset_content,
 2956            show_line_numbers: self.show_line_numbers,
 2957            show_git_diff_gutter: self.show_git_diff_gutter,
 2958            show_code_actions: self.show_code_actions,
 2959            show_runnables: self.show_runnables,
 2960            show_breakpoints: self.show_breakpoints,
 2961            git_blame_gutter_max_author_length,
 2962            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2963            placeholder_display_snapshot: self
 2964                .placeholder_display_map
 2965                .as_ref()
 2966                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2967            scroll_anchor: self.scroll_manager.anchor(),
 2968            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2969            is_focused: self.focus_handle.is_focused(window),
 2970            current_line_highlight: self
 2971                .current_line_highlight
 2972                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2973            gutter_hovered: self.gutter_hovered,
 2974        }
 2975    }
 2976
 2977    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2978        self.buffer.read(cx).language_at(point, cx)
 2979    }
 2980
 2981    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2982        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2983    }
 2984
 2985    pub fn active_excerpt(
 2986        &self,
 2987        cx: &App,
 2988    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2989        self.buffer
 2990            .read(cx)
 2991            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2992    }
 2993
 2994    pub fn mode(&self) -> &EditorMode {
 2995        &self.mode
 2996    }
 2997
 2998    pub fn set_mode(&mut self, mode: EditorMode) {
 2999        self.mode = mode;
 3000    }
 3001
 3002    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3003        self.collaboration_hub.as_deref()
 3004    }
 3005
 3006    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3007        self.collaboration_hub = Some(hub);
 3008    }
 3009
 3010    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3011        self.in_project_search = in_project_search;
 3012    }
 3013
 3014    pub fn set_custom_context_menu(
 3015        &mut self,
 3016        f: impl 'static
 3017        + Fn(
 3018            &mut Self,
 3019            DisplayPoint,
 3020            &mut Window,
 3021            &mut Context<Self>,
 3022        ) -> Option<Entity<ui::ContextMenu>>,
 3023    ) {
 3024        self.custom_context_menu = Some(Box::new(f))
 3025    }
 3026
 3027    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3028        self.completion_provider = provider;
 3029    }
 3030
 3031    #[cfg(any(test, feature = "test-support"))]
 3032    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3033        self.completion_provider.clone()
 3034    }
 3035
 3036    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3037        self.semantics_provider.clone()
 3038    }
 3039
 3040    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3041        self.semantics_provider = provider;
 3042    }
 3043
 3044    pub fn set_edit_prediction_provider<T>(
 3045        &mut self,
 3046        provider: Option<Entity<T>>,
 3047        window: &mut Window,
 3048        cx: &mut Context<Self>,
 3049    ) where
 3050        T: EditPredictionDelegate,
 3051    {
 3052        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3053            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3054                if this.focus_handle.is_focused(window) {
 3055                    this.update_visible_edit_prediction(window, cx);
 3056                }
 3057            }),
 3058            provider: Arc::new(provider),
 3059        });
 3060        self.update_edit_prediction_settings(cx);
 3061        self.refresh_edit_prediction(false, false, window, cx);
 3062    }
 3063
 3064    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3065        self.placeholder_display_map
 3066            .as_ref()
 3067            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3068    }
 3069
 3070    pub fn set_placeholder_text(
 3071        &mut self,
 3072        placeholder_text: &str,
 3073        window: &mut Window,
 3074        cx: &mut Context<Self>,
 3075    ) {
 3076        let multibuffer = cx
 3077            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3078
 3079        let style = window.text_style();
 3080
 3081        self.placeholder_display_map = Some(cx.new(|cx| {
 3082            DisplayMap::new(
 3083                multibuffer,
 3084                style.font(),
 3085                style.font_size.to_pixels(window.rem_size()),
 3086                None,
 3087                FILE_HEADER_HEIGHT,
 3088                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3089                Default::default(),
 3090                DiagnosticSeverity::Off,
 3091                cx,
 3092            )
 3093        }));
 3094        cx.notify();
 3095    }
 3096
 3097    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3098        self.cursor_shape = cursor_shape;
 3099
 3100        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3101        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3102
 3103        cx.notify();
 3104    }
 3105
 3106    pub fn cursor_shape(&self) -> CursorShape {
 3107        self.cursor_shape
 3108    }
 3109
 3110    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3111        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3112    }
 3113
 3114    pub fn set_current_line_highlight(
 3115        &mut self,
 3116        current_line_highlight: Option<CurrentLineHighlight>,
 3117    ) {
 3118        self.current_line_highlight = current_line_highlight;
 3119    }
 3120
 3121    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3122        self.collapse_matches = collapse_matches;
 3123    }
 3124
 3125    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3126        if self.collapse_matches {
 3127            return range.start..range.start;
 3128        }
 3129        range.clone()
 3130    }
 3131
 3132    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3133        self.display_map.read(cx).clip_at_line_ends
 3134    }
 3135
 3136    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3137        if self.display_map.read(cx).clip_at_line_ends != clip {
 3138            self.display_map
 3139                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3140        }
 3141    }
 3142
 3143    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3144        self.input_enabled = input_enabled;
 3145    }
 3146
 3147    pub fn set_edit_predictions_hidden_for_vim_mode(
 3148        &mut self,
 3149        hidden: bool,
 3150        window: &mut Window,
 3151        cx: &mut Context<Self>,
 3152    ) {
 3153        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3154            self.edit_predictions_hidden_for_vim_mode = hidden;
 3155            if hidden {
 3156                self.update_visible_edit_prediction(window, cx);
 3157            } else {
 3158                self.refresh_edit_prediction(true, false, window, cx);
 3159            }
 3160        }
 3161    }
 3162
 3163    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3164        self.menu_edit_predictions_policy = value;
 3165    }
 3166
 3167    pub fn set_autoindent(&mut self, autoindent: bool) {
 3168        if autoindent {
 3169            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3170        } else {
 3171            self.autoindent_mode = None;
 3172        }
 3173    }
 3174
 3175    pub fn read_only(&self, cx: &App) -> bool {
 3176        self.read_only || self.buffer.read(cx).read_only()
 3177    }
 3178
 3179    pub fn set_read_only(&mut self, read_only: bool) {
 3180        self.read_only = read_only;
 3181    }
 3182
 3183    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3184        self.use_autoclose = autoclose;
 3185    }
 3186
 3187    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3188        self.use_auto_surround = auto_surround;
 3189    }
 3190
 3191    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3192        self.auto_replace_emoji_shortcode = auto_replace;
 3193    }
 3194
 3195    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3196        self.buffer_serialization = should_serialize.then(|| {
 3197            BufferSerialization::new(
 3198                ProjectSettings::get_global(cx)
 3199                    .session
 3200                    .restore_unsaved_buffers,
 3201            )
 3202        })
 3203    }
 3204
 3205    fn should_serialize_buffer(&self) -> bool {
 3206        self.buffer_serialization.is_some()
 3207    }
 3208
 3209    pub fn toggle_edit_predictions(
 3210        &mut self,
 3211        _: &ToggleEditPrediction,
 3212        window: &mut Window,
 3213        cx: &mut Context<Self>,
 3214    ) {
 3215        if self.show_edit_predictions_override.is_some() {
 3216            self.set_show_edit_predictions(None, window, cx);
 3217        } else {
 3218            let show_edit_predictions = !self.edit_predictions_enabled();
 3219            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3220        }
 3221    }
 3222
 3223    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3224        self.show_completions_on_input_override = show_completions_on_input;
 3225    }
 3226
 3227    pub fn set_show_edit_predictions(
 3228        &mut self,
 3229        show_edit_predictions: Option<bool>,
 3230        window: &mut Window,
 3231        cx: &mut Context<Self>,
 3232    ) {
 3233        self.show_edit_predictions_override = show_edit_predictions;
 3234        self.update_edit_prediction_settings(cx);
 3235
 3236        if let Some(false) = show_edit_predictions {
 3237            self.discard_edit_prediction(false, cx);
 3238        } else {
 3239            self.refresh_edit_prediction(false, true, window, cx);
 3240        }
 3241    }
 3242
 3243    fn edit_predictions_disabled_in_scope(
 3244        &self,
 3245        buffer: &Entity<Buffer>,
 3246        buffer_position: language::Anchor,
 3247        cx: &App,
 3248    ) -> bool {
 3249        let snapshot = buffer.read(cx).snapshot();
 3250        let settings = snapshot.settings_at(buffer_position, cx);
 3251
 3252        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3253            return false;
 3254        };
 3255
 3256        scope.override_name().is_some_and(|scope_name| {
 3257            settings
 3258                .edit_predictions_disabled_in
 3259                .iter()
 3260                .any(|s| s == scope_name)
 3261        })
 3262    }
 3263
 3264    pub fn set_use_modal_editing(&mut self, to: bool) {
 3265        self.use_modal_editing = to;
 3266    }
 3267
 3268    pub fn use_modal_editing(&self) -> bool {
 3269        self.use_modal_editing
 3270    }
 3271
 3272    fn selections_did_change(
 3273        &mut self,
 3274        local: bool,
 3275        old_cursor_position: &Anchor,
 3276        effects: SelectionEffects,
 3277        window: &mut Window,
 3278        cx: &mut Context<Self>,
 3279    ) {
 3280        window.invalidate_character_coordinates();
 3281
 3282        // Copy selections to primary selection buffer
 3283        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3284        if local {
 3285            let selections = self
 3286                .selections
 3287                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3288            let buffer_handle = self.buffer.read(cx).read(cx);
 3289
 3290            let mut text = String::new();
 3291            for (index, selection) in selections.iter().enumerate() {
 3292                let text_for_selection = buffer_handle
 3293                    .text_for_range(selection.start..selection.end)
 3294                    .collect::<String>();
 3295
 3296                text.push_str(&text_for_selection);
 3297                if index != selections.len() - 1 {
 3298                    text.push('\n');
 3299                }
 3300            }
 3301
 3302            if !text.is_empty() {
 3303                cx.write_to_primary(ClipboardItem::new_string(text));
 3304            }
 3305        }
 3306
 3307        let selection_anchors = self.selections.disjoint_anchors_arc();
 3308
 3309        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3310            self.buffer.update(cx, |buffer, cx| {
 3311                buffer.set_active_selections(
 3312                    &selection_anchors,
 3313                    self.selections.line_mode(),
 3314                    self.cursor_shape,
 3315                    cx,
 3316                )
 3317            });
 3318        }
 3319        let display_map = self
 3320            .display_map
 3321            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3322        let buffer = display_map.buffer_snapshot();
 3323        if self.selections.count() == 1 {
 3324            self.add_selections_state = None;
 3325        }
 3326        self.select_next_state = None;
 3327        self.select_prev_state = None;
 3328        self.select_syntax_node_history.try_clear();
 3329        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3330        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3331        self.take_rename(false, window, cx);
 3332
 3333        let newest_selection = self.selections.newest_anchor();
 3334        let new_cursor_position = newest_selection.head();
 3335        let selection_start = newest_selection.start;
 3336
 3337        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3338            self.push_to_nav_history(
 3339                *old_cursor_position,
 3340                Some(new_cursor_position.to_point(buffer)),
 3341                false,
 3342                effects.nav_history == Some(true),
 3343                cx,
 3344            );
 3345        }
 3346
 3347        if local {
 3348            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3349                self.register_buffer(buffer_id, cx);
 3350            }
 3351
 3352            let mut context_menu = self.context_menu.borrow_mut();
 3353            let completion_menu = match context_menu.as_ref() {
 3354                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3355                Some(CodeContextMenu::CodeActions(_)) => {
 3356                    *context_menu = None;
 3357                    None
 3358                }
 3359                None => None,
 3360            };
 3361            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3362            drop(context_menu);
 3363
 3364            if effects.completions
 3365                && let Some(completion_position) = completion_position
 3366            {
 3367                let start_offset = selection_start.to_offset(buffer);
 3368                let position_matches = start_offset == completion_position.to_offset(buffer);
 3369                let continue_showing = if position_matches {
 3370                    if self.snippet_stack.is_empty() {
 3371                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3372                            == Some(CharKind::Word)
 3373                    } else {
 3374                        // Snippet choices can be shown even when the cursor is in whitespace.
 3375                        // Dismissing the menu with actions like backspace is handled by
 3376                        // invalidation regions.
 3377                        true
 3378                    }
 3379                } else {
 3380                    false
 3381                };
 3382
 3383                if continue_showing {
 3384                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3385                } else {
 3386                    self.hide_context_menu(window, cx);
 3387                }
 3388            }
 3389
 3390            hide_hover(self, cx);
 3391
 3392            if old_cursor_position.to_display_point(&display_map).row()
 3393                != new_cursor_position.to_display_point(&display_map).row()
 3394            {
 3395                self.available_code_actions.take();
 3396            }
 3397            self.refresh_code_actions(window, cx);
 3398            self.refresh_document_highlights(cx);
 3399            refresh_linked_ranges(self, window, cx);
 3400
 3401            self.refresh_selected_text_highlights(false, window, cx);
 3402            self.refresh_matching_bracket_highlights(window, cx);
 3403            self.update_visible_edit_prediction(window, cx);
 3404            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3405            self.inline_blame_popover.take();
 3406            if self.git_blame_inline_enabled {
 3407                self.start_inline_blame_timer(window, cx);
 3408            }
 3409        }
 3410
 3411        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3412        cx.emit(EditorEvent::SelectionsChanged { local });
 3413
 3414        let selections = &self.selections.disjoint_anchors_arc();
 3415        if selections.len() == 1 {
 3416            cx.emit(SearchEvent::ActiveMatchChanged)
 3417        }
 3418        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3419            let inmemory_selections = selections
 3420                .iter()
 3421                .map(|s| {
 3422                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3423                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3424                })
 3425                .collect();
 3426            self.update_restoration_data(cx, |data| {
 3427                data.selections = inmemory_selections;
 3428            });
 3429
 3430            if WorkspaceSettings::get(None, cx).restore_on_startup
 3431                != RestoreOnStartupBehavior::EmptyTab
 3432                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3433            {
 3434                let snapshot = self.buffer().read(cx).snapshot(cx);
 3435                let selections = selections.clone();
 3436                let background_executor = cx.background_executor().clone();
 3437                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3438                self.serialize_selections = cx.background_spawn(async move {
 3439                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3440                    let db_selections = selections
 3441                        .iter()
 3442                        .map(|selection| {
 3443                            (
 3444                                selection.start.to_offset(&snapshot).0,
 3445                                selection.end.to_offset(&snapshot).0,
 3446                            )
 3447                        })
 3448                        .collect();
 3449
 3450                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3451                        .await
 3452                        .with_context(|| {
 3453                            format!(
 3454                                "persisting editor selections for editor {editor_id}, \
 3455                                workspace {workspace_id:?}"
 3456                            )
 3457                        })
 3458                        .log_err();
 3459                });
 3460            }
 3461        }
 3462
 3463        cx.notify();
 3464    }
 3465
 3466    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3467        use text::ToOffset as _;
 3468        use text::ToPoint as _;
 3469
 3470        if self.mode.is_minimap()
 3471            || WorkspaceSettings::get(None, cx).restore_on_startup
 3472                == RestoreOnStartupBehavior::EmptyTab
 3473        {
 3474            return;
 3475        }
 3476
 3477        if !self.buffer().read(cx).is_singleton() {
 3478            return;
 3479        }
 3480
 3481        let display_snapshot = self
 3482            .display_map
 3483            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3484        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3485            return;
 3486        };
 3487        let inmemory_folds = display_snapshot
 3488            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3489            .map(|fold| {
 3490                fold.range.start.text_anchor.to_point(&snapshot)
 3491                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3492            })
 3493            .collect();
 3494        self.update_restoration_data(cx, |data| {
 3495            data.folds = inmemory_folds;
 3496        });
 3497
 3498        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3499            return;
 3500        };
 3501        let background_executor = cx.background_executor().clone();
 3502        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3503        let db_folds = display_snapshot
 3504            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3505            .map(|fold| {
 3506                (
 3507                    fold.range.start.text_anchor.to_offset(&snapshot),
 3508                    fold.range.end.text_anchor.to_offset(&snapshot),
 3509                )
 3510            })
 3511            .collect();
 3512        self.serialize_folds = cx.background_spawn(async move {
 3513            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3514            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3515                .await
 3516                .with_context(|| {
 3517                    format!(
 3518                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3519                    )
 3520                })
 3521                .log_err();
 3522        });
 3523    }
 3524
 3525    pub fn sync_selections(
 3526        &mut self,
 3527        other: Entity<Editor>,
 3528        cx: &mut Context<Self>,
 3529    ) -> gpui::Subscription {
 3530        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3531        if !other_selections.is_empty() {
 3532            self.selections
 3533                .change_with(&self.display_snapshot(cx), |selections| {
 3534                    selections.select_anchors(other_selections);
 3535                });
 3536        }
 3537
 3538        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3539            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3540                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3541                if other_selections.is_empty() {
 3542                    return;
 3543                }
 3544                let snapshot = this.display_snapshot(cx);
 3545                this.selections.change_with(&snapshot, |selections| {
 3546                    selections.select_anchors(other_selections);
 3547                });
 3548            }
 3549        });
 3550
 3551        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3552            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3553                let these_selections = this.selections.disjoint_anchors().to_vec();
 3554                if these_selections.is_empty() {
 3555                    return;
 3556                }
 3557                other.update(cx, |other_editor, cx| {
 3558                    let snapshot = other_editor.display_snapshot(cx);
 3559                    other_editor
 3560                        .selections
 3561                        .change_with(&snapshot, |selections| {
 3562                            selections.select_anchors(these_selections);
 3563                        })
 3564                });
 3565            }
 3566        });
 3567
 3568        Subscription::join(other_subscription, this_subscription)
 3569    }
 3570
 3571    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3572        if self.buffer().read(cx).is_singleton() {
 3573            return;
 3574        }
 3575        let snapshot = self.buffer.read(cx).snapshot(cx);
 3576        let buffer_ids: HashSet<BufferId> = self
 3577            .selections
 3578            .disjoint_anchor_ranges()
 3579            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3580            .collect();
 3581        for buffer_id in buffer_ids {
 3582            self.unfold_buffer(buffer_id, cx);
 3583        }
 3584    }
 3585
 3586    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3587    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3588    /// effects of selection change occur at the end of the transaction.
 3589    pub fn change_selections<R>(
 3590        &mut self,
 3591        effects: SelectionEffects,
 3592        window: &mut Window,
 3593        cx: &mut Context<Self>,
 3594        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3595    ) -> R {
 3596        let snapshot = self.display_snapshot(cx);
 3597        if let Some(state) = &mut self.deferred_selection_effects_state {
 3598            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3599            state.effects.completions = effects.completions;
 3600            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3601            let (changed, result) = self.selections.change_with(&snapshot, change);
 3602            state.changed |= changed;
 3603            return result;
 3604        }
 3605        let mut state = DeferredSelectionEffectsState {
 3606            changed: false,
 3607            effects,
 3608            old_cursor_position: self.selections.newest_anchor().head(),
 3609            history_entry: SelectionHistoryEntry {
 3610                selections: self.selections.disjoint_anchors_arc(),
 3611                select_next_state: self.select_next_state.clone(),
 3612                select_prev_state: self.select_prev_state.clone(),
 3613                add_selections_state: self.add_selections_state.clone(),
 3614            },
 3615        };
 3616        let (changed, result) = self.selections.change_with(&snapshot, change);
 3617        state.changed = state.changed || changed;
 3618        if self.defer_selection_effects {
 3619            self.deferred_selection_effects_state = Some(state);
 3620        } else {
 3621            self.apply_selection_effects(state, window, cx);
 3622        }
 3623        result
 3624    }
 3625
 3626    /// Defers the effects of selection change, so that the effects of multiple calls to
 3627    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3628    /// to selection history and the state of popovers based on selection position aren't
 3629    /// erroneously updated.
 3630    pub fn with_selection_effects_deferred<R>(
 3631        &mut self,
 3632        window: &mut Window,
 3633        cx: &mut Context<Self>,
 3634        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3635    ) -> R {
 3636        let already_deferred = self.defer_selection_effects;
 3637        self.defer_selection_effects = true;
 3638        let result = update(self, window, cx);
 3639        if !already_deferred {
 3640            self.defer_selection_effects = false;
 3641            if let Some(state) = self.deferred_selection_effects_state.take() {
 3642                self.apply_selection_effects(state, window, cx);
 3643            }
 3644        }
 3645        result
 3646    }
 3647
 3648    fn apply_selection_effects(
 3649        &mut self,
 3650        state: DeferredSelectionEffectsState,
 3651        window: &mut Window,
 3652        cx: &mut Context<Self>,
 3653    ) {
 3654        if state.changed {
 3655            self.selection_history.push(state.history_entry);
 3656
 3657            if let Some(autoscroll) = state.effects.scroll {
 3658                self.request_autoscroll(autoscroll, cx);
 3659            }
 3660
 3661            let old_cursor_position = &state.old_cursor_position;
 3662
 3663            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3664
 3665            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3666                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3667            }
 3668        }
 3669    }
 3670
 3671    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3672    where
 3673        I: IntoIterator<Item = (Range<S>, T)>,
 3674        S: ToOffset,
 3675        T: Into<Arc<str>>,
 3676    {
 3677        if self.read_only(cx) {
 3678            return;
 3679        }
 3680
 3681        self.buffer
 3682            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3683    }
 3684
 3685    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3686    where
 3687        I: IntoIterator<Item = (Range<S>, T)>,
 3688        S: ToOffset,
 3689        T: Into<Arc<str>>,
 3690    {
 3691        if self.read_only(cx) {
 3692            return;
 3693        }
 3694
 3695        self.buffer.update(cx, |buffer, cx| {
 3696            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3697        });
 3698    }
 3699
 3700    pub fn edit_with_block_indent<I, S, T>(
 3701        &mut self,
 3702        edits: I,
 3703        original_indent_columns: Vec<Option<u32>>,
 3704        cx: &mut Context<Self>,
 3705    ) where
 3706        I: IntoIterator<Item = (Range<S>, T)>,
 3707        S: ToOffset,
 3708        T: Into<Arc<str>>,
 3709    {
 3710        if self.read_only(cx) {
 3711            return;
 3712        }
 3713
 3714        self.buffer.update(cx, |buffer, cx| {
 3715            buffer.edit(
 3716                edits,
 3717                Some(AutoindentMode::Block {
 3718                    original_indent_columns,
 3719                }),
 3720                cx,
 3721            )
 3722        });
 3723    }
 3724
 3725    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3726        self.hide_context_menu(window, cx);
 3727
 3728        match phase {
 3729            SelectPhase::Begin {
 3730                position,
 3731                add,
 3732                click_count,
 3733            } => self.begin_selection(position, add, click_count, window, cx),
 3734            SelectPhase::BeginColumnar {
 3735                position,
 3736                goal_column,
 3737                reset,
 3738                mode,
 3739            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3740            SelectPhase::Extend {
 3741                position,
 3742                click_count,
 3743            } => self.extend_selection(position, click_count, window, cx),
 3744            SelectPhase::Update {
 3745                position,
 3746                goal_column,
 3747                scroll_delta,
 3748            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3749            SelectPhase::End => self.end_selection(window, cx),
 3750        }
 3751    }
 3752
 3753    fn extend_selection(
 3754        &mut self,
 3755        position: DisplayPoint,
 3756        click_count: usize,
 3757        window: &mut Window,
 3758        cx: &mut Context<Self>,
 3759    ) {
 3760        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3761        let tail = self
 3762            .selections
 3763            .newest::<MultiBufferOffset>(&display_map)
 3764            .tail();
 3765        let click_count = click_count.max(match self.selections.select_mode() {
 3766            SelectMode::Character => 1,
 3767            SelectMode::Word(_) => 2,
 3768            SelectMode::Line(_) => 3,
 3769            SelectMode::All => 4,
 3770        });
 3771        self.begin_selection(position, false, click_count, window, cx);
 3772
 3773        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3774
 3775        let current_selection = match self.selections.select_mode() {
 3776            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3777            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3778        };
 3779
 3780        let mut pending_selection = self
 3781            .selections
 3782            .pending_anchor()
 3783            .cloned()
 3784            .expect("extend_selection not called with pending selection");
 3785
 3786        if pending_selection
 3787            .start
 3788            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3789            == Ordering::Greater
 3790        {
 3791            pending_selection.start = current_selection.start;
 3792        }
 3793        if pending_selection
 3794            .end
 3795            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3796            == Ordering::Less
 3797        {
 3798            pending_selection.end = current_selection.end;
 3799            pending_selection.reversed = true;
 3800        }
 3801
 3802        let mut pending_mode = self.selections.pending_mode().unwrap();
 3803        match &mut pending_mode {
 3804            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3805            _ => {}
 3806        }
 3807
 3808        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3809            SelectionEffects::scroll(Autoscroll::fit())
 3810        } else {
 3811            SelectionEffects::no_scroll()
 3812        };
 3813
 3814        self.change_selections(effects, window, cx, |s| {
 3815            s.set_pending(pending_selection.clone(), pending_mode);
 3816            s.set_is_extending(true);
 3817        });
 3818    }
 3819
 3820    fn begin_selection(
 3821        &mut self,
 3822        position: DisplayPoint,
 3823        add: bool,
 3824        click_count: usize,
 3825        window: &mut Window,
 3826        cx: &mut Context<Self>,
 3827    ) {
 3828        if !self.focus_handle.is_focused(window) {
 3829            self.last_focused_descendant = None;
 3830            window.focus(&self.focus_handle);
 3831        }
 3832
 3833        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3834        let buffer = display_map.buffer_snapshot();
 3835        let position = display_map.clip_point(position, Bias::Left);
 3836
 3837        let start;
 3838        let end;
 3839        let mode;
 3840        let mut auto_scroll;
 3841        match click_count {
 3842            1 => {
 3843                start = buffer.anchor_before(position.to_point(&display_map));
 3844                end = start;
 3845                mode = SelectMode::Character;
 3846                auto_scroll = true;
 3847            }
 3848            2 => {
 3849                let position = display_map
 3850                    .clip_point(position, Bias::Left)
 3851                    .to_offset(&display_map, Bias::Left);
 3852                let (range, _) = buffer.surrounding_word(position, None);
 3853                start = buffer.anchor_before(range.start);
 3854                end = buffer.anchor_before(range.end);
 3855                mode = SelectMode::Word(start..end);
 3856                auto_scroll = true;
 3857            }
 3858            3 => {
 3859                let position = display_map
 3860                    .clip_point(position, Bias::Left)
 3861                    .to_point(&display_map);
 3862                let line_start = display_map.prev_line_boundary(position).0;
 3863                let next_line_start = buffer.clip_point(
 3864                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3865                    Bias::Left,
 3866                );
 3867                start = buffer.anchor_before(line_start);
 3868                end = buffer.anchor_before(next_line_start);
 3869                mode = SelectMode::Line(start..end);
 3870                auto_scroll = true;
 3871            }
 3872            _ => {
 3873                start = buffer.anchor_before(MultiBufferOffset(0));
 3874                end = buffer.anchor_before(buffer.len());
 3875                mode = SelectMode::All;
 3876                auto_scroll = false;
 3877            }
 3878        }
 3879        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3880
 3881        let point_to_delete: Option<usize> = {
 3882            let selected_points: Vec<Selection<Point>> =
 3883                self.selections.disjoint_in_range(start..end, &display_map);
 3884
 3885            if !add || click_count > 1 {
 3886                None
 3887            } else if !selected_points.is_empty() {
 3888                Some(selected_points[0].id)
 3889            } else {
 3890                let clicked_point_already_selected =
 3891                    self.selections.disjoint_anchors().iter().find(|selection| {
 3892                        selection.start.to_point(buffer) == start.to_point(buffer)
 3893                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3894                    });
 3895
 3896                clicked_point_already_selected.map(|selection| selection.id)
 3897            }
 3898        };
 3899
 3900        let selections_count = self.selections.count();
 3901        let effects = if auto_scroll {
 3902            SelectionEffects::default()
 3903        } else {
 3904            SelectionEffects::no_scroll()
 3905        };
 3906
 3907        self.change_selections(effects, window, cx, |s| {
 3908            if let Some(point_to_delete) = point_to_delete {
 3909                s.delete(point_to_delete);
 3910
 3911                if selections_count == 1 {
 3912                    s.set_pending_anchor_range(start..end, mode);
 3913                }
 3914            } else {
 3915                if !add {
 3916                    s.clear_disjoint();
 3917                }
 3918
 3919                s.set_pending_anchor_range(start..end, mode);
 3920            }
 3921        });
 3922    }
 3923
 3924    fn begin_columnar_selection(
 3925        &mut self,
 3926        position: DisplayPoint,
 3927        goal_column: u32,
 3928        reset: bool,
 3929        mode: ColumnarMode,
 3930        window: &mut Window,
 3931        cx: &mut Context<Self>,
 3932    ) {
 3933        if !self.focus_handle.is_focused(window) {
 3934            self.last_focused_descendant = None;
 3935            window.focus(&self.focus_handle);
 3936        }
 3937
 3938        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3939
 3940        if reset {
 3941            let pointer_position = display_map
 3942                .buffer_snapshot()
 3943                .anchor_before(position.to_point(&display_map));
 3944
 3945            self.change_selections(
 3946                SelectionEffects::scroll(Autoscroll::newest()),
 3947                window,
 3948                cx,
 3949                |s| {
 3950                    s.clear_disjoint();
 3951                    s.set_pending_anchor_range(
 3952                        pointer_position..pointer_position,
 3953                        SelectMode::Character,
 3954                    );
 3955                },
 3956            );
 3957        };
 3958
 3959        let tail = self.selections.newest::<Point>(&display_map).tail();
 3960        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3961        self.columnar_selection_state = match mode {
 3962            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3963                selection_tail: selection_anchor,
 3964                display_point: if reset {
 3965                    if position.column() != goal_column {
 3966                        Some(DisplayPoint::new(position.row(), goal_column))
 3967                    } else {
 3968                        None
 3969                    }
 3970                } else {
 3971                    None
 3972                },
 3973            }),
 3974            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3975                selection_tail: selection_anchor,
 3976            }),
 3977        };
 3978
 3979        if !reset {
 3980            self.select_columns(position, goal_column, &display_map, window, cx);
 3981        }
 3982    }
 3983
 3984    fn update_selection(
 3985        &mut self,
 3986        position: DisplayPoint,
 3987        goal_column: u32,
 3988        scroll_delta: gpui::Point<f32>,
 3989        window: &mut Window,
 3990        cx: &mut Context<Self>,
 3991    ) {
 3992        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3993
 3994        if self.columnar_selection_state.is_some() {
 3995            self.select_columns(position, goal_column, &display_map, window, cx);
 3996        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3997            let buffer = display_map.buffer_snapshot();
 3998            let head;
 3999            let tail;
 4000            let mode = self.selections.pending_mode().unwrap();
 4001            match &mode {
 4002                SelectMode::Character => {
 4003                    head = position.to_point(&display_map);
 4004                    tail = pending.tail().to_point(buffer);
 4005                }
 4006                SelectMode::Word(original_range) => {
 4007                    let offset = display_map
 4008                        .clip_point(position, Bias::Left)
 4009                        .to_offset(&display_map, Bias::Left);
 4010                    let original_range = original_range.to_offset(buffer);
 4011
 4012                    let head_offset = if buffer.is_inside_word(offset, None)
 4013                        || original_range.contains(&offset)
 4014                    {
 4015                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4016                        if word_range.start < original_range.start {
 4017                            word_range.start
 4018                        } else {
 4019                            word_range.end
 4020                        }
 4021                    } else {
 4022                        offset
 4023                    };
 4024
 4025                    head = head_offset.to_point(buffer);
 4026                    if head_offset <= original_range.start {
 4027                        tail = original_range.end.to_point(buffer);
 4028                    } else {
 4029                        tail = original_range.start.to_point(buffer);
 4030                    }
 4031                }
 4032                SelectMode::Line(original_range) => {
 4033                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4034
 4035                    let position = display_map
 4036                        .clip_point(position, Bias::Left)
 4037                        .to_point(&display_map);
 4038                    let line_start = display_map.prev_line_boundary(position).0;
 4039                    let next_line_start = buffer.clip_point(
 4040                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4041                        Bias::Left,
 4042                    );
 4043
 4044                    if line_start < original_range.start {
 4045                        head = line_start
 4046                    } else {
 4047                        head = next_line_start
 4048                    }
 4049
 4050                    if head <= original_range.start {
 4051                        tail = original_range.end;
 4052                    } else {
 4053                        tail = original_range.start;
 4054                    }
 4055                }
 4056                SelectMode::All => {
 4057                    return;
 4058                }
 4059            };
 4060
 4061            if head < tail {
 4062                pending.start = buffer.anchor_before(head);
 4063                pending.end = buffer.anchor_before(tail);
 4064                pending.reversed = true;
 4065            } else {
 4066                pending.start = buffer.anchor_before(tail);
 4067                pending.end = buffer.anchor_before(head);
 4068                pending.reversed = false;
 4069            }
 4070
 4071            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4072                s.set_pending(pending.clone(), mode);
 4073            });
 4074        } else {
 4075            log::error!("update_selection dispatched with no pending selection");
 4076            return;
 4077        }
 4078
 4079        self.apply_scroll_delta(scroll_delta, window, cx);
 4080        cx.notify();
 4081    }
 4082
 4083    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4084        self.columnar_selection_state.take();
 4085        if let Some(pending_mode) = self.selections.pending_mode() {
 4086            let selections = self
 4087                .selections
 4088                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4089            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4090                s.select(selections);
 4091                s.clear_pending();
 4092                if s.is_extending() {
 4093                    s.set_is_extending(false);
 4094                } else {
 4095                    s.set_select_mode(pending_mode);
 4096                }
 4097            });
 4098        }
 4099    }
 4100
 4101    fn select_columns(
 4102        &mut self,
 4103        head: DisplayPoint,
 4104        goal_column: u32,
 4105        display_map: &DisplaySnapshot,
 4106        window: &mut Window,
 4107        cx: &mut Context<Self>,
 4108    ) {
 4109        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4110            return;
 4111        };
 4112
 4113        let tail = match columnar_state {
 4114            ColumnarSelectionState::FromMouse {
 4115                selection_tail,
 4116                display_point,
 4117            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4118            ColumnarSelectionState::FromSelection { selection_tail } => {
 4119                selection_tail.to_display_point(display_map)
 4120            }
 4121        };
 4122
 4123        let start_row = cmp::min(tail.row(), head.row());
 4124        let end_row = cmp::max(tail.row(), head.row());
 4125        let start_column = cmp::min(tail.column(), goal_column);
 4126        let end_column = cmp::max(tail.column(), goal_column);
 4127        let reversed = start_column < tail.column();
 4128
 4129        let selection_ranges = (start_row.0..=end_row.0)
 4130            .map(DisplayRow)
 4131            .filter_map(|row| {
 4132                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4133                    || start_column <= display_map.line_len(row))
 4134                    && !display_map.is_block_line(row)
 4135                {
 4136                    let start = display_map
 4137                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4138                        .to_point(display_map);
 4139                    let end = display_map
 4140                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4141                        .to_point(display_map);
 4142                    if reversed {
 4143                        Some(end..start)
 4144                    } else {
 4145                        Some(start..end)
 4146                    }
 4147                } else {
 4148                    None
 4149                }
 4150            })
 4151            .collect::<Vec<_>>();
 4152        if selection_ranges.is_empty() {
 4153            return;
 4154        }
 4155
 4156        let ranges = match columnar_state {
 4157            ColumnarSelectionState::FromMouse { .. } => {
 4158                let mut non_empty_ranges = selection_ranges
 4159                    .iter()
 4160                    .filter(|selection_range| selection_range.start != selection_range.end)
 4161                    .peekable();
 4162                if non_empty_ranges.peek().is_some() {
 4163                    non_empty_ranges.cloned().collect()
 4164                } else {
 4165                    selection_ranges
 4166                }
 4167            }
 4168            _ => selection_ranges,
 4169        };
 4170
 4171        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4172            s.select_ranges(ranges);
 4173        });
 4174        cx.notify();
 4175    }
 4176
 4177    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4178        self.selections
 4179            .all_adjusted(snapshot)
 4180            .iter()
 4181            .any(|selection| !selection.is_empty())
 4182    }
 4183
 4184    pub fn has_pending_nonempty_selection(&self) -> bool {
 4185        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4186            Some(Selection { start, end, .. }) => start != end,
 4187            None => false,
 4188        };
 4189
 4190        pending_nonempty_selection
 4191            || (self.columnar_selection_state.is_some()
 4192                && self.selections.disjoint_anchors().len() > 1)
 4193    }
 4194
 4195    pub fn has_pending_selection(&self) -> bool {
 4196        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4197    }
 4198
 4199    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4200        self.selection_mark_mode = false;
 4201        self.selection_drag_state = SelectionDragState::None;
 4202
 4203        if self.dismiss_menus_and_popups(true, window, cx) {
 4204            cx.notify();
 4205            return;
 4206        }
 4207        if self.clear_expanded_diff_hunks(cx) {
 4208            cx.notify();
 4209            return;
 4210        }
 4211        if self.show_git_blame_gutter {
 4212            self.show_git_blame_gutter = false;
 4213            cx.notify();
 4214            return;
 4215        }
 4216
 4217        if self.mode.is_full()
 4218            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4219        {
 4220            cx.notify();
 4221            return;
 4222        }
 4223
 4224        cx.propagate();
 4225    }
 4226
 4227    pub fn dismiss_menus_and_popups(
 4228        &mut self,
 4229        is_user_requested: bool,
 4230        window: &mut Window,
 4231        cx: &mut Context<Self>,
 4232    ) -> bool {
 4233        let mut dismissed = false;
 4234
 4235        dismissed |= self.take_rename(false, window, cx).is_some();
 4236        dismissed |= self.hide_blame_popover(true, cx);
 4237        dismissed |= hide_hover(self, cx);
 4238        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4239        dismissed |= self.hide_context_menu(window, cx).is_some();
 4240        dismissed |= self.mouse_context_menu.take().is_some();
 4241        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4242        dismissed |= self.snippet_stack.pop().is_some();
 4243
 4244        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4245            self.dismiss_diagnostics(cx);
 4246            dismissed = true;
 4247        }
 4248
 4249        dismissed
 4250    }
 4251
 4252    fn linked_editing_ranges_for(
 4253        &self,
 4254        selection: Range<text::Anchor>,
 4255        cx: &App,
 4256    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4257        if self.linked_edit_ranges.is_empty() {
 4258            return None;
 4259        }
 4260        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4261            selection.end.buffer_id.and_then(|end_buffer_id| {
 4262                if selection.start.buffer_id != Some(end_buffer_id) {
 4263                    return None;
 4264                }
 4265                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4266                let snapshot = buffer.read(cx).snapshot();
 4267                self.linked_edit_ranges
 4268                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4269                    .map(|ranges| (ranges, snapshot, buffer))
 4270            })?;
 4271        use text::ToOffset as TO;
 4272        // find offset from the start of current range to current cursor position
 4273        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4274
 4275        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4276        let start_difference = start_offset - start_byte_offset;
 4277        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4278        let end_difference = end_offset - start_byte_offset;
 4279        // Current range has associated linked ranges.
 4280        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4281        for range in linked_ranges.iter() {
 4282            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4283            let end_offset = start_offset + end_difference;
 4284            let start_offset = start_offset + start_difference;
 4285            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4286                continue;
 4287            }
 4288            if self.selections.disjoint_anchor_ranges().any(|s| {
 4289                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4290                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4291                {
 4292                    return false;
 4293                }
 4294                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4295                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4296            }) {
 4297                continue;
 4298            }
 4299            let start = buffer_snapshot.anchor_after(start_offset);
 4300            let end = buffer_snapshot.anchor_after(end_offset);
 4301            linked_edits
 4302                .entry(buffer.clone())
 4303                .or_default()
 4304                .push(start..end);
 4305        }
 4306        Some(linked_edits)
 4307    }
 4308
 4309    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4310        let text: Arc<str> = text.into();
 4311
 4312        if self.read_only(cx) {
 4313            return;
 4314        }
 4315
 4316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4317
 4318        self.unfold_buffers_with_selections(cx);
 4319
 4320        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4321        let mut bracket_inserted = false;
 4322        let mut edits = Vec::new();
 4323        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4324        let mut new_selections = Vec::with_capacity(selections.len());
 4325        let mut new_autoclose_regions = Vec::new();
 4326        let snapshot = self.buffer.read(cx).read(cx);
 4327        let mut clear_linked_edit_ranges = false;
 4328
 4329        for (selection, autoclose_region) in
 4330            self.selections_with_autoclose_regions(selections, &snapshot)
 4331        {
 4332            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4333                // Determine if the inserted text matches the opening or closing
 4334                // bracket of any of this language's bracket pairs.
 4335                let mut bracket_pair = None;
 4336                let mut is_bracket_pair_start = false;
 4337                let mut is_bracket_pair_end = false;
 4338                if !text.is_empty() {
 4339                    let mut bracket_pair_matching_end = None;
 4340                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4341                    //  and they are removing the character that triggered IME popup.
 4342                    for (pair, enabled) in scope.brackets() {
 4343                        if !pair.close && !pair.surround {
 4344                            continue;
 4345                        }
 4346
 4347                        if enabled && pair.start.ends_with(text.as_ref()) {
 4348                            let prefix_len = pair.start.len() - text.len();
 4349                            let preceding_text_matches_prefix = prefix_len == 0
 4350                                || (selection.start.column >= (prefix_len as u32)
 4351                                    && snapshot.contains_str_at(
 4352                                        Point::new(
 4353                                            selection.start.row,
 4354                                            selection.start.column - (prefix_len as u32),
 4355                                        ),
 4356                                        &pair.start[..prefix_len],
 4357                                    ));
 4358                            if preceding_text_matches_prefix {
 4359                                bracket_pair = Some(pair.clone());
 4360                                is_bracket_pair_start = true;
 4361                                break;
 4362                            }
 4363                        }
 4364                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4365                        {
 4366                            // take first bracket pair matching end, but don't break in case a later bracket
 4367                            // pair matches start
 4368                            bracket_pair_matching_end = Some(pair.clone());
 4369                        }
 4370                    }
 4371                    if let Some(end) = bracket_pair_matching_end
 4372                        && bracket_pair.is_none()
 4373                    {
 4374                        bracket_pair = Some(end);
 4375                        is_bracket_pair_end = true;
 4376                    }
 4377                }
 4378
 4379                if let Some(bracket_pair) = bracket_pair {
 4380                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4381                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4382                    let auto_surround =
 4383                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4384                    if selection.is_empty() {
 4385                        if is_bracket_pair_start {
 4386                            // If the inserted text is a suffix of an opening bracket and the
 4387                            // selection is preceded by the rest of the opening bracket, then
 4388                            // insert the closing bracket.
 4389                            let following_text_allows_autoclose = snapshot
 4390                                .chars_at(selection.start)
 4391                                .next()
 4392                                .is_none_or(|c| scope.should_autoclose_before(c));
 4393
 4394                            let preceding_text_allows_autoclose = selection.start.column == 0
 4395                                || snapshot
 4396                                    .reversed_chars_at(selection.start)
 4397                                    .next()
 4398                                    .is_none_or(|c| {
 4399                                        bracket_pair.start != bracket_pair.end
 4400                                            || !snapshot
 4401                                                .char_classifier_at(selection.start)
 4402                                                .is_word(c)
 4403                                    });
 4404
 4405                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4406                                && bracket_pair.start.len() == 1
 4407                            {
 4408                                let target = bracket_pair.start.chars().next().unwrap();
 4409                                let mut byte_offset = 0u32;
 4410                                let current_line_count = snapshot
 4411                                    .reversed_chars_at(selection.start)
 4412                                    .take_while(|&c| c != '\n')
 4413                                    .filter(|c| {
 4414                                        byte_offset += c.len_utf8() as u32;
 4415                                        if *c != target {
 4416                                            return false;
 4417                                        }
 4418
 4419                                        let point = Point::new(
 4420                                            selection.start.row,
 4421                                            selection.start.column.saturating_sub(byte_offset),
 4422                                        );
 4423
 4424                                        let is_enabled = snapshot
 4425                                            .language_scope_at(point)
 4426                                            .and_then(|scope| {
 4427                                                scope
 4428                                                    .brackets()
 4429                                                    .find(|(pair, _)| {
 4430                                                        pair.start == bracket_pair.start
 4431                                                    })
 4432                                                    .map(|(_, enabled)| enabled)
 4433                                            })
 4434                                            .unwrap_or(true);
 4435
 4436                                        let is_delimiter = snapshot
 4437                                            .language_scope_at(Point::new(
 4438                                                point.row,
 4439                                                point.column + 1,
 4440                                            ))
 4441                                            .and_then(|scope| {
 4442                                                scope
 4443                                                    .brackets()
 4444                                                    .find(|(pair, _)| {
 4445                                                        pair.start == bracket_pair.start
 4446                                                    })
 4447                                                    .map(|(_, enabled)| !enabled)
 4448                                            })
 4449                                            .unwrap_or(false);
 4450
 4451                                        is_enabled && !is_delimiter
 4452                                    })
 4453                                    .count();
 4454                                current_line_count % 2 == 1
 4455                            } else {
 4456                                false
 4457                            };
 4458
 4459                            if autoclose
 4460                                && bracket_pair.close
 4461                                && following_text_allows_autoclose
 4462                                && preceding_text_allows_autoclose
 4463                                && !is_closing_quote
 4464                            {
 4465                                let anchor = snapshot.anchor_before(selection.end);
 4466                                new_selections.push((selection.map(|_| anchor), text.len()));
 4467                                new_autoclose_regions.push((
 4468                                    anchor,
 4469                                    text.len(),
 4470                                    selection.id,
 4471                                    bracket_pair.clone(),
 4472                                ));
 4473                                edits.push((
 4474                                    selection.range(),
 4475                                    format!("{}{}", text, bracket_pair.end).into(),
 4476                                ));
 4477                                bracket_inserted = true;
 4478                                continue;
 4479                            }
 4480                        }
 4481
 4482                        if let Some(region) = autoclose_region {
 4483                            // If the selection is followed by an auto-inserted closing bracket,
 4484                            // then don't insert that closing bracket again; just move the selection
 4485                            // past the closing bracket.
 4486                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4487                                && text.as_ref() == region.pair.end.as_str()
 4488                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4489                            if should_skip {
 4490                                let anchor = snapshot.anchor_after(selection.end);
 4491                                new_selections
 4492                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4493                                continue;
 4494                            }
 4495                        }
 4496
 4497                        let always_treat_brackets_as_autoclosed = snapshot
 4498                            .language_settings_at(selection.start, cx)
 4499                            .always_treat_brackets_as_autoclosed;
 4500                        if always_treat_brackets_as_autoclosed
 4501                            && is_bracket_pair_end
 4502                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4503                        {
 4504                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4505                            // and the inserted text is a closing bracket and the selection is followed
 4506                            // by the closing bracket then move the selection past the closing bracket.
 4507                            let anchor = snapshot.anchor_after(selection.end);
 4508                            new_selections.push((selection.map(|_| anchor), text.len()));
 4509                            continue;
 4510                        }
 4511                    }
 4512                    // If an opening bracket is 1 character long and is typed while
 4513                    // text is selected, then surround that text with the bracket pair.
 4514                    else if auto_surround
 4515                        && bracket_pair.surround
 4516                        && is_bracket_pair_start
 4517                        && bracket_pair.start.chars().count() == 1
 4518                    {
 4519                        edits.push((selection.start..selection.start, text.clone()));
 4520                        edits.push((
 4521                            selection.end..selection.end,
 4522                            bracket_pair.end.as_str().into(),
 4523                        ));
 4524                        bracket_inserted = true;
 4525                        new_selections.push((
 4526                            Selection {
 4527                                id: selection.id,
 4528                                start: snapshot.anchor_after(selection.start),
 4529                                end: snapshot.anchor_before(selection.end),
 4530                                reversed: selection.reversed,
 4531                                goal: selection.goal,
 4532                            },
 4533                            0,
 4534                        ));
 4535                        continue;
 4536                    }
 4537                }
 4538            }
 4539
 4540            if self.auto_replace_emoji_shortcode
 4541                && selection.is_empty()
 4542                && text.as_ref().ends_with(':')
 4543                && let Some(possible_emoji_short_code) =
 4544                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4545                && !possible_emoji_short_code.is_empty()
 4546                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4547            {
 4548                let emoji_shortcode_start = Point::new(
 4549                    selection.start.row,
 4550                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4551                );
 4552
 4553                // Remove shortcode from buffer
 4554                edits.push((
 4555                    emoji_shortcode_start..selection.start,
 4556                    "".to_string().into(),
 4557                ));
 4558                new_selections.push((
 4559                    Selection {
 4560                        id: selection.id,
 4561                        start: snapshot.anchor_after(emoji_shortcode_start),
 4562                        end: snapshot.anchor_before(selection.start),
 4563                        reversed: selection.reversed,
 4564                        goal: selection.goal,
 4565                    },
 4566                    0,
 4567                ));
 4568
 4569                // Insert emoji
 4570                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4571                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4572                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4573
 4574                continue;
 4575            }
 4576
 4577            // If not handling any auto-close operation, then just replace the selected
 4578            // text with the given input and move the selection to the end of the
 4579            // newly inserted text.
 4580            let anchor = snapshot.anchor_after(selection.end);
 4581            if !self.linked_edit_ranges.is_empty() {
 4582                let start_anchor = snapshot.anchor_before(selection.start);
 4583
 4584                let is_word_char = text.chars().next().is_none_or(|char| {
 4585                    let classifier = snapshot
 4586                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4587                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4588                    classifier.is_word(char)
 4589                });
 4590
 4591                if is_word_char {
 4592                    if let Some(ranges) = self
 4593                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4594                    {
 4595                        for (buffer, edits) in ranges {
 4596                            linked_edits
 4597                                .entry(buffer.clone())
 4598                                .or_default()
 4599                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4600                        }
 4601                    }
 4602                } else {
 4603                    clear_linked_edit_ranges = true;
 4604                }
 4605            }
 4606
 4607            new_selections.push((selection.map(|_| anchor), 0));
 4608            edits.push((selection.start..selection.end, text.clone()));
 4609        }
 4610
 4611        drop(snapshot);
 4612
 4613        self.transact(window, cx, |this, window, cx| {
 4614            if clear_linked_edit_ranges {
 4615                this.linked_edit_ranges.clear();
 4616            }
 4617            let initial_buffer_versions =
 4618                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4619
 4620            this.buffer.update(cx, |buffer, cx| {
 4621                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4622            });
 4623            for (buffer, edits) in linked_edits {
 4624                buffer.update(cx, |buffer, cx| {
 4625                    let snapshot = buffer.snapshot();
 4626                    let edits = edits
 4627                        .into_iter()
 4628                        .map(|(range, text)| {
 4629                            use text::ToPoint as TP;
 4630                            let end_point = TP::to_point(&range.end, &snapshot);
 4631                            let start_point = TP::to_point(&range.start, &snapshot);
 4632                            (start_point..end_point, text)
 4633                        })
 4634                        .sorted_by_key(|(range, _)| range.start);
 4635                    buffer.edit(edits, None, cx);
 4636                })
 4637            }
 4638            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4639            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4640            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4641            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4642                new_anchor_selections,
 4643                &map,
 4644            )
 4645            .zip(new_selection_deltas)
 4646            .map(|(selection, delta)| Selection {
 4647                id: selection.id,
 4648                start: selection.start + delta,
 4649                end: selection.end + delta,
 4650                reversed: selection.reversed,
 4651                goal: SelectionGoal::None,
 4652            })
 4653            .collect::<Vec<_>>();
 4654
 4655            let mut i = 0;
 4656            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4657                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4658                let start = map.buffer_snapshot().anchor_before(position);
 4659                let end = map.buffer_snapshot().anchor_after(position);
 4660                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4661                    match existing_state
 4662                        .range
 4663                        .start
 4664                        .cmp(&start, map.buffer_snapshot())
 4665                    {
 4666                        Ordering::Less => i += 1,
 4667                        Ordering::Greater => break,
 4668                        Ordering::Equal => {
 4669                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4670                                Ordering::Less => i += 1,
 4671                                Ordering::Equal => break,
 4672                                Ordering::Greater => break,
 4673                            }
 4674                        }
 4675                    }
 4676                }
 4677                this.autoclose_regions.insert(
 4678                    i,
 4679                    AutocloseRegion {
 4680                        selection_id,
 4681                        range: start..end,
 4682                        pair,
 4683                    },
 4684                );
 4685            }
 4686
 4687            let had_active_edit_prediction = this.has_active_edit_prediction();
 4688            this.change_selections(
 4689                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4690                window,
 4691                cx,
 4692                |s| s.select(new_selections),
 4693            );
 4694
 4695            if !bracket_inserted
 4696                && let Some(on_type_format_task) =
 4697                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4698            {
 4699                on_type_format_task.detach_and_log_err(cx);
 4700            }
 4701
 4702            let editor_settings = EditorSettings::get_global(cx);
 4703            if bracket_inserted
 4704                && (editor_settings.auto_signature_help
 4705                    || editor_settings.show_signature_help_after_edits)
 4706            {
 4707                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4708            }
 4709
 4710            let trigger_in_words =
 4711                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4712            if this.hard_wrap.is_some() {
 4713                let latest: Range<Point> = this.selections.newest(&map).range();
 4714                if latest.is_empty()
 4715                    && this
 4716                        .buffer()
 4717                        .read(cx)
 4718                        .snapshot(cx)
 4719                        .line_len(MultiBufferRow(latest.start.row))
 4720                        == latest.start.column
 4721                {
 4722                    this.rewrap_impl(
 4723                        RewrapOptions {
 4724                            override_language_settings: true,
 4725                            preserve_existing_whitespace: true,
 4726                        },
 4727                        cx,
 4728                    )
 4729                }
 4730            }
 4731            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4732            refresh_linked_ranges(this, window, cx);
 4733            this.refresh_edit_prediction(true, false, window, cx);
 4734            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4735        });
 4736    }
 4737
 4738    fn find_possible_emoji_shortcode_at_position(
 4739        snapshot: &MultiBufferSnapshot,
 4740        position: Point,
 4741    ) -> Option<String> {
 4742        let mut chars = Vec::new();
 4743        let mut found_colon = false;
 4744        for char in snapshot.reversed_chars_at(position).take(100) {
 4745            // Found a possible emoji shortcode in the middle of the buffer
 4746            if found_colon {
 4747                if char.is_whitespace() {
 4748                    chars.reverse();
 4749                    return Some(chars.iter().collect());
 4750                }
 4751                // If the previous character is not a whitespace, we are in the middle of a word
 4752                // and we only want to complete the shortcode if the word is made up of other emojis
 4753                let mut containing_word = String::new();
 4754                for ch in snapshot
 4755                    .reversed_chars_at(position)
 4756                    .skip(chars.len() + 1)
 4757                    .take(100)
 4758                {
 4759                    if ch.is_whitespace() {
 4760                        break;
 4761                    }
 4762                    containing_word.push(ch);
 4763                }
 4764                let containing_word = containing_word.chars().rev().collect::<String>();
 4765                if util::word_consists_of_emojis(containing_word.as_str()) {
 4766                    chars.reverse();
 4767                    return Some(chars.iter().collect());
 4768                }
 4769            }
 4770
 4771            if char.is_whitespace() || !char.is_ascii() {
 4772                return None;
 4773            }
 4774            if char == ':' {
 4775                found_colon = true;
 4776            } else {
 4777                chars.push(char);
 4778            }
 4779        }
 4780        // Found a possible emoji shortcode at the beginning of the buffer
 4781        chars.reverse();
 4782        Some(chars.iter().collect())
 4783    }
 4784
 4785    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4787        self.transact(window, cx, |this, window, cx| {
 4788            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4789                let selections = this
 4790                    .selections
 4791                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4792                let multi_buffer = this.buffer.read(cx);
 4793                let buffer = multi_buffer.snapshot(cx);
 4794                selections
 4795                    .iter()
 4796                    .map(|selection| {
 4797                        let start_point = selection.start.to_point(&buffer);
 4798                        let mut existing_indent =
 4799                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4800                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4801                        let start = selection.start;
 4802                        let end = selection.end;
 4803                        let selection_is_empty = start == end;
 4804                        let language_scope = buffer.language_scope_at(start);
 4805                        let (
 4806                            comment_delimiter,
 4807                            doc_delimiter,
 4808                            insert_extra_newline,
 4809                            indent_on_newline,
 4810                            indent_on_extra_newline,
 4811                        ) = if let Some(language) = &language_scope {
 4812                            let mut insert_extra_newline =
 4813                                insert_extra_newline_brackets(&buffer, start..end, language)
 4814                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4815
 4816                            // Comment extension on newline is allowed only for cursor selections
 4817                            let comment_delimiter = maybe!({
 4818                                if !selection_is_empty {
 4819                                    return None;
 4820                                }
 4821
 4822                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4823                                    return None;
 4824                                }
 4825
 4826                                let delimiters = language.line_comment_prefixes();
 4827                                let max_len_of_delimiter =
 4828                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4829                                let (snapshot, range) =
 4830                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4831
 4832                                let num_of_whitespaces = snapshot
 4833                                    .chars_for_range(range.clone())
 4834                                    .take_while(|c| c.is_whitespace())
 4835                                    .count();
 4836                                let comment_candidate = snapshot
 4837                                    .chars_for_range(range.clone())
 4838                                    .skip(num_of_whitespaces)
 4839                                    .take(max_len_of_delimiter)
 4840                                    .collect::<String>();
 4841                                let (delimiter, trimmed_len) = delimiters
 4842                                    .iter()
 4843                                    .filter_map(|delimiter| {
 4844                                        let prefix = delimiter.trim_end();
 4845                                        if comment_candidate.starts_with(prefix) {
 4846                                            Some((delimiter, prefix.len()))
 4847                                        } else {
 4848                                            None
 4849                                        }
 4850                                    })
 4851                                    .max_by_key(|(_, len)| *len)?;
 4852
 4853                                if let Some(BlockCommentConfig {
 4854                                    start: block_start, ..
 4855                                }) = language.block_comment()
 4856                                {
 4857                                    let block_start_trimmed = block_start.trim_end();
 4858                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4859                                        let line_content = snapshot
 4860                                            .chars_for_range(range)
 4861                                            .skip(num_of_whitespaces)
 4862                                            .take(block_start_trimmed.len())
 4863                                            .collect::<String>();
 4864
 4865                                        if line_content.starts_with(block_start_trimmed) {
 4866                                            return None;
 4867                                        }
 4868                                    }
 4869                                }
 4870
 4871                                let cursor_is_placed_after_comment_marker =
 4872                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4873                                if cursor_is_placed_after_comment_marker {
 4874                                    Some(delimiter.clone())
 4875                                } else {
 4876                                    None
 4877                                }
 4878                            });
 4879
 4880                            let mut indent_on_newline = IndentSize::spaces(0);
 4881                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4882
 4883                            let doc_delimiter = maybe!({
 4884                                if !selection_is_empty {
 4885                                    return None;
 4886                                }
 4887
 4888                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4889                                    return None;
 4890                                }
 4891
 4892                                let BlockCommentConfig {
 4893                                    start: start_tag,
 4894                                    end: end_tag,
 4895                                    prefix: delimiter,
 4896                                    tab_size: len,
 4897                                } = language.documentation_comment()?;
 4898                                let is_within_block_comment = buffer
 4899                                    .language_scope_at(start_point)
 4900                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4901                                if !is_within_block_comment {
 4902                                    return None;
 4903                                }
 4904
 4905                                let (snapshot, range) =
 4906                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4907
 4908                                let num_of_whitespaces = snapshot
 4909                                    .chars_for_range(range.clone())
 4910                                    .take_while(|c| c.is_whitespace())
 4911                                    .count();
 4912
 4913                                // 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.
 4914                                let column = start_point.column;
 4915                                let cursor_is_after_start_tag = {
 4916                                    let start_tag_len = start_tag.len();
 4917                                    let start_tag_line = snapshot
 4918                                        .chars_for_range(range.clone())
 4919                                        .skip(num_of_whitespaces)
 4920                                        .take(start_tag_len)
 4921                                        .collect::<String>();
 4922                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4923                                        num_of_whitespaces + start_tag_len <= column as usize
 4924                                    } else {
 4925                                        false
 4926                                    }
 4927                                };
 4928
 4929                                let cursor_is_after_delimiter = {
 4930                                    let delimiter_trim = delimiter.trim_end();
 4931                                    let delimiter_line = snapshot
 4932                                        .chars_for_range(range.clone())
 4933                                        .skip(num_of_whitespaces)
 4934                                        .take(delimiter_trim.len())
 4935                                        .collect::<String>();
 4936                                    if delimiter_line.starts_with(delimiter_trim) {
 4937                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4938                                    } else {
 4939                                        false
 4940                                    }
 4941                                };
 4942
 4943                                let cursor_is_before_end_tag_if_exists = {
 4944                                    let mut char_position = 0u32;
 4945                                    let mut end_tag_offset = None;
 4946
 4947                                    'outer: for chunk in snapshot.text_for_range(range) {
 4948                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4949                                            let chars_before_match =
 4950                                                chunk[..byte_pos].chars().count() as u32;
 4951                                            end_tag_offset =
 4952                                                Some(char_position + chars_before_match);
 4953                                            break 'outer;
 4954                                        }
 4955                                        char_position += chunk.chars().count() as u32;
 4956                                    }
 4957
 4958                                    if let Some(end_tag_offset) = end_tag_offset {
 4959                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4960                                        if cursor_is_after_start_tag {
 4961                                            if cursor_is_before_end_tag {
 4962                                                insert_extra_newline = true;
 4963                                            }
 4964                                            let cursor_is_at_start_of_end_tag =
 4965                                                column == end_tag_offset;
 4966                                            if cursor_is_at_start_of_end_tag {
 4967                                                indent_on_extra_newline.len = *len;
 4968                                            }
 4969                                        }
 4970                                        cursor_is_before_end_tag
 4971                                    } else {
 4972                                        true
 4973                                    }
 4974                                };
 4975
 4976                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4977                                    && cursor_is_before_end_tag_if_exists
 4978                                {
 4979                                    if cursor_is_after_start_tag {
 4980                                        indent_on_newline.len = *len;
 4981                                    }
 4982                                    Some(delimiter.clone())
 4983                                } else {
 4984                                    None
 4985                                }
 4986                            });
 4987
 4988                            (
 4989                                comment_delimiter,
 4990                                doc_delimiter,
 4991                                insert_extra_newline,
 4992                                indent_on_newline,
 4993                                indent_on_extra_newline,
 4994                            )
 4995                        } else {
 4996                            (
 4997                                None,
 4998                                None,
 4999                                false,
 5000                                IndentSize::default(),
 5001                                IndentSize::default(),
 5002                            )
 5003                        };
 5004
 5005                        let prevent_auto_indent = doc_delimiter.is_some();
 5006                        let delimiter = comment_delimiter.or(doc_delimiter);
 5007
 5008                        let capacity_for_delimiter =
 5009                            delimiter.as_deref().map(str::len).unwrap_or_default();
 5010                        let mut new_text = String::with_capacity(
 5011                            1 + capacity_for_delimiter
 5012                                + existing_indent.len as usize
 5013                                + indent_on_newline.len as usize
 5014                                + indent_on_extra_newline.len as usize,
 5015                        );
 5016                        new_text.push('\n');
 5017                        new_text.extend(existing_indent.chars());
 5018                        new_text.extend(indent_on_newline.chars());
 5019
 5020                        if let Some(delimiter) = &delimiter {
 5021                            new_text.push_str(delimiter);
 5022                        }
 5023
 5024                        if insert_extra_newline {
 5025                            new_text.push('\n');
 5026                            new_text.extend(existing_indent.chars());
 5027                            new_text.extend(indent_on_extra_newline.chars());
 5028                        }
 5029
 5030                        let anchor = buffer.anchor_after(end);
 5031                        let new_selection = selection.map(|_| anchor);
 5032                        (
 5033                            ((start..end, new_text), prevent_auto_indent),
 5034                            (insert_extra_newline, new_selection),
 5035                        )
 5036                    })
 5037                    .unzip()
 5038            };
 5039
 5040            let mut auto_indent_edits = Vec::new();
 5041            let mut edits = Vec::new();
 5042            for (edit, prevent_auto_indent) in edits_with_flags {
 5043                if prevent_auto_indent {
 5044                    edits.push(edit);
 5045                } else {
 5046                    auto_indent_edits.push(edit);
 5047                }
 5048            }
 5049            if !edits.is_empty() {
 5050                this.edit(edits, cx);
 5051            }
 5052            if !auto_indent_edits.is_empty() {
 5053                this.edit_with_autoindent(auto_indent_edits, cx);
 5054            }
 5055
 5056            let buffer = this.buffer.read(cx).snapshot(cx);
 5057            let new_selections = selection_info
 5058                .into_iter()
 5059                .map(|(extra_newline_inserted, new_selection)| {
 5060                    let mut cursor = new_selection.end.to_point(&buffer);
 5061                    if extra_newline_inserted {
 5062                        cursor.row -= 1;
 5063                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5064                    }
 5065                    new_selection.map(|_| cursor)
 5066                })
 5067                .collect();
 5068
 5069            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5070            this.refresh_edit_prediction(true, false, window, cx);
 5071            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5072                task.detach_and_log_err(cx);
 5073            }
 5074        });
 5075    }
 5076
 5077    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5079
 5080        let buffer = self.buffer.read(cx);
 5081        let snapshot = buffer.snapshot(cx);
 5082
 5083        let mut edits = Vec::new();
 5084        let mut rows = Vec::new();
 5085
 5086        for (rows_inserted, selection) in self
 5087            .selections
 5088            .all_adjusted(&self.display_snapshot(cx))
 5089            .into_iter()
 5090            .enumerate()
 5091        {
 5092            let cursor = selection.head();
 5093            let row = cursor.row;
 5094
 5095            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5096
 5097            let newline = "\n".to_string();
 5098            edits.push((start_of_line..start_of_line, newline));
 5099
 5100            rows.push(row + rows_inserted as u32);
 5101        }
 5102
 5103        self.transact(window, cx, |editor, window, cx| {
 5104            editor.edit(edits, cx);
 5105
 5106            editor.change_selections(Default::default(), window, cx, |s| {
 5107                let mut index = 0;
 5108                s.move_cursors_with(|map, _, _| {
 5109                    let row = rows[index];
 5110                    index += 1;
 5111
 5112                    let point = Point::new(row, 0);
 5113                    let boundary = map.next_line_boundary(point).1;
 5114                    let clipped = map.clip_point(boundary, Bias::Left);
 5115
 5116                    (clipped, SelectionGoal::None)
 5117                });
 5118            });
 5119
 5120            let mut indent_edits = Vec::new();
 5121            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5122            for row in rows {
 5123                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5124                for (row, indent) in indents {
 5125                    if indent.len == 0 {
 5126                        continue;
 5127                    }
 5128
 5129                    let text = match indent.kind {
 5130                        IndentKind::Space => " ".repeat(indent.len as usize),
 5131                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5132                    };
 5133                    let point = Point::new(row.0, 0);
 5134                    indent_edits.push((point..point, text));
 5135                }
 5136            }
 5137            editor.edit(indent_edits, cx);
 5138            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5139                format.detach_and_log_err(cx);
 5140            }
 5141        });
 5142    }
 5143
 5144    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5146
 5147        let buffer = self.buffer.read(cx);
 5148        let snapshot = buffer.snapshot(cx);
 5149
 5150        let mut edits = Vec::new();
 5151        let mut rows = Vec::new();
 5152        let mut rows_inserted = 0;
 5153
 5154        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5155            let cursor = selection.head();
 5156            let row = cursor.row;
 5157
 5158            let point = Point::new(row + 1, 0);
 5159            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5160
 5161            let newline = "\n".to_string();
 5162            edits.push((start_of_line..start_of_line, newline));
 5163
 5164            rows_inserted += 1;
 5165            rows.push(row + rows_inserted);
 5166        }
 5167
 5168        self.transact(window, cx, |editor, window, cx| {
 5169            editor.edit(edits, cx);
 5170
 5171            editor.change_selections(Default::default(), window, cx, |s| {
 5172                let mut index = 0;
 5173                s.move_cursors_with(|map, _, _| {
 5174                    let row = rows[index];
 5175                    index += 1;
 5176
 5177                    let point = Point::new(row, 0);
 5178                    let boundary = map.next_line_boundary(point).1;
 5179                    let clipped = map.clip_point(boundary, Bias::Left);
 5180
 5181                    (clipped, SelectionGoal::None)
 5182                });
 5183            });
 5184
 5185            let mut indent_edits = Vec::new();
 5186            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5187            for row in rows {
 5188                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5189                for (row, indent) in indents {
 5190                    if indent.len == 0 {
 5191                        continue;
 5192                    }
 5193
 5194                    let text = match indent.kind {
 5195                        IndentKind::Space => " ".repeat(indent.len as usize),
 5196                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5197                    };
 5198                    let point = Point::new(row.0, 0);
 5199                    indent_edits.push((point..point, text));
 5200                }
 5201            }
 5202            editor.edit(indent_edits, cx);
 5203            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5204                format.detach_and_log_err(cx);
 5205            }
 5206        });
 5207    }
 5208
 5209    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5210        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5211            original_indent_columns: Vec::new(),
 5212        });
 5213        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5214    }
 5215
 5216    fn insert_with_autoindent_mode(
 5217        &mut self,
 5218        text: &str,
 5219        autoindent_mode: Option<AutoindentMode>,
 5220        window: &mut Window,
 5221        cx: &mut Context<Self>,
 5222    ) {
 5223        if self.read_only(cx) {
 5224            return;
 5225        }
 5226
 5227        let text: Arc<str> = text.into();
 5228        self.transact(window, cx, |this, window, cx| {
 5229            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5230            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5231                let anchors = {
 5232                    let snapshot = buffer.read(cx);
 5233                    old_selections
 5234                        .iter()
 5235                        .map(|s| {
 5236                            let anchor = snapshot.anchor_after(s.head());
 5237                            s.map(|_| anchor)
 5238                        })
 5239                        .collect::<Vec<_>>()
 5240                };
 5241                buffer.edit(
 5242                    old_selections
 5243                        .iter()
 5244                        .map(|s| (s.start..s.end, text.clone())),
 5245                    autoindent_mode,
 5246                    cx,
 5247                );
 5248                anchors
 5249            });
 5250
 5251            this.change_selections(Default::default(), window, cx, |s| {
 5252                s.select_anchors(selection_anchors);
 5253            });
 5254
 5255            cx.notify();
 5256        });
 5257    }
 5258
 5259    fn trigger_completion_on_input(
 5260        &mut self,
 5261        text: &str,
 5262        trigger_in_words: bool,
 5263        window: &mut Window,
 5264        cx: &mut Context<Self>,
 5265    ) {
 5266        let completions_source = self
 5267            .context_menu
 5268            .borrow()
 5269            .as_ref()
 5270            .and_then(|menu| match menu {
 5271                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5272                CodeContextMenu::CodeActions(_) => None,
 5273            });
 5274
 5275        match completions_source {
 5276            Some(CompletionsMenuSource::Words { .. }) => {
 5277                self.open_or_update_completions_menu(
 5278                    Some(CompletionsMenuSource::Words {
 5279                        ignore_threshold: false,
 5280                    }),
 5281                    None,
 5282                    trigger_in_words,
 5283                    window,
 5284                    cx,
 5285                );
 5286            }
 5287            _ => self.open_or_update_completions_menu(
 5288                None,
 5289                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5290                true,
 5291                window,
 5292                cx,
 5293            ),
 5294        }
 5295    }
 5296
 5297    /// If any empty selections is touching the start of its innermost containing autoclose
 5298    /// region, expand it to select the brackets.
 5299    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5300        let selections = self
 5301            .selections
 5302            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5303        let buffer = self.buffer.read(cx).read(cx);
 5304        let new_selections = self
 5305            .selections_with_autoclose_regions(selections, &buffer)
 5306            .map(|(mut selection, region)| {
 5307                if !selection.is_empty() {
 5308                    return selection;
 5309                }
 5310
 5311                if let Some(region) = region {
 5312                    let mut range = region.range.to_offset(&buffer);
 5313                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5314                        range.start -= region.pair.start.len();
 5315                        if buffer.contains_str_at(range.start, &region.pair.start)
 5316                            && buffer.contains_str_at(range.end, &region.pair.end)
 5317                        {
 5318                            range.end += region.pair.end.len();
 5319                            selection.start = range.start;
 5320                            selection.end = range.end;
 5321
 5322                            return selection;
 5323                        }
 5324                    }
 5325                }
 5326
 5327                let always_treat_brackets_as_autoclosed = buffer
 5328                    .language_settings_at(selection.start, cx)
 5329                    .always_treat_brackets_as_autoclosed;
 5330
 5331                if !always_treat_brackets_as_autoclosed {
 5332                    return selection;
 5333                }
 5334
 5335                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5336                    for (pair, enabled) in scope.brackets() {
 5337                        if !enabled || !pair.close {
 5338                            continue;
 5339                        }
 5340
 5341                        if buffer.contains_str_at(selection.start, &pair.end) {
 5342                            let pair_start_len = pair.start.len();
 5343                            if buffer.contains_str_at(
 5344                                selection.start.saturating_sub_usize(pair_start_len),
 5345                                &pair.start,
 5346                            ) {
 5347                                selection.start -= pair_start_len;
 5348                                selection.end += pair.end.len();
 5349
 5350                                return selection;
 5351                            }
 5352                        }
 5353                    }
 5354                }
 5355
 5356                selection
 5357            })
 5358            .collect();
 5359
 5360        drop(buffer);
 5361        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5362            selections.select(new_selections)
 5363        });
 5364    }
 5365
 5366    /// Iterate the given selections, and for each one, find the smallest surrounding
 5367    /// autoclose region. This uses the ordering of the selections and the autoclose
 5368    /// regions to avoid repeated comparisons.
 5369    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5370        &'a self,
 5371        selections: impl IntoIterator<Item = Selection<D>>,
 5372        buffer: &'a MultiBufferSnapshot,
 5373    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5374        let mut i = 0;
 5375        let mut regions = self.autoclose_regions.as_slice();
 5376        selections.into_iter().map(move |selection| {
 5377            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5378
 5379            let mut enclosing = None;
 5380            while let Some(pair_state) = regions.get(i) {
 5381                if pair_state.range.end.to_offset(buffer) < range.start {
 5382                    regions = &regions[i + 1..];
 5383                    i = 0;
 5384                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5385                    break;
 5386                } else {
 5387                    if pair_state.selection_id == selection.id {
 5388                        enclosing = Some(pair_state);
 5389                    }
 5390                    i += 1;
 5391                }
 5392            }
 5393
 5394            (selection, enclosing)
 5395        })
 5396    }
 5397
 5398    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5399    fn invalidate_autoclose_regions(
 5400        &mut self,
 5401        mut selections: &[Selection<Anchor>],
 5402        buffer: &MultiBufferSnapshot,
 5403    ) {
 5404        self.autoclose_regions.retain(|state| {
 5405            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5406                return false;
 5407            }
 5408
 5409            let mut i = 0;
 5410            while let Some(selection) = selections.get(i) {
 5411                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5412                    selections = &selections[1..];
 5413                    continue;
 5414                }
 5415                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5416                    break;
 5417                }
 5418                if selection.id == state.selection_id {
 5419                    return true;
 5420                } else {
 5421                    i += 1;
 5422                }
 5423            }
 5424            false
 5425        });
 5426    }
 5427
 5428    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5429        let offset = position.to_offset(buffer);
 5430        let (word_range, kind) =
 5431            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5432        if offset > word_range.start && kind == Some(CharKind::Word) {
 5433            Some(
 5434                buffer
 5435                    .text_for_range(word_range.start..offset)
 5436                    .collect::<String>(),
 5437            )
 5438        } else {
 5439            None
 5440        }
 5441    }
 5442
 5443    pub fn visible_excerpts(
 5444        &self,
 5445        lsp_related_only: bool,
 5446        cx: &mut Context<Editor>,
 5447    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5448        let project = self.project().cloned();
 5449        let multi_buffer = self.buffer().read(cx);
 5450        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5451        let multi_buffer_visible_start = self
 5452            .scroll_manager
 5453            .anchor()
 5454            .anchor
 5455            .to_point(&multi_buffer_snapshot);
 5456        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5457            multi_buffer_visible_start
 5458                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5459            Bias::Left,
 5460        );
 5461        multi_buffer_snapshot
 5462            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5463            .into_iter()
 5464            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5465            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5466                if !lsp_related_only {
 5467                    return Some((
 5468                        excerpt_id,
 5469                        (
 5470                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5471                            buffer.version().clone(),
 5472                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5473                        ),
 5474                    ));
 5475                }
 5476
 5477                let project = project.as_ref()?.read(cx);
 5478                let buffer_file = project::File::from_dyn(buffer.file())?;
 5479                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5480                let worktree_entry = buffer_worktree
 5481                    .read(cx)
 5482                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5483                if worktree_entry.is_ignored {
 5484                    None
 5485                } else {
 5486                    Some((
 5487                        excerpt_id,
 5488                        (
 5489                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5490                            buffer.version().clone(),
 5491                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5492                        ),
 5493                    ))
 5494                }
 5495            })
 5496            .collect()
 5497    }
 5498
 5499    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5500        TextLayoutDetails {
 5501            text_system: window.text_system().clone(),
 5502            editor_style: self.style.clone().unwrap(),
 5503            rem_size: window.rem_size(),
 5504            scroll_anchor: self.scroll_manager.anchor(),
 5505            visible_rows: self.visible_line_count(),
 5506            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5507        }
 5508    }
 5509
 5510    fn trigger_on_type_formatting(
 5511        &self,
 5512        input: String,
 5513        window: &mut Window,
 5514        cx: &mut Context<Self>,
 5515    ) -> Option<Task<Result<()>>> {
 5516        if input.chars().count() != 1 {
 5517            return None;
 5518        }
 5519
 5520        let project = self.project()?;
 5521        let position = self.selections.newest_anchor().head();
 5522        let (buffer, buffer_position) = self
 5523            .buffer
 5524            .read(cx)
 5525            .text_anchor_for_position(position, cx)?;
 5526
 5527        let settings = language_settings::language_settings(
 5528            buffer
 5529                .read(cx)
 5530                .language_at(buffer_position)
 5531                .map(|l| l.name()),
 5532            buffer.read(cx).file(),
 5533            cx,
 5534        );
 5535        if !settings.use_on_type_format {
 5536            return None;
 5537        }
 5538
 5539        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5540        // hence we do LSP request & edit on host side only — add formats to host's history.
 5541        let push_to_lsp_host_history = true;
 5542        // If this is not the host, append its history with new edits.
 5543        let push_to_client_history = project.read(cx).is_via_collab();
 5544
 5545        let on_type_formatting = project.update(cx, |project, cx| {
 5546            project.on_type_format(
 5547                buffer.clone(),
 5548                buffer_position,
 5549                input,
 5550                push_to_lsp_host_history,
 5551                cx,
 5552            )
 5553        });
 5554        Some(cx.spawn_in(window, async move |editor, cx| {
 5555            if let Some(transaction) = on_type_formatting.await? {
 5556                if push_to_client_history {
 5557                    buffer
 5558                        .update(cx, |buffer, _| {
 5559                            buffer.push_transaction(transaction, Instant::now());
 5560                            buffer.finalize_last_transaction();
 5561                        })
 5562                        .ok();
 5563                }
 5564                editor.update(cx, |editor, cx| {
 5565                    editor.refresh_document_highlights(cx);
 5566                })?;
 5567            }
 5568            Ok(())
 5569        }))
 5570    }
 5571
 5572    pub fn show_word_completions(
 5573        &mut self,
 5574        _: &ShowWordCompletions,
 5575        window: &mut Window,
 5576        cx: &mut Context<Self>,
 5577    ) {
 5578        self.open_or_update_completions_menu(
 5579            Some(CompletionsMenuSource::Words {
 5580                ignore_threshold: true,
 5581            }),
 5582            None,
 5583            false,
 5584            window,
 5585            cx,
 5586        );
 5587    }
 5588
 5589    pub fn show_completions(
 5590        &mut self,
 5591        _: &ShowCompletions,
 5592        window: &mut Window,
 5593        cx: &mut Context<Self>,
 5594    ) {
 5595        self.open_or_update_completions_menu(None, None, false, window, cx);
 5596    }
 5597
 5598    fn open_or_update_completions_menu(
 5599        &mut self,
 5600        requested_source: Option<CompletionsMenuSource>,
 5601        trigger: Option<String>,
 5602        trigger_in_words: bool,
 5603        window: &mut Window,
 5604        cx: &mut Context<Self>,
 5605    ) {
 5606        if self.pending_rename.is_some() {
 5607            return;
 5608        }
 5609
 5610        let completions_source = self
 5611            .context_menu
 5612            .borrow()
 5613            .as_ref()
 5614            .and_then(|menu| match menu {
 5615                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5616                CodeContextMenu::CodeActions(_) => None,
 5617            });
 5618
 5619        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5620
 5621        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5622        // inserted and selected. To handle that case, the start of the selection is used so that
 5623        // the menu starts with all choices.
 5624        let position = self
 5625            .selections
 5626            .newest_anchor()
 5627            .start
 5628            .bias_right(&multibuffer_snapshot);
 5629        if position.diff_base_anchor.is_some() {
 5630            return;
 5631        }
 5632        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5633        let Some(buffer) = buffer_position
 5634            .text_anchor
 5635            .buffer_id
 5636            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5637        else {
 5638            return;
 5639        };
 5640        let buffer_snapshot = buffer.read(cx).snapshot();
 5641
 5642        let menu_is_open = matches!(
 5643            self.context_menu.borrow().as_ref(),
 5644            Some(CodeContextMenu::Completions(_))
 5645        );
 5646
 5647        let language = buffer_snapshot
 5648            .language_at(buffer_position.text_anchor)
 5649            .map(|language| language.name());
 5650
 5651        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5652        let completion_settings = language_settings.completions.clone();
 5653
 5654        let show_completions_on_input = self
 5655            .show_completions_on_input_override
 5656            .unwrap_or(language_settings.show_completions_on_input);
 5657        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5658            return;
 5659        }
 5660
 5661        let query: Option<Arc<String>> =
 5662            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5663                .map(|query| query.into());
 5664
 5665        drop(multibuffer_snapshot);
 5666
 5667        // Hide the current completions menu when query is empty. Without this, cached
 5668        // completions from before the trigger char may be reused (#32774).
 5669        if query.is_none() && menu_is_open {
 5670            self.hide_context_menu(window, cx);
 5671        }
 5672
 5673        let mut ignore_word_threshold = false;
 5674        let provider = match requested_source {
 5675            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5676            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5677                ignore_word_threshold = ignore_threshold;
 5678                None
 5679            }
 5680            Some(CompletionsMenuSource::SnippetChoices)
 5681            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5682                log::error!("bug: SnippetChoices requested_source is not handled");
 5683                None
 5684            }
 5685        };
 5686
 5687        let sort_completions = provider
 5688            .as_ref()
 5689            .is_some_and(|provider| provider.sort_completions());
 5690
 5691        let filter_completions = provider
 5692            .as_ref()
 5693            .is_none_or(|provider| provider.filter_completions());
 5694
 5695        let was_snippets_only = matches!(
 5696            completions_source,
 5697            Some(CompletionsMenuSource::SnippetsOnly)
 5698        );
 5699
 5700        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5701            if filter_completions {
 5702                menu.filter(
 5703                    query.clone().unwrap_or_default(),
 5704                    buffer_position.text_anchor,
 5705                    &buffer,
 5706                    provider.clone(),
 5707                    window,
 5708                    cx,
 5709                );
 5710            }
 5711            // When `is_incomplete` is false, no need to re-query completions when the current query
 5712            // is a suffix of the initial query.
 5713            let was_complete = !menu.is_incomplete;
 5714            if was_complete && !was_snippets_only {
 5715                // If the new query is a suffix of the old query (typing more characters) and
 5716                // the previous result was complete, the existing completions can be filtered.
 5717                //
 5718                // Note that snippet completions are always complete.
 5719                let query_matches = match (&menu.initial_query, &query) {
 5720                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5721                    (None, _) => true,
 5722                    _ => false,
 5723                };
 5724                if query_matches {
 5725                    let position_matches = if menu.initial_position == position {
 5726                        true
 5727                    } else {
 5728                        let snapshot = self.buffer.read(cx).read(cx);
 5729                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5730                    };
 5731                    if position_matches {
 5732                        return;
 5733                    }
 5734                }
 5735            }
 5736        };
 5737
 5738        let Anchor {
 5739            excerpt_id: buffer_excerpt_id,
 5740            text_anchor: buffer_position,
 5741            ..
 5742        } = buffer_position;
 5743
 5744        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5745            buffer_snapshot.surrounding_word(buffer_position, None)
 5746        {
 5747            let word_to_exclude = buffer_snapshot
 5748                .text_for_range(word_range.clone())
 5749                .collect::<String>();
 5750            (
 5751                buffer_snapshot.anchor_before(word_range.start)
 5752                    ..buffer_snapshot.anchor_after(buffer_position),
 5753                Some(word_to_exclude),
 5754            )
 5755        } else {
 5756            (buffer_position..buffer_position, None)
 5757        };
 5758
 5759        let show_completion_documentation = buffer_snapshot
 5760            .settings_at(buffer_position, cx)
 5761            .show_completion_documentation;
 5762
 5763        // The document can be large, so stay in reasonable bounds when searching for words,
 5764        // otherwise completion pop-up might be slow to appear.
 5765        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5766        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5767        let min_word_search = buffer_snapshot.clip_point(
 5768            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5769            Bias::Left,
 5770        );
 5771        let max_word_search = buffer_snapshot.clip_point(
 5772            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5773            Bias::Right,
 5774        );
 5775        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5776            ..buffer_snapshot.point_to_offset(max_word_search);
 5777
 5778        let skip_digits = query
 5779            .as_ref()
 5780            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5781
 5782        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5783            trigger.as_ref().is_none_or(|trigger| {
 5784                provider.is_completion_trigger(
 5785                    &buffer,
 5786                    position.text_anchor,
 5787                    trigger,
 5788                    trigger_in_words,
 5789                    cx,
 5790                )
 5791            })
 5792        });
 5793
 5794        let provider_responses = if let Some(provider) = &provider
 5795            && load_provider_completions
 5796        {
 5797            let trigger_character =
 5798                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5799            let completion_context = CompletionContext {
 5800                trigger_kind: match &trigger_character {
 5801                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5802                    None => CompletionTriggerKind::INVOKED,
 5803                },
 5804                trigger_character,
 5805            };
 5806
 5807            provider.completions(
 5808                buffer_excerpt_id,
 5809                &buffer,
 5810                buffer_position,
 5811                completion_context,
 5812                window,
 5813                cx,
 5814            )
 5815        } else {
 5816            Task::ready(Ok(Vec::new()))
 5817        };
 5818
 5819        let load_word_completions = if !self.word_completions_enabled {
 5820            false
 5821        } else if requested_source
 5822            == Some(CompletionsMenuSource::Words {
 5823                ignore_threshold: true,
 5824            })
 5825        {
 5826            true
 5827        } else {
 5828            load_provider_completions
 5829                && completion_settings.words != WordsCompletionMode::Disabled
 5830                && (ignore_word_threshold || {
 5831                    let words_min_length = completion_settings.words_min_length;
 5832                    // check whether word has at least `words_min_length` characters
 5833                    let query_chars = query.iter().flat_map(|q| q.chars());
 5834                    query_chars.take(words_min_length).count() == words_min_length
 5835                })
 5836        };
 5837
 5838        let mut words = if load_word_completions {
 5839            cx.background_spawn({
 5840                let buffer_snapshot = buffer_snapshot.clone();
 5841                async move {
 5842                    buffer_snapshot.words_in_range(WordsQuery {
 5843                        fuzzy_contents: None,
 5844                        range: word_search_range,
 5845                        skip_digits,
 5846                    })
 5847                }
 5848            })
 5849        } else {
 5850            Task::ready(BTreeMap::default())
 5851        };
 5852
 5853        let snippets = if let Some(provider) = &provider
 5854            && provider.show_snippets()
 5855            && let Some(project) = self.project()
 5856        {
 5857            let char_classifier = buffer_snapshot
 5858                .char_classifier_at(buffer_position)
 5859                .scope_context(Some(CharScopeContext::Completion));
 5860            project.update(cx, |project, cx| {
 5861                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5862            })
 5863        } else {
 5864            Task::ready(Ok(CompletionResponse {
 5865                completions: Vec::new(),
 5866                display_options: Default::default(),
 5867                is_incomplete: false,
 5868            }))
 5869        };
 5870
 5871        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5872
 5873        let id = post_inc(&mut self.next_completion_id);
 5874        let task = cx.spawn_in(window, async move |editor, cx| {
 5875            let Ok(()) = editor.update(cx, |this, _| {
 5876                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5877            }) else {
 5878                return;
 5879            };
 5880
 5881            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5882            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5883            let mut completions = Vec::new();
 5884            let mut is_incomplete = false;
 5885            let mut display_options: Option<CompletionDisplayOptions> = None;
 5886            if let Some(provider_responses) = provider_responses.await.log_err()
 5887                && !provider_responses.is_empty()
 5888            {
 5889                for response in provider_responses {
 5890                    completions.extend(response.completions);
 5891                    is_incomplete = is_incomplete || response.is_incomplete;
 5892                    match display_options.as_mut() {
 5893                        None => {
 5894                            display_options = Some(response.display_options);
 5895                        }
 5896                        Some(options) => options.merge(&response.display_options),
 5897                    }
 5898                }
 5899                if completion_settings.words == WordsCompletionMode::Fallback {
 5900                    words = Task::ready(BTreeMap::default());
 5901                }
 5902            }
 5903            let display_options = display_options.unwrap_or_default();
 5904
 5905            let mut words = words.await;
 5906            if let Some(word_to_exclude) = &word_to_exclude {
 5907                words.remove(word_to_exclude);
 5908            }
 5909            for lsp_completion in &completions {
 5910                words.remove(&lsp_completion.new_text);
 5911            }
 5912            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5913                replace_range: word_replace_range.clone(),
 5914                new_text: word.clone(),
 5915                label: CodeLabel::plain(word, None),
 5916                match_start: None,
 5917                snippet_deduplication_key: None,
 5918                icon_path: None,
 5919                documentation: None,
 5920                source: CompletionSource::BufferWord {
 5921                    word_range,
 5922                    resolved: false,
 5923                },
 5924                insert_text_mode: Some(InsertTextMode::AS_IS),
 5925                confirm: None,
 5926            }));
 5927
 5928            completions.extend(
 5929                snippets
 5930                    .await
 5931                    .into_iter()
 5932                    .flat_map(|response| response.completions),
 5933            );
 5934
 5935            let menu = if completions.is_empty() {
 5936                None
 5937            } else {
 5938                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5939                    let languages = editor
 5940                        .workspace
 5941                        .as_ref()
 5942                        .and_then(|(workspace, _)| workspace.upgrade())
 5943                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5944                    let menu = CompletionsMenu::new(
 5945                        id,
 5946                        requested_source.unwrap_or(if load_provider_completions {
 5947                            CompletionsMenuSource::Normal
 5948                        } else {
 5949                            CompletionsMenuSource::SnippetsOnly
 5950                        }),
 5951                        sort_completions,
 5952                        show_completion_documentation,
 5953                        position,
 5954                        query.clone(),
 5955                        is_incomplete,
 5956                        buffer.clone(),
 5957                        completions.into(),
 5958                        editor
 5959                            .context_menu()
 5960                            .borrow_mut()
 5961                            .as_ref()
 5962                            .map(|menu| menu.primary_scroll_handle()),
 5963                        display_options,
 5964                        snippet_sort_order,
 5965                        languages,
 5966                        language,
 5967                        cx,
 5968                    );
 5969
 5970                    let query = if filter_completions { query } else { None };
 5971                    let matches_task = menu.do_async_filtering(
 5972                        query.unwrap_or_default(),
 5973                        buffer_position,
 5974                        &buffer,
 5975                        cx,
 5976                    );
 5977                    (menu, matches_task)
 5978                }) else {
 5979                    return;
 5980                };
 5981
 5982                let matches = matches_task.await;
 5983
 5984                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5985                    // Newer menu already set, so exit.
 5986                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5987                        editor.context_menu.borrow().as_ref()
 5988                        && prev_menu.id > id
 5989                    {
 5990                        return;
 5991                    };
 5992
 5993                    // Only valid to take prev_menu because either the new menu is immediately set
 5994                    // below, or the menu is hidden.
 5995                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5996                        editor.context_menu.borrow_mut().take()
 5997                    {
 5998                        let position_matches =
 5999                            if prev_menu.initial_position == menu.initial_position {
 6000                                true
 6001                            } else {
 6002                                let snapshot = editor.buffer.read(cx).read(cx);
 6003                                prev_menu.initial_position.to_offset(&snapshot)
 6004                                    == menu.initial_position.to_offset(&snapshot)
 6005                            };
 6006                        if position_matches {
 6007                            // Preserve markdown cache before `set_filter_results` because it will
 6008                            // try to populate the documentation cache.
 6009                            menu.preserve_markdown_cache(prev_menu);
 6010                        }
 6011                    };
 6012
 6013                    menu.set_filter_results(matches, provider, window, cx);
 6014                }) else {
 6015                    return;
 6016                };
 6017
 6018                menu.visible().then_some(menu)
 6019            };
 6020
 6021            editor
 6022                .update_in(cx, |editor, window, cx| {
 6023                    if editor.focus_handle.is_focused(window)
 6024                        && let Some(menu) = menu
 6025                    {
 6026                        *editor.context_menu.borrow_mut() =
 6027                            Some(CodeContextMenu::Completions(menu));
 6028
 6029                        crate::hover_popover::hide_hover(editor, cx);
 6030                        if editor.show_edit_predictions_in_menu() {
 6031                            editor.update_visible_edit_prediction(window, cx);
 6032                        } else {
 6033                            editor.discard_edit_prediction(false, cx);
 6034                        }
 6035
 6036                        cx.notify();
 6037                        return;
 6038                    }
 6039
 6040                    if editor.completion_tasks.len() <= 1 {
 6041                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6042                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6043                        // If it was already hidden and we don't show edit predictions in the menu,
 6044                        // we should also show the edit prediction when available.
 6045                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6046                            editor.update_visible_edit_prediction(window, cx);
 6047                        }
 6048                    }
 6049                })
 6050                .ok();
 6051        });
 6052
 6053        self.completion_tasks.push((id, task));
 6054    }
 6055
 6056    #[cfg(feature = "test-support")]
 6057    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6058        let menu = self.context_menu.borrow();
 6059        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6060            let completions = menu.completions.borrow();
 6061            Some(completions.to_vec())
 6062        } else {
 6063            None
 6064        }
 6065    }
 6066
 6067    pub fn with_completions_menu_matching_id<R>(
 6068        &self,
 6069        id: CompletionId,
 6070        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6071    ) -> R {
 6072        let mut context_menu = self.context_menu.borrow_mut();
 6073        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6074            return f(None);
 6075        };
 6076        if completions_menu.id != id {
 6077            return f(None);
 6078        }
 6079        f(Some(completions_menu))
 6080    }
 6081
 6082    pub fn confirm_completion(
 6083        &mut self,
 6084        action: &ConfirmCompletion,
 6085        window: &mut Window,
 6086        cx: &mut Context<Self>,
 6087    ) -> Option<Task<Result<()>>> {
 6088        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6089        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6090    }
 6091
 6092    pub fn confirm_completion_insert(
 6093        &mut self,
 6094        _: &ConfirmCompletionInsert,
 6095        window: &mut Window,
 6096        cx: &mut Context<Self>,
 6097    ) -> Option<Task<Result<()>>> {
 6098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6099        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6100    }
 6101
 6102    pub fn confirm_completion_replace(
 6103        &mut self,
 6104        _: &ConfirmCompletionReplace,
 6105        window: &mut Window,
 6106        cx: &mut Context<Self>,
 6107    ) -> Option<Task<Result<()>>> {
 6108        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6109        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6110    }
 6111
 6112    pub fn compose_completion(
 6113        &mut self,
 6114        action: &ComposeCompletion,
 6115        window: &mut Window,
 6116        cx: &mut Context<Self>,
 6117    ) -> Option<Task<Result<()>>> {
 6118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6119        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6120    }
 6121
 6122    fn do_completion(
 6123        &mut self,
 6124        item_ix: Option<usize>,
 6125        intent: CompletionIntent,
 6126        window: &mut Window,
 6127        cx: &mut Context<Editor>,
 6128    ) -> Option<Task<Result<()>>> {
 6129        use language::ToOffset as _;
 6130
 6131        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6132        else {
 6133            return None;
 6134        };
 6135
 6136        let candidate_id = {
 6137            let entries = completions_menu.entries.borrow();
 6138            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6139            if self.show_edit_predictions_in_menu() {
 6140                self.discard_edit_prediction(true, cx);
 6141            }
 6142            mat.candidate_id
 6143        };
 6144
 6145        let completion = completions_menu
 6146            .completions
 6147            .borrow()
 6148            .get(candidate_id)?
 6149            .clone();
 6150        cx.stop_propagation();
 6151
 6152        let buffer_handle = completions_menu.buffer.clone();
 6153
 6154        let CompletionEdit {
 6155            new_text,
 6156            snippet,
 6157            replace_range,
 6158        } = process_completion_for_edit(
 6159            &completion,
 6160            intent,
 6161            &buffer_handle,
 6162            &completions_menu.initial_position.text_anchor,
 6163            cx,
 6164        );
 6165
 6166        let buffer = buffer_handle.read(cx);
 6167        let snapshot = self.buffer.read(cx).snapshot(cx);
 6168        let newest_anchor = self.selections.newest_anchor();
 6169        let replace_range_multibuffer = {
 6170            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6171            excerpt.map_range_from_buffer(replace_range.clone())
 6172        };
 6173        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6174            return None;
 6175        }
 6176
 6177        let old_text = buffer
 6178            .text_for_range(replace_range.clone())
 6179            .collect::<String>();
 6180        let lookbehind = newest_anchor
 6181            .start
 6182            .text_anchor
 6183            .to_offset(buffer)
 6184            .saturating_sub(replace_range.start.0);
 6185        let lookahead = replace_range
 6186            .end
 6187            .0
 6188            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6189        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6190        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6191
 6192        let selections = self
 6193            .selections
 6194            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6195        let mut ranges = Vec::new();
 6196        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6197
 6198        for selection in &selections {
 6199            let range = if selection.id == newest_anchor.id {
 6200                replace_range_multibuffer.clone()
 6201            } else {
 6202                let mut range = selection.range();
 6203
 6204                // if prefix is present, don't duplicate it
 6205                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6206                    range.start = range.start.saturating_sub_usize(lookbehind);
 6207
 6208                    // if suffix is also present, mimic the newest cursor and replace it
 6209                    if selection.id != newest_anchor.id
 6210                        && snapshot.contains_str_at(range.end, suffix)
 6211                    {
 6212                        range.end += lookahead;
 6213                    }
 6214                }
 6215                range
 6216            };
 6217
 6218            ranges.push(range.clone());
 6219
 6220            if !self.linked_edit_ranges.is_empty() {
 6221                let start_anchor = snapshot.anchor_before(range.start);
 6222                let end_anchor = snapshot.anchor_after(range.end);
 6223                if let Some(ranges) = self
 6224                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6225                {
 6226                    for (buffer, edits) in ranges {
 6227                        linked_edits
 6228                            .entry(buffer.clone())
 6229                            .or_default()
 6230                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6231                    }
 6232                }
 6233            }
 6234        }
 6235
 6236        let common_prefix_len = old_text
 6237            .chars()
 6238            .zip(new_text.chars())
 6239            .take_while(|(a, b)| a == b)
 6240            .map(|(a, _)| a.len_utf8())
 6241            .sum::<usize>();
 6242
 6243        cx.emit(EditorEvent::InputHandled {
 6244            utf16_range_to_replace: None,
 6245            text: new_text[common_prefix_len..].into(),
 6246        });
 6247
 6248        self.transact(window, cx, |editor, window, cx| {
 6249            if let Some(mut snippet) = snippet {
 6250                snippet.text = new_text.to_string();
 6251                editor
 6252                    .insert_snippet(&ranges, snippet, window, cx)
 6253                    .log_err();
 6254            } else {
 6255                editor.buffer.update(cx, |multi_buffer, cx| {
 6256                    let auto_indent = match completion.insert_text_mode {
 6257                        Some(InsertTextMode::AS_IS) => None,
 6258                        _ => editor.autoindent_mode.clone(),
 6259                    };
 6260                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6261                    multi_buffer.edit(edits, auto_indent, cx);
 6262                });
 6263            }
 6264            for (buffer, edits) in linked_edits {
 6265                buffer.update(cx, |buffer, cx| {
 6266                    let snapshot = buffer.snapshot();
 6267                    let edits = edits
 6268                        .into_iter()
 6269                        .map(|(range, text)| {
 6270                            use text::ToPoint as TP;
 6271                            let end_point = TP::to_point(&range.end, &snapshot);
 6272                            let start_point = TP::to_point(&range.start, &snapshot);
 6273                            (start_point..end_point, text)
 6274                        })
 6275                        .sorted_by_key(|(range, _)| range.start);
 6276                    buffer.edit(edits, None, cx);
 6277                })
 6278            }
 6279
 6280            editor.refresh_edit_prediction(true, false, window, cx);
 6281        });
 6282        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6283
 6284        let show_new_completions_on_confirm = completion
 6285            .confirm
 6286            .as_ref()
 6287            .is_some_and(|confirm| confirm(intent, window, cx));
 6288        if show_new_completions_on_confirm {
 6289            self.open_or_update_completions_menu(None, None, false, window, cx);
 6290        }
 6291
 6292        let provider = self.completion_provider.as_ref()?;
 6293
 6294        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6295        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6296            let CompletionSource::Lsp {
 6297                lsp_completion,
 6298                server_id,
 6299                ..
 6300            } = &completion.source
 6301            else {
 6302                return None;
 6303            };
 6304            let lsp_command = lsp_completion.command.as_ref()?;
 6305            let available_commands = lsp_store
 6306                .read(cx)
 6307                .lsp_server_capabilities
 6308                .get(server_id)
 6309                .and_then(|server_capabilities| {
 6310                    server_capabilities
 6311                        .execute_command_provider
 6312                        .as_ref()
 6313                        .map(|options| options.commands.as_slice())
 6314                })?;
 6315            if available_commands.contains(&lsp_command.command) {
 6316                Some(CodeAction {
 6317                    server_id: *server_id,
 6318                    range: language::Anchor::MIN..language::Anchor::MIN,
 6319                    lsp_action: LspAction::Command(lsp_command.clone()),
 6320                    resolved: false,
 6321                })
 6322            } else {
 6323                None
 6324            }
 6325        });
 6326
 6327        drop(completion);
 6328        let apply_edits = provider.apply_additional_edits_for_completion(
 6329            buffer_handle.clone(),
 6330            completions_menu.completions.clone(),
 6331            candidate_id,
 6332            true,
 6333            cx,
 6334        );
 6335
 6336        let editor_settings = EditorSettings::get_global(cx);
 6337        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6338            // After the code completion is finished, users often want to know what signatures are needed.
 6339            // so we should automatically call signature_help
 6340            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6341        }
 6342
 6343        Some(cx.spawn_in(window, async move |editor, cx| {
 6344            apply_edits.await?;
 6345
 6346            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6347                let title = command.lsp_action.title().to_owned();
 6348                let project_transaction = lsp_store
 6349                    .update(cx, |lsp_store, cx| {
 6350                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6351                    })?
 6352                    .await
 6353                    .context("applying post-completion command")?;
 6354                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6355                    Self::open_project_transaction(
 6356                        &editor,
 6357                        workspace.downgrade(),
 6358                        project_transaction,
 6359                        title,
 6360                        cx,
 6361                    )
 6362                    .await?;
 6363                }
 6364            }
 6365
 6366            Ok(())
 6367        }))
 6368    }
 6369
 6370    pub fn toggle_code_actions(
 6371        &mut self,
 6372        action: &ToggleCodeActions,
 6373        window: &mut Window,
 6374        cx: &mut Context<Self>,
 6375    ) {
 6376        let quick_launch = action.quick_launch;
 6377        let mut context_menu = self.context_menu.borrow_mut();
 6378        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6379            if code_actions.deployed_from == action.deployed_from {
 6380                // Toggle if we're selecting the same one
 6381                *context_menu = None;
 6382                cx.notify();
 6383                return;
 6384            } else {
 6385                // Otherwise, clear it and start a new one
 6386                *context_menu = None;
 6387                cx.notify();
 6388            }
 6389        }
 6390        drop(context_menu);
 6391        let snapshot = self.snapshot(window, cx);
 6392        let deployed_from = action.deployed_from.clone();
 6393        let action = action.clone();
 6394        self.completion_tasks.clear();
 6395        self.discard_edit_prediction(false, cx);
 6396
 6397        let multibuffer_point = match &action.deployed_from {
 6398            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6399                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6400            }
 6401            _ => self
 6402                .selections
 6403                .newest::<Point>(&snapshot.display_snapshot)
 6404                .head(),
 6405        };
 6406        let Some((buffer, buffer_row)) = snapshot
 6407            .buffer_snapshot()
 6408            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6409            .and_then(|(buffer_snapshot, range)| {
 6410                self.buffer()
 6411                    .read(cx)
 6412                    .buffer(buffer_snapshot.remote_id())
 6413                    .map(|buffer| (buffer, range.start.row))
 6414            })
 6415        else {
 6416            return;
 6417        };
 6418        let buffer_id = buffer.read(cx).remote_id();
 6419        let tasks = self
 6420            .tasks
 6421            .get(&(buffer_id, buffer_row))
 6422            .map(|t| Arc::new(t.to_owned()));
 6423
 6424        if !self.focus_handle.is_focused(window) {
 6425            return;
 6426        }
 6427        let project = self.project.clone();
 6428
 6429        let code_actions_task = match deployed_from {
 6430            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6431            _ => self.code_actions(buffer_row, window, cx),
 6432        };
 6433
 6434        let runnable_task = match deployed_from {
 6435            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6436            _ => {
 6437                let mut task_context_task = Task::ready(None);
 6438                if let Some(tasks) = &tasks
 6439                    && let Some(project) = project
 6440                {
 6441                    task_context_task =
 6442                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6443                }
 6444
 6445                cx.spawn_in(window, {
 6446                    let buffer = buffer.clone();
 6447                    async move |editor, cx| {
 6448                        let task_context = task_context_task.await;
 6449
 6450                        let resolved_tasks =
 6451                            tasks
 6452                                .zip(task_context.clone())
 6453                                .map(|(tasks, task_context)| ResolvedTasks {
 6454                                    templates: tasks.resolve(&task_context).collect(),
 6455                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6456                                        multibuffer_point.row,
 6457                                        tasks.column,
 6458                                    )),
 6459                                });
 6460                        let debug_scenarios = editor
 6461                            .update(cx, |editor, cx| {
 6462                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6463                            })?
 6464                            .await;
 6465                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6466                    }
 6467                })
 6468            }
 6469        };
 6470
 6471        cx.spawn_in(window, async move |editor, cx| {
 6472            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6473            let code_actions = code_actions_task.await;
 6474            let spawn_straight_away = quick_launch
 6475                && resolved_tasks
 6476                    .as_ref()
 6477                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6478                && code_actions
 6479                    .as_ref()
 6480                    .is_none_or(|actions| actions.is_empty())
 6481                && debug_scenarios.is_empty();
 6482
 6483            editor.update_in(cx, |editor, window, cx| {
 6484                crate::hover_popover::hide_hover(editor, cx);
 6485                let actions = CodeActionContents::new(
 6486                    resolved_tasks,
 6487                    code_actions,
 6488                    debug_scenarios,
 6489                    task_context.unwrap_or_default(),
 6490                );
 6491
 6492                // Don't show the menu if there are no actions available
 6493                if actions.is_empty() {
 6494                    cx.notify();
 6495                    return Task::ready(Ok(()));
 6496                }
 6497
 6498                *editor.context_menu.borrow_mut() =
 6499                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6500                        buffer,
 6501                        actions,
 6502                        selected_item: Default::default(),
 6503                        scroll_handle: UniformListScrollHandle::default(),
 6504                        deployed_from,
 6505                    }));
 6506                cx.notify();
 6507                if spawn_straight_away
 6508                    && let Some(task) = editor.confirm_code_action(
 6509                        &ConfirmCodeAction { item_ix: Some(0) },
 6510                        window,
 6511                        cx,
 6512                    )
 6513                {
 6514                    return task;
 6515                }
 6516
 6517                Task::ready(Ok(()))
 6518            })
 6519        })
 6520        .detach_and_log_err(cx);
 6521    }
 6522
 6523    fn debug_scenarios(
 6524        &mut self,
 6525        resolved_tasks: &Option<ResolvedTasks>,
 6526        buffer: &Entity<Buffer>,
 6527        cx: &mut App,
 6528    ) -> Task<Vec<task::DebugScenario>> {
 6529        maybe!({
 6530            let project = self.project()?;
 6531            let dap_store = project.read(cx).dap_store();
 6532            let mut scenarios = vec![];
 6533            let resolved_tasks = resolved_tasks.as_ref()?;
 6534            let buffer = buffer.read(cx);
 6535            let language = buffer.language()?;
 6536            let file = buffer.file();
 6537            let debug_adapter = language_settings(language.name().into(), file, cx)
 6538                .debuggers
 6539                .first()
 6540                .map(SharedString::from)
 6541                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6542
 6543            dap_store.update(cx, |dap_store, cx| {
 6544                for (_, task) in &resolved_tasks.templates {
 6545                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6546                        task.original_task().clone(),
 6547                        debug_adapter.clone().into(),
 6548                        task.display_label().to_owned().into(),
 6549                        cx,
 6550                    );
 6551                    scenarios.push(maybe_scenario);
 6552                }
 6553            });
 6554            Some(cx.background_spawn(async move {
 6555                futures::future::join_all(scenarios)
 6556                    .await
 6557                    .into_iter()
 6558                    .flatten()
 6559                    .collect::<Vec<_>>()
 6560            }))
 6561        })
 6562        .unwrap_or_else(|| Task::ready(vec![]))
 6563    }
 6564
 6565    fn code_actions(
 6566        &mut self,
 6567        buffer_row: u32,
 6568        window: &mut Window,
 6569        cx: &mut Context<Self>,
 6570    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6571        let mut task = self.code_actions_task.take();
 6572        cx.spawn_in(window, async move |editor, cx| {
 6573            while let Some(prev_task) = task {
 6574                prev_task.await.log_err();
 6575                task = editor
 6576                    .update(cx, |this, _| this.code_actions_task.take())
 6577                    .ok()?;
 6578            }
 6579
 6580            editor
 6581                .update(cx, |editor, cx| {
 6582                    editor
 6583                        .available_code_actions
 6584                        .clone()
 6585                        .and_then(|(location, code_actions)| {
 6586                            let snapshot = location.buffer.read(cx).snapshot();
 6587                            let point_range = location.range.to_point(&snapshot);
 6588                            let point_range = point_range.start.row..=point_range.end.row;
 6589                            if point_range.contains(&buffer_row) {
 6590                                Some(code_actions)
 6591                            } else {
 6592                                None
 6593                            }
 6594                        })
 6595                })
 6596                .ok()
 6597                .flatten()
 6598        })
 6599    }
 6600
 6601    pub fn confirm_code_action(
 6602        &mut self,
 6603        action: &ConfirmCodeAction,
 6604        window: &mut Window,
 6605        cx: &mut Context<Self>,
 6606    ) -> Option<Task<Result<()>>> {
 6607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6608
 6609        let actions_menu =
 6610            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6611                menu
 6612            } else {
 6613                return None;
 6614            };
 6615
 6616        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6617        let action = actions_menu.actions.get(action_ix)?;
 6618        let title = action.label();
 6619        let buffer = actions_menu.buffer;
 6620        let workspace = self.workspace()?;
 6621
 6622        match action {
 6623            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6624                workspace.update(cx, |workspace, cx| {
 6625                    workspace.schedule_resolved_task(
 6626                        task_source_kind,
 6627                        resolved_task,
 6628                        false,
 6629                        window,
 6630                        cx,
 6631                    );
 6632
 6633                    Some(Task::ready(Ok(())))
 6634                })
 6635            }
 6636            CodeActionsItem::CodeAction {
 6637                excerpt_id,
 6638                action,
 6639                provider,
 6640            } => {
 6641                let apply_code_action =
 6642                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6643                let workspace = workspace.downgrade();
 6644                Some(cx.spawn_in(window, async move |editor, cx| {
 6645                    let project_transaction = apply_code_action.await?;
 6646                    Self::open_project_transaction(
 6647                        &editor,
 6648                        workspace,
 6649                        project_transaction,
 6650                        title,
 6651                        cx,
 6652                    )
 6653                    .await
 6654                }))
 6655            }
 6656            CodeActionsItem::DebugScenario(scenario) => {
 6657                let context = actions_menu.actions.context;
 6658
 6659                workspace.update(cx, |workspace, cx| {
 6660                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6661                    workspace.start_debug_session(
 6662                        scenario,
 6663                        context,
 6664                        Some(buffer),
 6665                        None,
 6666                        window,
 6667                        cx,
 6668                    );
 6669                });
 6670                Some(Task::ready(Ok(())))
 6671            }
 6672        }
 6673    }
 6674
 6675    pub async fn open_project_transaction(
 6676        editor: &WeakEntity<Editor>,
 6677        workspace: WeakEntity<Workspace>,
 6678        transaction: ProjectTransaction,
 6679        title: String,
 6680        cx: &mut AsyncWindowContext,
 6681    ) -> Result<()> {
 6682        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6683        cx.update(|_, cx| {
 6684            entries.sort_unstable_by_key(|(buffer, _)| {
 6685                buffer.read(cx).file().map(|f| f.path().clone())
 6686            });
 6687        })?;
 6688        if entries.is_empty() {
 6689            return Ok(());
 6690        }
 6691
 6692        // If the project transaction's edits are all contained within this editor, then
 6693        // avoid opening a new editor to display them.
 6694
 6695        if let [(buffer, transaction)] = &*entries {
 6696            let excerpt = editor.update(cx, |editor, cx| {
 6697                editor
 6698                    .buffer()
 6699                    .read(cx)
 6700                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6701            })?;
 6702            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6703                && excerpted_buffer == *buffer
 6704            {
 6705                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6706                    let excerpt_range = excerpt_range.to_offset(buffer);
 6707                    buffer
 6708                        .edited_ranges_for_transaction::<usize>(transaction)
 6709                        .all(|range| {
 6710                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6711                        })
 6712                })?;
 6713
 6714                if all_edits_within_excerpt {
 6715                    return Ok(());
 6716                }
 6717            }
 6718        }
 6719
 6720        let mut ranges_to_highlight = Vec::new();
 6721        let excerpt_buffer = cx.new(|cx| {
 6722            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6723            for (buffer_handle, transaction) in &entries {
 6724                let edited_ranges = buffer_handle
 6725                    .read(cx)
 6726                    .edited_ranges_for_transaction::<Point>(transaction)
 6727                    .collect::<Vec<_>>();
 6728                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6729                    PathKey::for_buffer(buffer_handle, cx),
 6730                    buffer_handle.clone(),
 6731                    edited_ranges,
 6732                    multibuffer_context_lines(cx),
 6733                    cx,
 6734                );
 6735
 6736                ranges_to_highlight.extend(ranges);
 6737            }
 6738            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6739            multibuffer
 6740        })?;
 6741
 6742        workspace.update_in(cx, |workspace, window, cx| {
 6743            let project = workspace.project().clone();
 6744            let editor =
 6745                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6746            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6747            editor.update(cx, |editor, cx| {
 6748                editor.highlight_background::<Self>(
 6749                    &ranges_to_highlight,
 6750                    |_, theme| theme.colors().editor_highlighted_line_background,
 6751                    cx,
 6752                );
 6753            });
 6754        })?;
 6755
 6756        Ok(())
 6757    }
 6758
 6759    pub fn clear_code_action_providers(&mut self) {
 6760        self.code_action_providers.clear();
 6761        self.available_code_actions.take();
 6762    }
 6763
 6764    pub fn add_code_action_provider(
 6765        &mut self,
 6766        provider: Rc<dyn CodeActionProvider>,
 6767        window: &mut Window,
 6768        cx: &mut Context<Self>,
 6769    ) {
 6770        if self
 6771            .code_action_providers
 6772            .iter()
 6773            .any(|existing_provider| existing_provider.id() == provider.id())
 6774        {
 6775            return;
 6776        }
 6777
 6778        self.code_action_providers.push(provider);
 6779        self.refresh_code_actions(window, cx);
 6780    }
 6781
 6782    pub fn remove_code_action_provider(
 6783        &mut self,
 6784        id: Arc<str>,
 6785        window: &mut Window,
 6786        cx: &mut Context<Self>,
 6787    ) {
 6788        self.code_action_providers
 6789            .retain(|provider| provider.id() != id);
 6790        self.refresh_code_actions(window, cx);
 6791    }
 6792
 6793    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6794        !self.code_action_providers.is_empty()
 6795            && EditorSettings::get_global(cx).toolbar.code_actions
 6796    }
 6797
 6798    pub fn has_available_code_actions(&self) -> bool {
 6799        self.available_code_actions
 6800            .as_ref()
 6801            .is_some_and(|(_, actions)| !actions.is_empty())
 6802    }
 6803
 6804    fn render_inline_code_actions(
 6805        &self,
 6806        icon_size: ui::IconSize,
 6807        display_row: DisplayRow,
 6808        is_active: bool,
 6809        cx: &mut Context<Self>,
 6810    ) -> AnyElement {
 6811        let show_tooltip = !self.context_menu_visible();
 6812        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6813            .icon_size(icon_size)
 6814            .shape(ui::IconButtonShape::Square)
 6815            .icon_color(ui::Color::Hidden)
 6816            .toggle_state(is_active)
 6817            .when(show_tooltip, |this| {
 6818                this.tooltip({
 6819                    let focus_handle = self.focus_handle.clone();
 6820                    move |_window, cx| {
 6821                        Tooltip::for_action_in(
 6822                            "Toggle Code Actions",
 6823                            &ToggleCodeActions {
 6824                                deployed_from: None,
 6825                                quick_launch: false,
 6826                            },
 6827                            &focus_handle,
 6828                            cx,
 6829                        )
 6830                    }
 6831                })
 6832            })
 6833            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6834                window.focus(&editor.focus_handle(cx));
 6835                editor.toggle_code_actions(
 6836                    &crate::actions::ToggleCodeActions {
 6837                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6838                            display_row,
 6839                        )),
 6840                        quick_launch: false,
 6841                    },
 6842                    window,
 6843                    cx,
 6844                );
 6845            }))
 6846            .into_any_element()
 6847    }
 6848
 6849    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6850        &self.context_menu
 6851    }
 6852
 6853    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6854        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6855            cx.background_executor()
 6856                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6857                .await;
 6858
 6859            let (start_buffer, start, _, end, newest_selection) = this
 6860                .update(cx, |this, cx| {
 6861                    let newest_selection = this.selections.newest_anchor().clone();
 6862                    if newest_selection.head().diff_base_anchor.is_some() {
 6863                        return None;
 6864                    }
 6865                    let display_snapshot = this.display_snapshot(cx);
 6866                    let newest_selection_adjusted =
 6867                        this.selections.newest_adjusted(&display_snapshot);
 6868                    let buffer = this.buffer.read(cx);
 6869
 6870                    let (start_buffer, start) =
 6871                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6872                    let (end_buffer, end) =
 6873                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6874
 6875                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6876                })?
 6877                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6878                .context(
 6879                    "Expected selection to lie in a single buffer when refreshing code actions",
 6880                )?;
 6881            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6882                let providers = this.code_action_providers.clone();
 6883                let tasks = this
 6884                    .code_action_providers
 6885                    .iter()
 6886                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6887                    .collect::<Vec<_>>();
 6888                (providers, tasks)
 6889            })?;
 6890
 6891            let mut actions = Vec::new();
 6892            for (provider, provider_actions) in
 6893                providers.into_iter().zip(future::join_all(tasks).await)
 6894            {
 6895                if let Some(provider_actions) = provider_actions.log_err() {
 6896                    actions.extend(provider_actions.into_iter().map(|action| {
 6897                        AvailableCodeAction {
 6898                            excerpt_id: newest_selection.start.excerpt_id,
 6899                            action,
 6900                            provider: provider.clone(),
 6901                        }
 6902                    }));
 6903                }
 6904            }
 6905
 6906            this.update(cx, |this, cx| {
 6907                this.available_code_actions = if actions.is_empty() {
 6908                    None
 6909                } else {
 6910                    Some((
 6911                        Location {
 6912                            buffer: start_buffer,
 6913                            range: start..end,
 6914                        },
 6915                        actions.into(),
 6916                    ))
 6917                };
 6918                cx.notify();
 6919            })
 6920        }));
 6921    }
 6922
 6923    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6924        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6925            self.show_git_blame_inline = false;
 6926
 6927            self.show_git_blame_inline_delay_task =
 6928                Some(cx.spawn_in(window, async move |this, cx| {
 6929                    cx.background_executor().timer(delay).await;
 6930
 6931                    this.update(cx, |this, cx| {
 6932                        this.show_git_blame_inline = true;
 6933                        cx.notify();
 6934                    })
 6935                    .log_err();
 6936                }));
 6937        }
 6938    }
 6939
 6940    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6941        let snapshot = self.snapshot(window, cx);
 6942        let cursor = self
 6943            .selections
 6944            .newest::<Point>(&snapshot.display_snapshot)
 6945            .head();
 6946        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6947        else {
 6948            return;
 6949        };
 6950
 6951        if self.blame.is_none() {
 6952            self.start_git_blame(true, window, cx);
 6953        }
 6954        let Some(blame) = self.blame.as_ref() else {
 6955            return;
 6956        };
 6957
 6958        let row_info = RowInfo {
 6959            buffer_id: Some(buffer.remote_id()),
 6960            buffer_row: Some(point.row),
 6961            ..Default::default()
 6962        };
 6963        let Some((buffer, blame_entry)) = blame
 6964            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6965            .flatten()
 6966        else {
 6967            return;
 6968        };
 6969
 6970        let anchor = self.selections.newest_anchor().head();
 6971        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6972        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6973            self.show_blame_popover(
 6974                buffer,
 6975                &blame_entry,
 6976                position + last_bounds.origin,
 6977                true,
 6978                cx,
 6979            );
 6980        };
 6981    }
 6982
 6983    fn show_blame_popover(
 6984        &mut self,
 6985        buffer: BufferId,
 6986        blame_entry: &BlameEntry,
 6987        position: gpui::Point<Pixels>,
 6988        ignore_timeout: bool,
 6989        cx: &mut Context<Self>,
 6990    ) {
 6991        if let Some(state) = &mut self.inline_blame_popover {
 6992            state.hide_task.take();
 6993        } else {
 6994            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6995            let blame_entry = blame_entry.clone();
 6996            let show_task = cx.spawn(async move |editor, cx| {
 6997                if !ignore_timeout {
 6998                    cx.background_executor()
 6999                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7000                        .await;
 7001                }
 7002                editor
 7003                    .update(cx, |editor, cx| {
 7004                        editor.inline_blame_popover_show_task.take();
 7005                        let Some(blame) = editor.blame.as_ref() else {
 7006                            return;
 7007                        };
 7008                        let blame = blame.read(cx);
 7009                        let details = blame.details_for_entry(buffer, &blame_entry);
 7010                        let markdown = cx.new(|cx| {
 7011                            Markdown::new(
 7012                                details
 7013                                    .as_ref()
 7014                                    .map(|message| message.message.clone())
 7015                                    .unwrap_or_default(),
 7016                                None,
 7017                                None,
 7018                                cx,
 7019                            )
 7020                        });
 7021                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7022                            position,
 7023                            hide_task: None,
 7024                            popover_bounds: None,
 7025                            popover_state: InlineBlamePopoverState {
 7026                                scroll_handle: ScrollHandle::new(),
 7027                                commit_message: details,
 7028                                markdown,
 7029                            },
 7030                            keyboard_grace: ignore_timeout,
 7031                        });
 7032                        cx.notify();
 7033                    })
 7034                    .ok();
 7035            });
 7036            self.inline_blame_popover_show_task = Some(show_task);
 7037        }
 7038    }
 7039
 7040    pub fn has_mouse_context_menu(&self) -> bool {
 7041        self.mouse_context_menu.is_some()
 7042    }
 7043
 7044    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7045        self.inline_blame_popover_show_task.take();
 7046        if let Some(state) = &mut self.inline_blame_popover {
 7047            let hide_task = cx.spawn(async move |editor, cx| {
 7048                if !ignore_timeout {
 7049                    cx.background_executor()
 7050                        .timer(std::time::Duration::from_millis(100))
 7051                        .await;
 7052                }
 7053                editor
 7054                    .update(cx, |editor, cx| {
 7055                        editor.inline_blame_popover.take();
 7056                        cx.notify();
 7057                    })
 7058                    .ok();
 7059            });
 7060            state.hide_task = Some(hide_task);
 7061            true
 7062        } else {
 7063            false
 7064        }
 7065    }
 7066
 7067    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7068        if self.pending_rename.is_some() {
 7069            return None;
 7070        }
 7071
 7072        let provider = self.semantics_provider.clone()?;
 7073        let buffer = self.buffer.read(cx);
 7074        let newest_selection = self.selections.newest_anchor().clone();
 7075        let cursor_position = newest_selection.head();
 7076        let (cursor_buffer, cursor_buffer_position) =
 7077            buffer.text_anchor_for_position(cursor_position, cx)?;
 7078        let (tail_buffer, tail_buffer_position) =
 7079            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7080        if cursor_buffer != tail_buffer {
 7081            return None;
 7082        }
 7083
 7084        let snapshot = cursor_buffer.read(cx).snapshot();
 7085        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7086        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7087        if start_word_range != end_word_range {
 7088            self.document_highlights_task.take();
 7089            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7090            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7091            return None;
 7092        }
 7093
 7094        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7095        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7096            cx.background_executor()
 7097                .timer(Duration::from_millis(debounce))
 7098                .await;
 7099
 7100            let highlights = if let Some(highlights) = cx
 7101                .update(|cx| {
 7102                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7103                })
 7104                .ok()
 7105                .flatten()
 7106            {
 7107                highlights.await.log_err()
 7108            } else {
 7109                None
 7110            };
 7111
 7112            if let Some(highlights) = highlights {
 7113                this.update(cx, |this, cx| {
 7114                    if this.pending_rename.is_some() {
 7115                        return;
 7116                    }
 7117
 7118                    let buffer = this.buffer.read(cx);
 7119                    if buffer
 7120                        .text_anchor_for_position(cursor_position, cx)
 7121                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7122                    {
 7123                        return;
 7124                    }
 7125
 7126                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7127                    let mut write_ranges = Vec::new();
 7128                    let mut read_ranges = Vec::new();
 7129                    for highlight in highlights {
 7130                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7131                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7132                        {
 7133                            let start = highlight
 7134                                .range
 7135                                .start
 7136                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7137                            let end = highlight
 7138                                .range
 7139                                .end
 7140                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7141                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7142                                continue;
 7143                            }
 7144
 7145                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7146                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7147                                write_ranges.push(range);
 7148                            } else {
 7149                                read_ranges.push(range);
 7150                            }
 7151                        }
 7152                    }
 7153
 7154                    this.highlight_background::<DocumentHighlightRead>(
 7155                        &read_ranges,
 7156                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7157                        cx,
 7158                    );
 7159                    this.highlight_background::<DocumentHighlightWrite>(
 7160                        &write_ranges,
 7161                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7162                        cx,
 7163                    );
 7164                    cx.notify();
 7165                })
 7166                .log_err();
 7167            }
 7168        }));
 7169        None
 7170    }
 7171
 7172    fn prepare_highlight_query_from_selection(
 7173        &mut self,
 7174        window: &Window,
 7175        cx: &mut Context<Editor>,
 7176    ) -> Option<(String, Range<Anchor>)> {
 7177        if matches!(self.mode, EditorMode::SingleLine) {
 7178            return None;
 7179        }
 7180        if !EditorSettings::get_global(cx).selection_highlight {
 7181            return None;
 7182        }
 7183        if self.selections.count() != 1 || self.selections.line_mode() {
 7184            return None;
 7185        }
 7186        let snapshot = self.snapshot(window, cx);
 7187        let selection = self.selections.newest::<Point>(&snapshot);
 7188        // If the selection spans multiple rows OR it is empty
 7189        if selection.start.row != selection.end.row
 7190            || selection.start.column == selection.end.column
 7191        {
 7192            return None;
 7193        }
 7194        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7195        let query = snapshot
 7196            .buffer_snapshot()
 7197            .text_for_range(selection_anchor_range.clone())
 7198            .collect::<String>();
 7199        if query.trim().is_empty() {
 7200            return None;
 7201        }
 7202        Some((query, selection_anchor_range))
 7203    }
 7204
 7205    #[ztracing::instrument(skip_all)]
 7206    fn update_selection_occurrence_highlights(
 7207        &mut self,
 7208        query_text: String,
 7209        query_range: Range<Anchor>,
 7210        multi_buffer_range_to_query: Range<Point>,
 7211        use_debounce: bool,
 7212        window: &mut Window,
 7213        cx: &mut Context<Editor>,
 7214    ) -> Task<()> {
 7215        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7216        cx.spawn_in(window, async move |editor, cx| {
 7217            if use_debounce {
 7218                cx.background_executor()
 7219                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7220                    .await;
 7221            }
 7222            let match_task = cx.background_spawn(async move {
 7223                let buffer_ranges = multi_buffer_snapshot
 7224                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7225                    .into_iter()
 7226                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7227                let mut match_ranges = Vec::new();
 7228                let Ok(regex) = project::search::SearchQuery::text(
 7229                    query_text.clone(),
 7230                    false,
 7231                    false,
 7232                    false,
 7233                    Default::default(),
 7234                    Default::default(),
 7235                    false,
 7236                    None,
 7237                ) else {
 7238                    return Vec::default();
 7239                };
 7240                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7241                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7242                    match_ranges.extend(
 7243                        regex
 7244                            .search(
 7245                                buffer_snapshot,
 7246                                Some(search_range.start.0..search_range.end.0),
 7247                            )
 7248                            .await
 7249                            .into_iter()
 7250                            .filter_map(|match_range| {
 7251                                let match_start = buffer_snapshot
 7252                                    .anchor_after(search_range.start + match_range.start);
 7253                                let match_end = buffer_snapshot
 7254                                    .anchor_before(search_range.start + match_range.end);
 7255                                let match_anchor_range =
 7256                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7257                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7258                            }),
 7259                    );
 7260                }
 7261                match_ranges
 7262            });
 7263            let match_ranges = match_task.await;
 7264            editor
 7265                .update_in(cx, |editor, _, cx| {
 7266                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7267                    if !match_ranges.is_empty() {
 7268                        editor.highlight_background::<SelectedTextHighlight>(
 7269                            &match_ranges,
 7270                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7271                            cx,
 7272                        )
 7273                    }
 7274                })
 7275                .log_err();
 7276        })
 7277    }
 7278
 7279    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7280        struct NewlineFold;
 7281        let type_id = std::any::TypeId::of::<NewlineFold>();
 7282        if !self.mode.is_single_line() {
 7283            return;
 7284        }
 7285        let snapshot = self.snapshot(window, cx);
 7286        if snapshot.buffer_snapshot().max_point().row == 0 {
 7287            return;
 7288        }
 7289        let task = cx.background_spawn(async move {
 7290            let new_newlines = snapshot
 7291                .buffer_chars_at(MultiBufferOffset(0))
 7292                .filter_map(|(c, i)| {
 7293                    if c == '\n' {
 7294                        Some(
 7295                            snapshot.buffer_snapshot().anchor_after(i)
 7296                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7297                        )
 7298                    } else {
 7299                        None
 7300                    }
 7301                })
 7302                .collect::<Vec<_>>();
 7303            let existing_newlines = snapshot
 7304                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7305                .filter_map(|fold| {
 7306                    if fold.placeholder.type_tag == Some(type_id) {
 7307                        Some(fold.range.start..fold.range.end)
 7308                    } else {
 7309                        None
 7310                    }
 7311                })
 7312                .collect::<Vec<_>>();
 7313
 7314            (new_newlines, existing_newlines)
 7315        });
 7316        self.folding_newlines = cx.spawn(async move |this, cx| {
 7317            let (new_newlines, existing_newlines) = task.await;
 7318            if new_newlines == existing_newlines {
 7319                return;
 7320            }
 7321            let placeholder = FoldPlaceholder {
 7322                render: Arc::new(move |_, _, cx| {
 7323                    div()
 7324                        .bg(cx.theme().status().hint_background)
 7325                        .border_b_1()
 7326                        .size_full()
 7327                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7328                        .border_color(cx.theme().status().hint)
 7329                        .child("\\n")
 7330                        .into_any()
 7331                }),
 7332                constrain_width: false,
 7333                merge_adjacent: false,
 7334                type_tag: Some(type_id),
 7335            };
 7336            let creases = new_newlines
 7337                .into_iter()
 7338                .map(|range| Crease::simple(range, placeholder.clone()))
 7339                .collect();
 7340            this.update(cx, |this, cx| {
 7341                this.display_map.update(cx, |display_map, cx| {
 7342                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7343                    display_map.fold(creases, cx);
 7344                });
 7345            })
 7346            .ok();
 7347        });
 7348    }
 7349
 7350    #[ztracing::instrument(skip_all)]
 7351    fn refresh_selected_text_highlights(
 7352        &mut self,
 7353        on_buffer_edit: bool,
 7354        window: &mut Window,
 7355        cx: &mut Context<Editor>,
 7356    ) {
 7357        let Some((query_text, query_range)) =
 7358            self.prepare_highlight_query_from_selection(window, cx)
 7359        else {
 7360            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7361            self.quick_selection_highlight_task.take();
 7362            self.debounced_selection_highlight_task.take();
 7363            return;
 7364        };
 7365        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7366        if on_buffer_edit
 7367            || self
 7368                .quick_selection_highlight_task
 7369                .as_ref()
 7370                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7371        {
 7372            let multi_buffer_visible_start = self
 7373                .scroll_manager
 7374                .anchor()
 7375                .anchor
 7376                .to_point(&multi_buffer_snapshot);
 7377            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7378                multi_buffer_visible_start
 7379                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7380                Bias::Left,
 7381            );
 7382            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7383            self.quick_selection_highlight_task = Some((
 7384                query_range.clone(),
 7385                self.update_selection_occurrence_highlights(
 7386                    query_text.clone(),
 7387                    query_range.clone(),
 7388                    multi_buffer_visible_range,
 7389                    false,
 7390                    window,
 7391                    cx,
 7392                ),
 7393            ));
 7394        }
 7395        if on_buffer_edit
 7396            || self
 7397                .debounced_selection_highlight_task
 7398                .as_ref()
 7399                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7400        {
 7401            let multi_buffer_start = multi_buffer_snapshot
 7402                .anchor_before(MultiBufferOffset(0))
 7403                .to_point(&multi_buffer_snapshot);
 7404            let multi_buffer_end = multi_buffer_snapshot
 7405                .anchor_after(multi_buffer_snapshot.len())
 7406                .to_point(&multi_buffer_snapshot);
 7407            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7408            self.debounced_selection_highlight_task = Some((
 7409                query_range.clone(),
 7410                self.update_selection_occurrence_highlights(
 7411                    query_text,
 7412                    query_range,
 7413                    multi_buffer_full_range,
 7414                    true,
 7415                    window,
 7416                    cx,
 7417                ),
 7418            ));
 7419        }
 7420    }
 7421
 7422    pub fn refresh_edit_prediction(
 7423        &mut self,
 7424        debounce: bool,
 7425        user_requested: bool,
 7426        window: &mut Window,
 7427        cx: &mut Context<Self>,
 7428    ) -> Option<()> {
 7429        if DisableAiSettings::get_global(cx).disable_ai {
 7430            return None;
 7431        }
 7432
 7433        let provider = self.edit_prediction_provider()?;
 7434        let cursor = self.selections.newest_anchor().head();
 7435        let (buffer, cursor_buffer_position) =
 7436            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7437
 7438        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7439            self.discard_edit_prediction(false, cx);
 7440            return None;
 7441        }
 7442
 7443        self.update_visible_edit_prediction(window, cx);
 7444
 7445        if !user_requested
 7446            && (!self.should_show_edit_predictions()
 7447                || !self.is_focused(window)
 7448                || buffer.read(cx).is_empty())
 7449        {
 7450            self.discard_edit_prediction(false, cx);
 7451            return None;
 7452        }
 7453
 7454        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7455        Some(())
 7456    }
 7457
 7458    fn show_edit_predictions_in_menu(&self) -> bool {
 7459        match self.edit_prediction_settings {
 7460            EditPredictionSettings::Disabled => false,
 7461            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7462        }
 7463    }
 7464
 7465    pub fn edit_predictions_enabled(&self) -> bool {
 7466        match self.edit_prediction_settings {
 7467            EditPredictionSettings::Disabled => false,
 7468            EditPredictionSettings::Enabled { .. } => true,
 7469        }
 7470    }
 7471
 7472    fn edit_prediction_requires_modifier(&self) -> bool {
 7473        match self.edit_prediction_settings {
 7474            EditPredictionSettings::Disabled => false,
 7475            EditPredictionSettings::Enabled {
 7476                preview_requires_modifier,
 7477                ..
 7478            } => preview_requires_modifier,
 7479        }
 7480    }
 7481
 7482    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7483        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7484            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7485            self.discard_edit_prediction(false, cx);
 7486        } else {
 7487            let selection = self.selections.newest_anchor();
 7488            let cursor = selection.head();
 7489
 7490            if let Some((buffer, cursor_buffer_position)) =
 7491                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7492            {
 7493                self.edit_prediction_settings =
 7494                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7495            }
 7496        }
 7497    }
 7498
 7499    fn edit_prediction_settings_at_position(
 7500        &self,
 7501        buffer: &Entity<Buffer>,
 7502        buffer_position: language::Anchor,
 7503        cx: &App,
 7504    ) -> EditPredictionSettings {
 7505        if !self.mode.is_full()
 7506            || !self.show_edit_predictions_override.unwrap_or(true)
 7507            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7508        {
 7509            return EditPredictionSettings::Disabled;
 7510        }
 7511
 7512        let buffer = buffer.read(cx);
 7513
 7514        let file = buffer.file();
 7515
 7516        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7517            return EditPredictionSettings::Disabled;
 7518        };
 7519
 7520        let by_provider = matches!(
 7521            self.menu_edit_predictions_policy,
 7522            MenuEditPredictionsPolicy::ByProvider
 7523        );
 7524
 7525        let show_in_menu = by_provider
 7526            && self
 7527                .edit_prediction_provider
 7528                .as_ref()
 7529                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7530
 7531        let preview_requires_modifier =
 7532            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7533
 7534        EditPredictionSettings::Enabled {
 7535            show_in_menu,
 7536            preview_requires_modifier,
 7537        }
 7538    }
 7539
 7540    fn should_show_edit_predictions(&self) -> bool {
 7541        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7542    }
 7543
 7544    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7545        matches!(
 7546            self.edit_prediction_preview,
 7547            EditPredictionPreview::Active { .. }
 7548        )
 7549    }
 7550
 7551    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7552        let cursor = self.selections.newest_anchor().head();
 7553        if let Some((buffer, cursor_position)) =
 7554            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7555        {
 7556            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7557        } else {
 7558            false
 7559        }
 7560    }
 7561
 7562    pub fn supports_minimap(&self, cx: &App) -> bool {
 7563        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7564    }
 7565
 7566    fn edit_predictions_enabled_in_buffer(
 7567        &self,
 7568        buffer: &Entity<Buffer>,
 7569        buffer_position: language::Anchor,
 7570        cx: &App,
 7571    ) -> bool {
 7572        maybe!({
 7573            if self.read_only(cx) {
 7574                return Some(false);
 7575            }
 7576            let provider = self.edit_prediction_provider()?;
 7577            if !provider.is_enabled(buffer, buffer_position, cx) {
 7578                return Some(false);
 7579            }
 7580            let buffer = buffer.read(cx);
 7581            let Some(file) = buffer.file() else {
 7582                return Some(true);
 7583            };
 7584            let settings = all_language_settings(Some(file), cx);
 7585            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7586        })
 7587        .unwrap_or(false)
 7588    }
 7589
 7590    fn cycle_edit_prediction(
 7591        &mut self,
 7592        direction: Direction,
 7593        window: &mut Window,
 7594        cx: &mut Context<Self>,
 7595    ) -> Option<()> {
 7596        let provider = self.edit_prediction_provider()?;
 7597        let cursor = self.selections.newest_anchor().head();
 7598        let (buffer, cursor_buffer_position) =
 7599            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7600        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7601            return None;
 7602        }
 7603
 7604        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7605        self.update_visible_edit_prediction(window, cx);
 7606
 7607        Some(())
 7608    }
 7609
 7610    pub fn show_edit_prediction(
 7611        &mut self,
 7612        _: &ShowEditPrediction,
 7613        window: &mut Window,
 7614        cx: &mut Context<Self>,
 7615    ) {
 7616        if !self.has_active_edit_prediction() {
 7617            self.refresh_edit_prediction(false, true, window, cx);
 7618            return;
 7619        }
 7620
 7621        self.update_visible_edit_prediction(window, cx);
 7622    }
 7623
 7624    pub fn display_cursor_names(
 7625        &mut self,
 7626        _: &DisplayCursorNames,
 7627        window: &mut Window,
 7628        cx: &mut Context<Self>,
 7629    ) {
 7630        self.show_cursor_names(window, cx);
 7631    }
 7632
 7633    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7634        self.show_cursor_names = true;
 7635        cx.notify();
 7636        cx.spawn_in(window, async move |this, cx| {
 7637            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7638            this.update(cx, |this, cx| {
 7639                this.show_cursor_names = false;
 7640                cx.notify()
 7641            })
 7642            .ok()
 7643        })
 7644        .detach();
 7645    }
 7646
 7647    pub fn next_edit_prediction(
 7648        &mut self,
 7649        _: &NextEditPrediction,
 7650        window: &mut Window,
 7651        cx: &mut Context<Self>,
 7652    ) {
 7653        if self.has_active_edit_prediction() {
 7654            self.cycle_edit_prediction(Direction::Next, window, cx);
 7655        } else {
 7656            let is_copilot_disabled = self
 7657                .refresh_edit_prediction(false, true, window, cx)
 7658                .is_none();
 7659            if is_copilot_disabled {
 7660                cx.propagate();
 7661            }
 7662        }
 7663    }
 7664
 7665    pub fn previous_edit_prediction(
 7666        &mut self,
 7667        _: &PreviousEditPrediction,
 7668        window: &mut Window,
 7669        cx: &mut Context<Self>,
 7670    ) {
 7671        if self.has_active_edit_prediction() {
 7672            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7673        } else {
 7674            let is_copilot_disabled = self
 7675                .refresh_edit_prediction(false, true, window, cx)
 7676                .is_none();
 7677            if is_copilot_disabled {
 7678                cx.propagate();
 7679            }
 7680        }
 7681    }
 7682
 7683    pub fn accept_partial_edit_prediction(
 7684        &mut self,
 7685        granularity: EditPredictionGranularity,
 7686        window: &mut Window,
 7687        cx: &mut Context<Self>,
 7688    ) {
 7689        if self.show_edit_predictions_in_menu() {
 7690            self.hide_context_menu(window, cx);
 7691        }
 7692
 7693        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7694            return;
 7695        };
 7696
 7697        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7698            return;
 7699        }
 7700
 7701        match &active_edit_prediction.completion {
 7702            EditPrediction::MoveWithin { target, .. } => {
 7703                let target = *target;
 7704
 7705                if matches!(granularity, EditPredictionGranularity::Full) {
 7706                    if let Some(position_map) = &self.last_position_map {
 7707                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7708                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7709
 7710                        if is_visible || !self.edit_prediction_requires_modifier() {
 7711                            self.unfold_ranges(&[target..target], true, false, cx);
 7712                            self.change_selections(
 7713                                SelectionEffects::scroll(Autoscroll::newest()),
 7714                                window,
 7715                                cx,
 7716                                |selections| {
 7717                                    selections.select_anchor_ranges([target..target]);
 7718                                },
 7719                            );
 7720                            self.clear_row_highlights::<EditPredictionPreview>();
 7721                            self.edit_prediction_preview
 7722                                .set_previous_scroll_position(None);
 7723                        } else {
 7724                            // Highlight and request scroll
 7725                            self.edit_prediction_preview
 7726                                .set_previous_scroll_position(Some(
 7727                                    position_map.snapshot.scroll_anchor,
 7728                                ));
 7729                            self.highlight_rows::<EditPredictionPreview>(
 7730                                target..target,
 7731                                cx.theme().colors().editor_highlighted_line_background,
 7732                                RowHighlightOptions {
 7733                                    autoscroll: true,
 7734                                    ..Default::default()
 7735                                },
 7736                                cx,
 7737                            );
 7738                            self.request_autoscroll(Autoscroll::fit(), cx);
 7739                        }
 7740                    }
 7741                } else {
 7742                    self.change_selections(
 7743                        SelectionEffects::scroll(Autoscroll::newest()),
 7744                        window,
 7745                        cx,
 7746                        |selections| {
 7747                            selections.select_anchor_ranges([target..target]);
 7748                        },
 7749                    );
 7750                }
 7751            }
 7752            EditPrediction::MoveOutside { snapshot, target } => {
 7753                if let Some(workspace) = self.workspace() {
 7754                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7755                        .detach_and_log_err(cx);
 7756                }
 7757            }
 7758            EditPrediction::Edit { edits, .. } => {
 7759                self.report_edit_prediction_event(
 7760                    active_edit_prediction.completion_id.clone(),
 7761                    true,
 7762                    cx,
 7763                );
 7764
 7765                match granularity {
 7766                    EditPredictionGranularity::Full => {
 7767                        if let Some(provider) = self.edit_prediction_provider() {
 7768                            provider.accept(cx);
 7769                        }
 7770
 7771                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7772                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7773                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7774
 7775                        self.buffer.update(cx, |buffer, cx| {
 7776                            buffer.edit(edits.iter().cloned(), None, cx)
 7777                        });
 7778
 7779                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7780                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7781                        });
 7782
 7783                        let selections = self.selections.disjoint_anchors_arc();
 7784                        if let Some(transaction_id_now) =
 7785                            self.buffer.read(cx).last_transaction_id(cx)
 7786                        {
 7787                            if transaction_id_prev != Some(transaction_id_now) {
 7788                                self.selection_history
 7789                                    .insert_transaction(transaction_id_now, selections);
 7790                            }
 7791                        }
 7792
 7793                        self.update_visible_edit_prediction(window, cx);
 7794                        if self.active_edit_prediction.is_none() {
 7795                            self.refresh_edit_prediction(true, true, window, cx);
 7796                        }
 7797                        cx.notify();
 7798                    }
 7799                    _ => {
 7800                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7801                        let cursor_offset = self
 7802                            .selections
 7803                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7804                            .head();
 7805
 7806                        let insertion = edits.iter().find_map(|(range, text)| {
 7807                            let range = range.to_offset(&snapshot);
 7808                            if range.is_empty() && range.start == cursor_offset {
 7809                                Some(text)
 7810                            } else {
 7811                                None
 7812                            }
 7813                        });
 7814
 7815                        if let Some(text) = insertion {
 7816                            let text_to_insert = match granularity {
 7817                                EditPredictionGranularity::Word => {
 7818                                    let mut partial = text
 7819                                        .chars()
 7820                                        .by_ref()
 7821                                        .take_while(|c| c.is_alphabetic())
 7822                                        .collect::<String>();
 7823                                    if partial.is_empty() {
 7824                                        partial = text
 7825                                            .chars()
 7826                                            .by_ref()
 7827                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7828                                            .collect::<String>();
 7829                                    }
 7830                                    partial
 7831                                }
 7832                                EditPredictionGranularity::Line => {
 7833                                    if let Some(line) = text.split_inclusive('\n').next() {
 7834                                        line.to_string()
 7835                                    } else {
 7836                                        text.to_string()
 7837                                    }
 7838                                }
 7839                                EditPredictionGranularity::Full => unreachable!(),
 7840                            };
 7841
 7842                            cx.emit(EditorEvent::InputHandled {
 7843                                utf16_range_to_replace: None,
 7844                                text: text_to_insert.clone().into(),
 7845                            });
 7846
 7847                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7848                            self.refresh_edit_prediction(true, true, window, cx);
 7849                            cx.notify();
 7850                        } else {
 7851                            self.accept_partial_edit_prediction(
 7852                                EditPredictionGranularity::Full,
 7853                                window,
 7854                                cx,
 7855                            );
 7856                        }
 7857                    }
 7858                }
 7859            }
 7860        }
 7861
 7862        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7863    }
 7864
 7865    pub fn accept_next_word_edit_prediction(
 7866        &mut self,
 7867        _: &AcceptNextWordEditPrediction,
 7868        window: &mut Window,
 7869        cx: &mut Context<Self>,
 7870    ) {
 7871        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7872    }
 7873
 7874    pub fn accept_next_line_edit_prediction(
 7875        &mut self,
 7876        _: &AcceptNextLineEditPrediction,
 7877        window: &mut Window,
 7878        cx: &mut Context<Self>,
 7879    ) {
 7880        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7881    }
 7882
 7883    pub fn accept_edit_prediction(
 7884        &mut self,
 7885        _: &AcceptEditPrediction,
 7886        window: &mut Window,
 7887        cx: &mut Context<Self>,
 7888    ) {
 7889        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7890    }
 7891
 7892    fn discard_edit_prediction(
 7893        &mut self,
 7894        should_report_edit_prediction_event: bool,
 7895        cx: &mut Context<Self>,
 7896    ) -> bool {
 7897        if should_report_edit_prediction_event {
 7898            let completion_id = self
 7899                .active_edit_prediction
 7900                .as_ref()
 7901                .and_then(|active_completion| active_completion.completion_id.clone());
 7902
 7903            self.report_edit_prediction_event(completion_id, false, cx);
 7904        }
 7905
 7906        if let Some(provider) = self.edit_prediction_provider() {
 7907            provider.discard(cx);
 7908        }
 7909
 7910        self.take_active_edit_prediction(cx)
 7911    }
 7912
 7913    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7914        let Some(provider) = self.edit_prediction_provider() else {
 7915            return;
 7916        };
 7917
 7918        let Some((_, buffer, _)) = self
 7919            .buffer
 7920            .read(cx)
 7921            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7922        else {
 7923            return;
 7924        };
 7925
 7926        let extension = buffer
 7927            .read(cx)
 7928            .file()
 7929            .and_then(|file| Some(file.path().extension()?.to_string()));
 7930
 7931        let event_type = match accepted {
 7932            true => "Edit Prediction Accepted",
 7933            false => "Edit Prediction Discarded",
 7934        };
 7935        telemetry::event!(
 7936            event_type,
 7937            provider = provider.name(),
 7938            prediction_id = id,
 7939            suggestion_accepted = accepted,
 7940            file_extension = extension,
 7941        );
 7942    }
 7943
 7944    fn open_editor_at_anchor(
 7945        snapshot: &language::BufferSnapshot,
 7946        target: language::Anchor,
 7947        workspace: &Entity<Workspace>,
 7948        window: &mut Window,
 7949        cx: &mut App,
 7950    ) -> Task<Result<()>> {
 7951        workspace.update(cx, |workspace, cx| {
 7952            let path = snapshot.file().map(|file| file.full_path(cx));
 7953            let Some(path) =
 7954                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7955            else {
 7956                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7957            };
 7958            let target = text::ToPoint::to_point(&target, snapshot);
 7959            let item = workspace.open_path(path, None, true, window, cx);
 7960            window.spawn(cx, async move |cx| {
 7961                let Some(editor) = item.await?.downcast::<Editor>() else {
 7962                    return Ok(());
 7963                };
 7964                editor
 7965                    .update_in(cx, |editor, window, cx| {
 7966                        editor.go_to_singleton_buffer_point(target, window, cx);
 7967                    })
 7968                    .ok();
 7969                anyhow::Ok(())
 7970            })
 7971        })
 7972    }
 7973
 7974    pub fn has_active_edit_prediction(&self) -> bool {
 7975        self.active_edit_prediction.is_some()
 7976    }
 7977
 7978    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7979        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7980            return false;
 7981        };
 7982
 7983        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7984        self.clear_highlights::<EditPredictionHighlight>(cx);
 7985        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7986        true
 7987    }
 7988
 7989    /// Returns true when we're displaying the edit prediction popover below the cursor
 7990    /// like we are not previewing and the LSP autocomplete menu is visible
 7991    /// or we are in `when_holding_modifier` mode.
 7992    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7993        if self.edit_prediction_preview_is_active()
 7994            || !self.show_edit_predictions_in_menu()
 7995            || !self.edit_predictions_enabled()
 7996        {
 7997            return false;
 7998        }
 7999
 8000        if self.has_visible_completions_menu() {
 8001            return true;
 8002        }
 8003
 8004        has_completion && self.edit_prediction_requires_modifier()
 8005    }
 8006
 8007    fn handle_modifiers_changed(
 8008        &mut self,
 8009        modifiers: Modifiers,
 8010        position_map: &PositionMap,
 8011        window: &mut Window,
 8012        cx: &mut Context<Self>,
 8013    ) {
 8014        // Ensure that the edit prediction preview is updated, even when not
 8015        // enabled, if there's an active edit prediction preview.
 8016        if self.show_edit_predictions_in_menu()
 8017            || matches!(
 8018                self.edit_prediction_preview,
 8019                EditPredictionPreview::Active { .. }
 8020            )
 8021        {
 8022            self.update_edit_prediction_preview(&modifiers, window, cx);
 8023        }
 8024
 8025        self.update_selection_mode(&modifiers, position_map, window, cx);
 8026
 8027        let mouse_position = window.mouse_position();
 8028        if !position_map.text_hitbox.is_hovered(window) {
 8029            return;
 8030        }
 8031
 8032        self.update_hovered_link(
 8033            position_map.point_for_position(mouse_position),
 8034            &position_map.snapshot,
 8035            modifiers,
 8036            window,
 8037            cx,
 8038        )
 8039    }
 8040
 8041    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8042        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8043            MultiCursorModifier::Alt => modifiers.secondary(),
 8044            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8045        }
 8046    }
 8047
 8048    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8049        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8050            MultiCursorModifier::Alt => modifiers.alt,
 8051            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8052        }
 8053    }
 8054
 8055    fn columnar_selection_mode(
 8056        modifiers: &Modifiers,
 8057        cx: &mut Context<Self>,
 8058    ) -> Option<ColumnarMode> {
 8059        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8060            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8061                Some(ColumnarMode::FromMouse)
 8062            } else if Self::is_alt_pressed(modifiers, cx) {
 8063                Some(ColumnarMode::FromSelection)
 8064            } else {
 8065                None
 8066            }
 8067        } else {
 8068            None
 8069        }
 8070    }
 8071
 8072    fn update_selection_mode(
 8073        &mut self,
 8074        modifiers: &Modifiers,
 8075        position_map: &PositionMap,
 8076        window: &mut Window,
 8077        cx: &mut Context<Self>,
 8078    ) {
 8079        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8080            return;
 8081        };
 8082        if self.selections.pending_anchor().is_none() {
 8083            return;
 8084        }
 8085
 8086        let mouse_position = window.mouse_position();
 8087        let point_for_position = position_map.point_for_position(mouse_position);
 8088        let position = point_for_position.previous_valid;
 8089
 8090        self.select(
 8091            SelectPhase::BeginColumnar {
 8092                position,
 8093                reset: false,
 8094                mode,
 8095                goal_column: point_for_position.exact_unclipped.column(),
 8096            },
 8097            window,
 8098            cx,
 8099        );
 8100    }
 8101
 8102    fn update_edit_prediction_preview(
 8103        &mut self,
 8104        modifiers: &Modifiers,
 8105        window: &mut Window,
 8106        cx: &mut Context<Self>,
 8107    ) {
 8108        let mut modifiers_held = false;
 8109
 8110        // Check bindings for all granularities.
 8111        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8112        let granularities = [
 8113            EditPredictionGranularity::Full,
 8114            EditPredictionGranularity::Line,
 8115            EditPredictionGranularity::Word,
 8116        ];
 8117
 8118        for granularity in granularities {
 8119            if let Some(keystroke) = self
 8120                .accept_edit_prediction_keybind(granularity, window, cx)
 8121                .keystroke()
 8122            {
 8123                modifiers_held = modifiers_held
 8124                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8125            }
 8126        }
 8127
 8128        if modifiers_held {
 8129            if matches!(
 8130                self.edit_prediction_preview,
 8131                EditPredictionPreview::Inactive { .. }
 8132            ) {
 8133                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8134                    provider.provider.did_show(cx)
 8135                }
 8136
 8137                self.edit_prediction_preview = EditPredictionPreview::Active {
 8138                    previous_scroll_position: None,
 8139                    since: Instant::now(),
 8140                };
 8141
 8142                self.update_visible_edit_prediction(window, cx);
 8143                cx.notify();
 8144            }
 8145        } else if let EditPredictionPreview::Active {
 8146            previous_scroll_position,
 8147            since,
 8148        } = self.edit_prediction_preview
 8149        {
 8150            if let (Some(previous_scroll_position), Some(position_map)) =
 8151                (previous_scroll_position, self.last_position_map.as_ref())
 8152            {
 8153                self.set_scroll_position(
 8154                    previous_scroll_position
 8155                        .scroll_position(&position_map.snapshot.display_snapshot),
 8156                    window,
 8157                    cx,
 8158                );
 8159            }
 8160
 8161            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8162                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8163            };
 8164            self.clear_row_highlights::<EditPredictionPreview>();
 8165            self.update_visible_edit_prediction(window, cx);
 8166            cx.notify();
 8167        }
 8168    }
 8169
 8170    fn update_visible_edit_prediction(
 8171        &mut self,
 8172        _window: &mut Window,
 8173        cx: &mut Context<Self>,
 8174    ) -> Option<()> {
 8175        if DisableAiSettings::get_global(cx).disable_ai {
 8176            return None;
 8177        }
 8178
 8179        if self.ime_transaction.is_some() {
 8180            self.discard_edit_prediction(false, cx);
 8181            return None;
 8182        }
 8183
 8184        let selection = self.selections.newest_anchor();
 8185        let cursor = selection.head();
 8186        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8187        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8188        let excerpt_id = cursor.excerpt_id;
 8189
 8190        let show_in_menu = self.show_edit_predictions_in_menu();
 8191        let completions_menu_has_precedence = !show_in_menu
 8192            && (self.context_menu.borrow().is_some()
 8193                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8194
 8195        if completions_menu_has_precedence
 8196            || !offset_selection.is_empty()
 8197            || self
 8198                .active_edit_prediction
 8199                .as_ref()
 8200                .is_some_and(|completion| {
 8201                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8202                        return false;
 8203                    };
 8204                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8205                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8206                    !invalidation_range.contains(&offset_selection.head())
 8207                })
 8208        {
 8209            self.discard_edit_prediction(false, cx);
 8210            return None;
 8211        }
 8212
 8213        self.take_active_edit_prediction(cx);
 8214        let Some(provider) = self.edit_prediction_provider() else {
 8215            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8216            return None;
 8217        };
 8218
 8219        let (buffer, cursor_buffer_position) =
 8220            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8221
 8222        self.edit_prediction_settings =
 8223            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8224
 8225        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8226
 8227        if self.edit_prediction_indent_conflict {
 8228            let cursor_point = cursor.to_point(&multibuffer);
 8229            let mut suggested_indent = None;
 8230            multibuffer.suggested_indents_callback(
 8231                cursor_point.row..cursor_point.row + 1,
 8232                |_, indent| {
 8233                    suggested_indent = Some(indent);
 8234                    ControlFlow::Break(())
 8235                },
 8236                cx,
 8237            );
 8238
 8239            if let Some(indent) = suggested_indent
 8240                && indent.len == cursor_point.column
 8241            {
 8242                self.edit_prediction_indent_conflict = false;
 8243            }
 8244        }
 8245
 8246        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8247
 8248        let (completion_id, edits, edit_preview) = match edit_prediction {
 8249            edit_prediction_types::EditPrediction::Local {
 8250                id,
 8251                edits,
 8252                edit_preview,
 8253            } => (id, edits, edit_preview),
 8254            edit_prediction_types::EditPrediction::Jump {
 8255                id,
 8256                snapshot,
 8257                target,
 8258            } => {
 8259                self.stale_edit_prediction_in_menu = None;
 8260                self.active_edit_prediction = Some(EditPredictionState {
 8261                    inlay_ids: vec![],
 8262                    completion: EditPrediction::MoveOutside { snapshot, target },
 8263                    completion_id: id,
 8264                    invalidation_range: None,
 8265                });
 8266                cx.notify();
 8267                return Some(());
 8268            }
 8269        };
 8270
 8271        let edits = edits
 8272            .into_iter()
 8273            .flat_map(|(range, new_text)| {
 8274                Some((
 8275                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8276                    new_text,
 8277                ))
 8278            })
 8279            .collect::<Vec<_>>();
 8280        if edits.is_empty() {
 8281            return None;
 8282        }
 8283
 8284        let first_edit_start = edits.first().unwrap().0.start;
 8285        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8286        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8287
 8288        let last_edit_end = edits.last().unwrap().0.end;
 8289        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8290        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8291
 8292        let cursor_row = cursor.to_point(&multibuffer).row;
 8293
 8294        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8295
 8296        let mut inlay_ids = Vec::new();
 8297        let invalidation_row_range;
 8298        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8299            Some(cursor_row..edit_end_row)
 8300        } else if cursor_row > edit_end_row {
 8301            Some(edit_start_row..cursor_row)
 8302        } else {
 8303            None
 8304        };
 8305        let supports_jump = self
 8306            .edit_prediction_provider
 8307            .as_ref()
 8308            .map(|provider| provider.provider.supports_jump_to_edit())
 8309            .unwrap_or(true);
 8310
 8311        let is_move = supports_jump
 8312            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8313        let completion = if is_move {
 8314            invalidation_row_range =
 8315                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8316            let target = first_edit_start;
 8317            EditPrediction::MoveWithin { target, snapshot }
 8318        } else {
 8319            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8320                && !self.edit_predictions_hidden_for_vim_mode;
 8321
 8322            if show_completions_in_buffer {
 8323                if let Some(provider) = &self.edit_prediction_provider {
 8324                    provider.provider.did_show(cx);
 8325                }
 8326                if edits
 8327                    .iter()
 8328                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8329                {
 8330                    let mut inlays = Vec::new();
 8331                    for (range, new_text) in &edits {
 8332                        let inlay = Inlay::edit_prediction(
 8333                            post_inc(&mut self.next_inlay_id),
 8334                            range.start,
 8335                            new_text.as_ref(),
 8336                        );
 8337                        inlay_ids.push(inlay.id);
 8338                        inlays.push(inlay);
 8339                    }
 8340
 8341                    self.splice_inlays(&[], inlays, cx);
 8342                } else {
 8343                    let background_color = cx.theme().status().deleted_background;
 8344                    self.highlight_text::<EditPredictionHighlight>(
 8345                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8346                        HighlightStyle {
 8347                            background_color: Some(background_color),
 8348                            ..Default::default()
 8349                        },
 8350                        cx,
 8351                    );
 8352                }
 8353            }
 8354
 8355            invalidation_row_range = edit_start_row..edit_end_row;
 8356
 8357            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8358                if provider.show_tab_accept_marker() {
 8359                    EditDisplayMode::TabAccept
 8360                } else {
 8361                    EditDisplayMode::Inline
 8362                }
 8363            } else {
 8364                EditDisplayMode::DiffPopover
 8365            };
 8366
 8367            EditPrediction::Edit {
 8368                edits,
 8369                edit_preview,
 8370                display_mode,
 8371                snapshot,
 8372            }
 8373        };
 8374
 8375        let invalidation_range = multibuffer
 8376            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8377            ..multibuffer.anchor_after(Point::new(
 8378                invalidation_row_range.end,
 8379                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8380            ));
 8381
 8382        self.stale_edit_prediction_in_menu = None;
 8383        self.active_edit_prediction = Some(EditPredictionState {
 8384            inlay_ids,
 8385            completion,
 8386            completion_id,
 8387            invalidation_range: Some(invalidation_range),
 8388        });
 8389
 8390        cx.notify();
 8391
 8392        Some(())
 8393    }
 8394
 8395    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8396        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8397    }
 8398
 8399    fn clear_tasks(&mut self) {
 8400        self.tasks.clear()
 8401    }
 8402
 8403    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8404        if self.tasks.insert(key, value).is_some() {
 8405            // This case should hopefully be rare, but just in case...
 8406            log::error!(
 8407                "multiple different run targets found on a single line, only the last target will be rendered"
 8408            )
 8409        }
 8410    }
 8411
 8412    /// Get all display points of breakpoints that will be rendered within editor
 8413    ///
 8414    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8415    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8416    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8417    fn active_breakpoints(
 8418        &self,
 8419        range: Range<DisplayRow>,
 8420        window: &mut Window,
 8421        cx: &mut Context<Self>,
 8422    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8423        let mut breakpoint_display_points = HashMap::default();
 8424
 8425        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8426            return breakpoint_display_points;
 8427        };
 8428
 8429        let snapshot = self.snapshot(window, cx);
 8430
 8431        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8432        let Some(project) = self.project() else {
 8433            return breakpoint_display_points;
 8434        };
 8435
 8436        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8437            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8438
 8439        for (buffer_snapshot, range, excerpt_id) in
 8440            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8441        {
 8442            let Some(buffer) = project
 8443                .read(cx)
 8444                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8445            else {
 8446                continue;
 8447            };
 8448            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8449                &buffer,
 8450                Some(
 8451                    buffer_snapshot.anchor_before(range.start)
 8452                        ..buffer_snapshot.anchor_after(range.end),
 8453                ),
 8454                buffer_snapshot,
 8455                cx,
 8456            );
 8457            for (breakpoint, state) in breakpoints {
 8458                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8459                let position = multi_buffer_anchor
 8460                    .to_point(&multi_buffer_snapshot)
 8461                    .to_display_point(&snapshot);
 8462
 8463                breakpoint_display_points.insert(
 8464                    position.row(),
 8465                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8466                );
 8467            }
 8468        }
 8469
 8470        breakpoint_display_points
 8471    }
 8472
 8473    fn breakpoint_context_menu(
 8474        &self,
 8475        anchor: Anchor,
 8476        window: &mut Window,
 8477        cx: &mut Context<Self>,
 8478    ) -> Entity<ui::ContextMenu> {
 8479        let weak_editor = cx.weak_entity();
 8480        let focus_handle = self.focus_handle(cx);
 8481
 8482        let row = self
 8483            .buffer
 8484            .read(cx)
 8485            .snapshot(cx)
 8486            .summary_for_anchor::<Point>(&anchor)
 8487            .row;
 8488
 8489        let breakpoint = self
 8490            .breakpoint_at_row(row, window, cx)
 8491            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8492
 8493        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8494            "Edit Log Breakpoint"
 8495        } else {
 8496            "Set Log Breakpoint"
 8497        };
 8498
 8499        let condition_breakpoint_msg = if breakpoint
 8500            .as_ref()
 8501            .is_some_and(|bp| bp.1.condition.is_some())
 8502        {
 8503            "Edit Condition Breakpoint"
 8504        } else {
 8505            "Set Condition Breakpoint"
 8506        };
 8507
 8508        let hit_condition_breakpoint_msg = if breakpoint
 8509            .as_ref()
 8510            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8511        {
 8512            "Edit Hit Condition Breakpoint"
 8513        } else {
 8514            "Set Hit Condition Breakpoint"
 8515        };
 8516
 8517        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8518            "Unset Breakpoint"
 8519        } else {
 8520            "Set Breakpoint"
 8521        };
 8522
 8523        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8524
 8525        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8526            BreakpointState::Enabled => Some("Disable"),
 8527            BreakpointState::Disabled => Some("Enable"),
 8528        });
 8529
 8530        let (anchor, breakpoint) =
 8531            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8532
 8533        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8534            menu.on_blur_subscription(Subscription::new(|| {}))
 8535                .context(focus_handle)
 8536                .when(run_to_cursor, |this| {
 8537                    let weak_editor = weak_editor.clone();
 8538                    this.entry("Run to cursor", None, move |window, cx| {
 8539                        weak_editor
 8540                            .update(cx, |editor, cx| {
 8541                                editor.change_selections(
 8542                                    SelectionEffects::no_scroll(),
 8543                                    window,
 8544                                    cx,
 8545                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8546                                );
 8547                            })
 8548                            .ok();
 8549
 8550                        window.dispatch_action(Box::new(RunToCursor), cx);
 8551                    })
 8552                    .separator()
 8553                })
 8554                .when_some(toggle_state_msg, |this, msg| {
 8555                    this.entry(msg, None, {
 8556                        let weak_editor = weak_editor.clone();
 8557                        let breakpoint = breakpoint.clone();
 8558                        move |_window, cx| {
 8559                            weak_editor
 8560                                .update(cx, |this, cx| {
 8561                                    this.edit_breakpoint_at_anchor(
 8562                                        anchor,
 8563                                        breakpoint.as_ref().clone(),
 8564                                        BreakpointEditAction::InvertState,
 8565                                        cx,
 8566                                    );
 8567                                })
 8568                                .log_err();
 8569                        }
 8570                    })
 8571                })
 8572                .entry(set_breakpoint_msg, None, {
 8573                    let weak_editor = weak_editor.clone();
 8574                    let breakpoint = breakpoint.clone();
 8575                    move |_window, cx| {
 8576                        weak_editor
 8577                            .update(cx, |this, cx| {
 8578                                this.edit_breakpoint_at_anchor(
 8579                                    anchor,
 8580                                    breakpoint.as_ref().clone(),
 8581                                    BreakpointEditAction::Toggle,
 8582                                    cx,
 8583                                );
 8584                            })
 8585                            .log_err();
 8586                    }
 8587                })
 8588                .entry(log_breakpoint_msg, None, {
 8589                    let breakpoint = breakpoint.clone();
 8590                    let weak_editor = weak_editor.clone();
 8591                    move |window, cx| {
 8592                        weak_editor
 8593                            .update(cx, |this, cx| {
 8594                                this.add_edit_breakpoint_block(
 8595                                    anchor,
 8596                                    breakpoint.as_ref(),
 8597                                    BreakpointPromptEditAction::Log,
 8598                                    window,
 8599                                    cx,
 8600                                );
 8601                            })
 8602                            .log_err();
 8603                    }
 8604                })
 8605                .entry(condition_breakpoint_msg, None, {
 8606                    let breakpoint = breakpoint.clone();
 8607                    let weak_editor = weak_editor.clone();
 8608                    move |window, cx| {
 8609                        weak_editor
 8610                            .update(cx, |this, cx| {
 8611                                this.add_edit_breakpoint_block(
 8612                                    anchor,
 8613                                    breakpoint.as_ref(),
 8614                                    BreakpointPromptEditAction::Condition,
 8615                                    window,
 8616                                    cx,
 8617                                );
 8618                            })
 8619                            .log_err();
 8620                    }
 8621                })
 8622                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8623                    weak_editor
 8624                        .update(cx, |this, cx| {
 8625                            this.add_edit_breakpoint_block(
 8626                                anchor,
 8627                                breakpoint.as_ref(),
 8628                                BreakpointPromptEditAction::HitCondition,
 8629                                window,
 8630                                cx,
 8631                            );
 8632                        })
 8633                        .log_err();
 8634                })
 8635        })
 8636    }
 8637
 8638    fn render_breakpoint(
 8639        &self,
 8640        position: Anchor,
 8641        row: DisplayRow,
 8642        breakpoint: &Breakpoint,
 8643        state: Option<BreakpointSessionState>,
 8644        cx: &mut Context<Self>,
 8645    ) -> IconButton {
 8646        let is_rejected = state.is_some_and(|s| !s.verified);
 8647        // Is it a breakpoint that shows up when hovering over gutter?
 8648        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8649            (false, false),
 8650            |PhantomBreakpointIndicator {
 8651                 is_active,
 8652                 display_row,
 8653                 collides_with_existing_breakpoint,
 8654             }| {
 8655                (
 8656                    is_active && display_row == row,
 8657                    collides_with_existing_breakpoint,
 8658                )
 8659            },
 8660        );
 8661
 8662        let (color, icon) = {
 8663            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8664                (false, false) => ui::IconName::DebugBreakpoint,
 8665                (true, false) => ui::IconName::DebugLogBreakpoint,
 8666                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8667                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8668            };
 8669
 8670            let color = cx.theme().colors();
 8671
 8672            let color = if is_phantom {
 8673                if collides_with_existing {
 8674                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8675                } else {
 8676                    Color::Hint
 8677                }
 8678            } else if is_rejected {
 8679                Color::Disabled
 8680            } else {
 8681                Color::Debugger
 8682            };
 8683
 8684            (color, icon)
 8685        };
 8686
 8687        let breakpoint = Arc::from(breakpoint.clone());
 8688
 8689        let alt_as_text = gpui::Keystroke {
 8690            modifiers: Modifiers::secondary_key(),
 8691            ..Default::default()
 8692        };
 8693        let primary_action_text = if breakpoint.is_disabled() {
 8694            "Enable breakpoint"
 8695        } else if is_phantom && !collides_with_existing {
 8696            "Set breakpoint"
 8697        } else {
 8698            "Unset breakpoint"
 8699        };
 8700        let focus_handle = self.focus_handle.clone();
 8701
 8702        let meta = if is_rejected {
 8703            SharedString::from("No executable code is associated with this line.")
 8704        } else if collides_with_existing && !breakpoint.is_disabled() {
 8705            SharedString::from(format!(
 8706                "{alt_as_text}-click to disable,\nright-click for more options."
 8707            ))
 8708        } else {
 8709            SharedString::from("Right-click for more options.")
 8710        };
 8711        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8712            .icon_size(IconSize::XSmall)
 8713            .size(ui::ButtonSize::None)
 8714            .when(is_rejected, |this| {
 8715                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8716            })
 8717            .icon_color(color)
 8718            .style(ButtonStyle::Transparent)
 8719            .on_click(cx.listener({
 8720                move |editor, event: &ClickEvent, window, cx| {
 8721                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8722                        BreakpointEditAction::InvertState
 8723                    } else {
 8724                        BreakpointEditAction::Toggle
 8725                    };
 8726
 8727                    window.focus(&editor.focus_handle(cx));
 8728                    editor.edit_breakpoint_at_anchor(
 8729                        position,
 8730                        breakpoint.as_ref().clone(),
 8731                        edit_action,
 8732                        cx,
 8733                    );
 8734                }
 8735            }))
 8736            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8737                editor.set_breakpoint_context_menu(
 8738                    row,
 8739                    Some(position),
 8740                    event.position(),
 8741                    window,
 8742                    cx,
 8743                );
 8744            }))
 8745            .tooltip(move |_window, cx| {
 8746                Tooltip::with_meta_in(
 8747                    primary_action_text,
 8748                    Some(&ToggleBreakpoint),
 8749                    meta.clone(),
 8750                    &focus_handle,
 8751                    cx,
 8752                )
 8753            })
 8754    }
 8755
 8756    fn build_tasks_context(
 8757        project: &Entity<Project>,
 8758        buffer: &Entity<Buffer>,
 8759        buffer_row: u32,
 8760        tasks: &Arc<RunnableTasks>,
 8761        cx: &mut Context<Self>,
 8762    ) -> Task<Option<task::TaskContext>> {
 8763        let position = Point::new(buffer_row, tasks.column);
 8764        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8765        let location = Location {
 8766            buffer: buffer.clone(),
 8767            range: range_start..range_start,
 8768        };
 8769        // Fill in the environmental variables from the tree-sitter captures
 8770        let mut captured_task_variables = TaskVariables::default();
 8771        for (capture_name, value) in tasks.extra_variables.clone() {
 8772            captured_task_variables.insert(
 8773                task::VariableName::Custom(capture_name.into()),
 8774                value.clone(),
 8775            );
 8776        }
 8777        project.update(cx, |project, cx| {
 8778            project.task_store().update(cx, |task_store, cx| {
 8779                task_store.task_context_for_location(captured_task_variables, location, cx)
 8780            })
 8781        })
 8782    }
 8783
 8784    pub fn spawn_nearest_task(
 8785        &mut self,
 8786        action: &SpawnNearestTask,
 8787        window: &mut Window,
 8788        cx: &mut Context<Self>,
 8789    ) {
 8790        let Some((workspace, _)) = self.workspace.clone() else {
 8791            return;
 8792        };
 8793        let Some(project) = self.project.clone() else {
 8794            return;
 8795        };
 8796
 8797        // Try to find a closest, enclosing node using tree-sitter that has a task
 8798        let Some((buffer, buffer_row, tasks)) = self
 8799            .find_enclosing_node_task(cx)
 8800            // Or find the task that's closest in row-distance.
 8801            .or_else(|| self.find_closest_task(cx))
 8802        else {
 8803            return;
 8804        };
 8805
 8806        let reveal_strategy = action.reveal;
 8807        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8808        cx.spawn_in(window, async move |_, cx| {
 8809            let context = task_context.await?;
 8810            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8811
 8812            let resolved = &mut resolved_task.resolved;
 8813            resolved.reveal = reveal_strategy;
 8814
 8815            workspace
 8816                .update_in(cx, |workspace, window, cx| {
 8817                    workspace.schedule_resolved_task(
 8818                        task_source_kind,
 8819                        resolved_task,
 8820                        false,
 8821                        window,
 8822                        cx,
 8823                    );
 8824                })
 8825                .ok()
 8826        })
 8827        .detach();
 8828    }
 8829
 8830    fn find_closest_task(
 8831        &mut self,
 8832        cx: &mut Context<Self>,
 8833    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8834        let cursor_row = self
 8835            .selections
 8836            .newest_adjusted(&self.display_snapshot(cx))
 8837            .head()
 8838            .row;
 8839
 8840        let ((buffer_id, row), tasks) = self
 8841            .tasks
 8842            .iter()
 8843            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8844
 8845        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8846        let tasks = Arc::new(tasks.to_owned());
 8847        Some((buffer, *row, tasks))
 8848    }
 8849
 8850    fn find_enclosing_node_task(
 8851        &mut self,
 8852        cx: &mut Context<Self>,
 8853    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8854        let snapshot = self.buffer.read(cx).snapshot(cx);
 8855        let offset = self
 8856            .selections
 8857            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8858            .head();
 8859        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8860        let offset = excerpt.map_offset_to_buffer(offset);
 8861        let buffer_id = excerpt.buffer().remote_id();
 8862
 8863        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8864        let mut cursor = layer.node().walk();
 8865
 8866        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8867            if cursor.node().end_byte() == offset.0 {
 8868                cursor.goto_next_sibling();
 8869            }
 8870        }
 8871
 8872        // Ascend to the smallest ancestor that contains the range and has a task.
 8873        loop {
 8874            let node = cursor.node();
 8875            let node_range = node.byte_range();
 8876            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8877
 8878            // Check if this node contains our offset
 8879            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8880                // If it contains offset, check for task
 8881                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8882                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8883                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8884                }
 8885            }
 8886
 8887            if !cursor.goto_parent() {
 8888                break;
 8889            }
 8890        }
 8891        None
 8892    }
 8893
 8894    fn render_run_indicator(
 8895        &self,
 8896        _style: &EditorStyle,
 8897        is_active: bool,
 8898        row: DisplayRow,
 8899        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8900        cx: &mut Context<Self>,
 8901    ) -> IconButton {
 8902        let color = Color::Muted;
 8903        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8904
 8905        IconButton::new(
 8906            ("run_indicator", row.0 as usize),
 8907            ui::IconName::PlayOutlined,
 8908        )
 8909        .shape(ui::IconButtonShape::Square)
 8910        .icon_size(IconSize::XSmall)
 8911        .icon_color(color)
 8912        .toggle_state(is_active)
 8913        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8914            let quick_launch = match e {
 8915                ClickEvent::Keyboard(_) => true,
 8916                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8917            };
 8918
 8919            window.focus(&editor.focus_handle(cx));
 8920            editor.toggle_code_actions(
 8921                &ToggleCodeActions {
 8922                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8923                    quick_launch,
 8924                },
 8925                window,
 8926                cx,
 8927            );
 8928        }))
 8929        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8930            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8931        }))
 8932    }
 8933
 8934    pub fn context_menu_visible(&self) -> bool {
 8935        !self.edit_prediction_preview_is_active()
 8936            && self
 8937                .context_menu
 8938                .borrow()
 8939                .as_ref()
 8940                .is_some_and(|menu| menu.visible())
 8941    }
 8942
 8943    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8944        self.context_menu
 8945            .borrow()
 8946            .as_ref()
 8947            .map(|menu| menu.origin())
 8948    }
 8949
 8950    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8951        self.context_menu_options = Some(options);
 8952    }
 8953
 8954    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8955    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8956
 8957    fn render_edit_prediction_popover(
 8958        &mut self,
 8959        text_bounds: &Bounds<Pixels>,
 8960        content_origin: gpui::Point<Pixels>,
 8961        right_margin: Pixels,
 8962        editor_snapshot: &EditorSnapshot,
 8963        visible_row_range: Range<DisplayRow>,
 8964        scroll_top: ScrollOffset,
 8965        scroll_bottom: ScrollOffset,
 8966        line_layouts: &[LineWithInvisibles],
 8967        line_height: Pixels,
 8968        scroll_position: gpui::Point<ScrollOffset>,
 8969        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8970        newest_selection_head: Option<DisplayPoint>,
 8971        editor_width: Pixels,
 8972        style: &EditorStyle,
 8973        window: &mut Window,
 8974        cx: &mut App,
 8975    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8976        if self.mode().is_minimap() {
 8977            return None;
 8978        }
 8979        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8980
 8981        if self.edit_prediction_visible_in_cursor_popover(true) {
 8982            return None;
 8983        }
 8984
 8985        match &active_edit_prediction.completion {
 8986            EditPrediction::MoveWithin { target, .. } => {
 8987                let target_display_point = target.to_display_point(editor_snapshot);
 8988
 8989                if self.edit_prediction_requires_modifier() {
 8990                    if !self.edit_prediction_preview_is_active() {
 8991                        return None;
 8992                    }
 8993
 8994                    self.render_edit_prediction_modifier_jump_popover(
 8995                        text_bounds,
 8996                        content_origin,
 8997                        visible_row_range,
 8998                        line_layouts,
 8999                        line_height,
 9000                        scroll_pixel_position,
 9001                        newest_selection_head,
 9002                        target_display_point,
 9003                        window,
 9004                        cx,
 9005                    )
 9006                } else {
 9007                    self.render_edit_prediction_eager_jump_popover(
 9008                        text_bounds,
 9009                        content_origin,
 9010                        editor_snapshot,
 9011                        visible_row_range,
 9012                        scroll_top,
 9013                        scroll_bottom,
 9014                        line_height,
 9015                        scroll_pixel_position,
 9016                        target_display_point,
 9017                        editor_width,
 9018                        window,
 9019                        cx,
 9020                    )
 9021                }
 9022            }
 9023            EditPrediction::Edit {
 9024                display_mode: EditDisplayMode::Inline,
 9025                ..
 9026            } => None,
 9027            EditPrediction::Edit {
 9028                display_mode: EditDisplayMode::TabAccept,
 9029                edits,
 9030                ..
 9031            } => {
 9032                let range = &edits.first()?.0;
 9033                let target_display_point = range.end.to_display_point(editor_snapshot);
 9034
 9035                self.render_edit_prediction_end_of_line_popover(
 9036                    "Accept",
 9037                    editor_snapshot,
 9038                    visible_row_range,
 9039                    target_display_point,
 9040                    line_height,
 9041                    scroll_pixel_position,
 9042                    content_origin,
 9043                    editor_width,
 9044                    window,
 9045                    cx,
 9046                )
 9047            }
 9048            EditPrediction::Edit {
 9049                edits,
 9050                edit_preview,
 9051                display_mode: EditDisplayMode::DiffPopover,
 9052                snapshot,
 9053            } => self.render_edit_prediction_diff_popover(
 9054                text_bounds,
 9055                content_origin,
 9056                right_margin,
 9057                editor_snapshot,
 9058                visible_row_range,
 9059                line_layouts,
 9060                line_height,
 9061                scroll_position,
 9062                scroll_pixel_position,
 9063                newest_selection_head,
 9064                editor_width,
 9065                style,
 9066                edits,
 9067                edit_preview,
 9068                snapshot,
 9069                window,
 9070                cx,
 9071            ),
 9072            EditPrediction::MoveOutside { snapshot, .. } => {
 9073                let mut element = self
 9074                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9075                    .into_any();
 9076
 9077                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9078                let origin_x = text_bounds.size.width - size.width - px(30.);
 9079                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9080                element.prepaint_at(origin, window, cx);
 9081
 9082                Some((element, origin))
 9083            }
 9084        }
 9085    }
 9086
 9087    fn render_edit_prediction_modifier_jump_popover(
 9088        &mut self,
 9089        text_bounds: &Bounds<Pixels>,
 9090        content_origin: gpui::Point<Pixels>,
 9091        visible_row_range: Range<DisplayRow>,
 9092        line_layouts: &[LineWithInvisibles],
 9093        line_height: Pixels,
 9094        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9095        newest_selection_head: Option<DisplayPoint>,
 9096        target_display_point: DisplayPoint,
 9097        window: &mut Window,
 9098        cx: &mut App,
 9099    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9100        let scrolled_content_origin =
 9101            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9102
 9103        const SCROLL_PADDING_Y: Pixels = px(12.);
 9104
 9105        if target_display_point.row() < visible_row_range.start {
 9106            return self.render_edit_prediction_scroll_popover(
 9107                |_| SCROLL_PADDING_Y,
 9108                IconName::ArrowUp,
 9109                visible_row_range,
 9110                line_layouts,
 9111                newest_selection_head,
 9112                scrolled_content_origin,
 9113                window,
 9114                cx,
 9115            );
 9116        } else if target_display_point.row() >= visible_row_range.end {
 9117            return self.render_edit_prediction_scroll_popover(
 9118                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9119                IconName::ArrowDown,
 9120                visible_row_range,
 9121                line_layouts,
 9122                newest_selection_head,
 9123                scrolled_content_origin,
 9124                window,
 9125                cx,
 9126            );
 9127        }
 9128
 9129        const POLE_WIDTH: Pixels = px(2.);
 9130
 9131        let line_layout =
 9132            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9133        let target_column = target_display_point.column() as usize;
 9134
 9135        let target_x = line_layout.x_for_index(target_column);
 9136        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9137            - scroll_pixel_position.y;
 9138
 9139        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9140
 9141        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9142        border_color.l += 0.001;
 9143
 9144        let mut element = v_flex()
 9145            .items_end()
 9146            .when(flag_on_right, |el| el.items_start())
 9147            .child(if flag_on_right {
 9148                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9149                    .rounded_bl(px(0.))
 9150                    .rounded_tl(px(0.))
 9151                    .border_l_2()
 9152                    .border_color(border_color)
 9153            } else {
 9154                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9155                    .rounded_br(px(0.))
 9156                    .rounded_tr(px(0.))
 9157                    .border_r_2()
 9158                    .border_color(border_color)
 9159            })
 9160            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9161            .into_any();
 9162
 9163        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9164
 9165        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9166            - point(
 9167                if flag_on_right {
 9168                    POLE_WIDTH
 9169                } else {
 9170                    size.width - POLE_WIDTH
 9171                },
 9172                size.height - line_height,
 9173            );
 9174
 9175        origin.x = origin.x.max(content_origin.x);
 9176
 9177        element.prepaint_at(origin, window, cx);
 9178
 9179        Some((element, origin))
 9180    }
 9181
 9182    fn render_edit_prediction_scroll_popover(
 9183        &mut self,
 9184        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9185        scroll_icon: IconName,
 9186        visible_row_range: Range<DisplayRow>,
 9187        line_layouts: &[LineWithInvisibles],
 9188        newest_selection_head: Option<DisplayPoint>,
 9189        scrolled_content_origin: gpui::Point<Pixels>,
 9190        window: &mut Window,
 9191        cx: &mut App,
 9192    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9193        let mut element = self
 9194            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9195            .into_any();
 9196
 9197        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9198
 9199        let cursor = newest_selection_head?;
 9200        let cursor_row_layout =
 9201            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9202        let cursor_column = cursor.column() as usize;
 9203
 9204        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9205
 9206        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9207
 9208        element.prepaint_at(origin, window, cx);
 9209        Some((element, origin))
 9210    }
 9211
 9212    fn render_edit_prediction_eager_jump_popover(
 9213        &mut self,
 9214        text_bounds: &Bounds<Pixels>,
 9215        content_origin: gpui::Point<Pixels>,
 9216        editor_snapshot: &EditorSnapshot,
 9217        visible_row_range: Range<DisplayRow>,
 9218        scroll_top: ScrollOffset,
 9219        scroll_bottom: ScrollOffset,
 9220        line_height: Pixels,
 9221        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9222        target_display_point: DisplayPoint,
 9223        editor_width: Pixels,
 9224        window: &mut Window,
 9225        cx: &mut App,
 9226    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9227        if target_display_point.row().as_f64() < scroll_top {
 9228            let mut element = self
 9229                .render_edit_prediction_line_popover(
 9230                    "Jump to Edit",
 9231                    Some(IconName::ArrowUp),
 9232                    window,
 9233                    cx,
 9234                )
 9235                .into_any();
 9236
 9237            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9238            let offset = point(
 9239                (text_bounds.size.width - size.width) / 2.,
 9240                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9241            );
 9242
 9243            let origin = text_bounds.origin + offset;
 9244            element.prepaint_at(origin, window, cx);
 9245            Some((element, origin))
 9246        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9247            let mut element = self
 9248                .render_edit_prediction_line_popover(
 9249                    "Jump to Edit",
 9250                    Some(IconName::ArrowDown),
 9251                    window,
 9252                    cx,
 9253                )
 9254                .into_any();
 9255
 9256            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9257            let offset = point(
 9258                (text_bounds.size.width - size.width) / 2.,
 9259                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9260            );
 9261
 9262            let origin = text_bounds.origin + offset;
 9263            element.prepaint_at(origin, window, cx);
 9264            Some((element, origin))
 9265        } else {
 9266            self.render_edit_prediction_end_of_line_popover(
 9267                "Jump to Edit",
 9268                editor_snapshot,
 9269                visible_row_range,
 9270                target_display_point,
 9271                line_height,
 9272                scroll_pixel_position,
 9273                content_origin,
 9274                editor_width,
 9275                window,
 9276                cx,
 9277            )
 9278        }
 9279    }
 9280
 9281    fn render_edit_prediction_end_of_line_popover(
 9282        self: &mut Editor,
 9283        label: &'static str,
 9284        editor_snapshot: &EditorSnapshot,
 9285        visible_row_range: Range<DisplayRow>,
 9286        target_display_point: DisplayPoint,
 9287        line_height: Pixels,
 9288        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9289        content_origin: gpui::Point<Pixels>,
 9290        editor_width: Pixels,
 9291        window: &mut Window,
 9292        cx: &mut App,
 9293    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9294        let target_line_end = DisplayPoint::new(
 9295            target_display_point.row(),
 9296            editor_snapshot.line_len(target_display_point.row()),
 9297        );
 9298
 9299        let mut element = self
 9300            .render_edit_prediction_line_popover(label, None, window, cx)
 9301            .into_any();
 9302
 9303        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9304
 9305        let line_origin =
 9306            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9307
 9308        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9309        let mut origin = start_point
 9310            + line_origin
 9311            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9312        origin.x = origin.x.max(content_origin.x);
 9313
 9314        let max_x = content_origin.x + editor_width - size.width;
 9315
 9316        if origin.x > max_x {
 9317            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9318
 9319            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9320                origin.y += offset;
 9321                IconName::ArrowUp
 9322            } else {
 9323                origin.y -= offset;
 9324                IconName::ArrowDown
 9325            };
 9326
 9327            element = self
 9328                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9329                .into_any();
 9330
 9331            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9332
 9333            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9334        }
 9335
 9336        element.prepaint_at(origin, window, cx);
 9337        Some((element, origin))
 9338    }
 9339
 9340    fn render_edit_prediction_diff_popover(
 9341        self: &Editor,
 9342        text_bounds: &Bounds<Pixels>,
 9343        content_origin: gpui::Point<Pixels>,
 9344        right_margin: Pixels,
 9345        editor_snapshot: &EditorSnapshot,
 9346        visible_row_range: Range<DisplayRow>,
 9347        line_layouts: &[LineWithInvisibles],
 9348        line_height: Pixels,
 9349        scroll_position: gpui::Point<ScrollOffset>,
 9350        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9351        newest_selection_head: Option<DisplayPoint>,
 9352        editor_width: Pixels,
 9353        style: &EditorStyle,
 9354        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9355        edit_preview: &Option<language::EditPreview>,
 9356        snapshot: &language::BufferSnapshot,
 9357        window: &mut Window,
 9358        cx: &mut App,
 9359    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9360        let edit_start = edits
 9361            .first()
 9362            .unwrap()
 9363            .0
 9364            .start
 9365            .to_display_point(editor_snapshot);
 9366        let edit_end = edits
 9367            .last()
 9368            .unwrap()
 9369            .0
 9370            .end
 9371            .to_display_point(editor_snapshot);
 9372
 9373        let is_visible = visible_row_range.contains(&edit_start.row())
 9374            || visible_row_range.contains(&edit_end.row());
 9375        if !is_visible {
 9376            return None;
 9377        }
 9378
 9379        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9380            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9381        } else {
 9382            // Fallback for providers without edit_preview
 9383            crate::edit_prediction_fallback_text(edits, cx)
 9384        };
 9385
 9386        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9387        let line_count = highlighted_edits.text.lines().count();
 9388
 9389        const BORDER_WIDTH: Pixels = px(1.);
 9390
 9391        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9392        let has_keybind = keybind.is_some();
 9393
 9394        let mut element = h_flex()
 9395            .items_start()
 9396            .child(
 9397                h_flex()
 9398                    .bg(cx.theme().colors().editor_background)
 9399                    .border(BORDER_WIDTH)
 9400                    .shadow_xs()
 9401                    .border_color(cx.theme().colors().border)
 9402                    .rounded_l_lg()
 9403                    .when(line_count > 1, |el| el.rounded_br_lg())
 9404                    .pr_1()
 9405                    .child(styled_text),
 9406            )
 9407            .child(
 9408                h_flex()
 9409                    .h(line_height + BORDER_WIDTH * 2.)
 9410                    .px_1p5()
 9411                    .gap_1()
 9412                    // Workaround: For some reason, there's a gap if we don't do this
 9413                    .ml(-BORDER_WIDTH)
 9414                    .shadow(vec![gpui::BoxShadow {
 9415                        color: gpui::black().opacity(0.05),
 9416                        offset: point(px(1.), px(1.)),
 9417                        blur_radius: px(2.),
 9418                        spread_radius: px(0.),
 9419                    }])
 9420                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9421                    .border(BORDER_WIDTH)
 9422                    .border_color(cx.theme().colors().border)
 9423                    .rounded_r_lg()
 9424                    .id("edit_prediction_diff_popover_keybind")
 9425                    .when(!has_keybind, |el| {
 9426                        let status_colors = cx.theme().status();
 9427
 9428                        el.bg(status_colors.error_background)
 9429                            .border_color(status_colors.error.opacity(0.6))
 9430                            .child(Icon::new(IconName::Info).color(Color::Error))
 9431                            .cursor_default()
 9432                            .hoverable_tooltip(move |_window, cx| {
 9433                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9434                            })
 9435                    })
 9436                    .children(keybind),
 9437            )
 9438            .into_any();
 9439
 9440        let longest_row =
 9441            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9442        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9443            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9444        } else {
 9445            layout_line(
 9446                longest_row,
 9447                editor_snapshot,
 9448                style,
 9449                editor_width,
 9450                |_| false,
 9451                window,
 9452                cx,
 9453            )
 9454            .width
 9455        };
 9456
 9457        let viewport_bounds =
 9458            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9459                right: -right_margin,
 9460                ..Default::default()
 9461            });
 9462
 9463        let x_after_longest = Pixels::from(
 9464            ScrollPixelOffset::from(
 9465                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9466            ) - scroll_pixel_position.x,
 9467        );
 9468
 9469        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9470
 9471        // Fully visible if it can be displayed within the window (allow overlapping other
 9472        // panes). However, this is only allowed if the popover starts within text_bounds.
 9473        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9474            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9475
 9476        let mut origin = if can_position_to_the_right {
 9477            point(
 9478                x_after_longest,
 9479                text_bounds.origin.y
 9480                    + Pixels::from(
 9481                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9482                            - scroll_pixel_position.y,
 9483                    ),
 9484            )
 9485        } else {
 9486            let cursor_row = newest_selection_head.map(|head| head.row());
 9487            let above_edit = edit_start
 9488                .row()
 9489                .0
 9490                .checked_sub(line_count as u32)
 9491                .map(DisplayRow);
 9492            let below_edit = Some(edit_end.row() + 1);
 9493            let above_cursor =
 9494                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9495            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9496
 9497            // Place the edit popover adjacent to the edit if there is a location
 9498            // available that is onscreen and does not obscure the cursor. Otherwise,
 9499            // place it adjacent to the cursor.
 9500            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9501                .into_iter()
 9502                .flatten()
 9503                .find(|&start_row| {
 9504                    let end_row = start_row + line_count as u32;
 9505                    visible_row_range.contains(&start_row)
 9506                        && visible_row_range.contains(&end_row)
 9507                        && cursor_row
 9508                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9509                })?;
 9510
 9511            content_origin
 9512                + point(
 9513                    Pixels::from(-scroll_pixel_position.x),
 9514                    Pixels::from(
 9515                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9516                    ),
 9517                )
 9518        };
 9519
 9520        origin.x -= BORDER_WIDTH;
 9521
 9522        window.defer_draw(element, origin, 1);
 9523
 9524        // Do not return an element, since it will already be drawn due to defer_draw.
 9525        None
 9526    }
 9527
 9528    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9529        px(30.)
 9530    }
 9531
 9532    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9533        if self.read_only(cx) {
 9534            cx.theme().players().read_only()
 9535        } else {
 9536            self.style.as_ref().unwrap().local_player
 9537        }
 9538    }
 9539
 9540    fn render_edit_prediction_accept_keybind(
 9541        &self,
 9542        window: &mut Window,
 9543        cx: &mut App,
 9544    ) -> Option<AnyElement> {
 9545        let accept_binding =
 9546            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9547        let accept_keystroke = accept_binding.keystroke()?;
 9548
 9549        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9550
 9551        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9552            Color::Accent
 9553        } else {
 9554            Color::Muted
 9555        };
 9556
 9557        h_flex()
 9558            .px_0p5()
 9559            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9560            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9561            .text_size(TextSize::XSmall.rems(cx))
 9562            .child(h_flex().children(ui::render_modifiers(
 9563                accept_keystroke.modifiers(),
 9564                PlatformStyle::platform(),
 9565                Some(modifiers_color),
 9566                Some(IconSize::XSmall.rems().into()),
 9567                true,
 9568            )))
 9569            .when(is_platform_style_mac, |parent| {
 9570                parent.child(accept_keystroke.key().to_string())
 9571            })
 9572            .when(!is_platform_style_mac, |parent| {
 9573                parent.child(
 9574                    Key::new(
 9575                        util::capitalize(accept_keystroke.key()),
 9576                        Some(Color::Default),
 9577                    )
 9578                    .size(Some(IconSize::XSmall.rems().into())),
 9579                )
 9580            })
 9581            .into_any()
 9582            .into()
 9583    }
 9584
 9585    fn render_edit_prediction_line_popover(
 9586        &self,
 9587        label: impl Into<SharedString>,
 9588        icon: Option<IconName>,
 9589        window: &mut Window,
 9590        cx: &mut App,
 9591    ) -> Stateful<Div> {
 9592        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9593
 9594        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9595        let has_keybind = keybind.is_some();
 9596
 9597        h_flex()
 9598            .id("ep-line-popover")
 9599            .py_0p5()
 9600            .pl_1()
 9601            .pr(padding_right)
 9602            .gap_1()
 9603            .rounded_md()
 9604            .border_1()
 9605            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9606            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9607            .shadow_xs()
 9608            .when(!has_keybind, |el| {
 9609                let status_colors = cx.theme().status();
 9610
 9611                el.bg(status_colors.error_background)
 9612                    .border_color(status_colors.error.opacity(0.6))
 9613                    .pl_2()
 9614                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9615                    .cursor_default()
 9616                    .hoverable_tooltip(move |_window, cx| {
 9617                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9618                    })
 9619            })
 9620            .children(keybind)
 9621            .child(
 9622                Label::new(label)
 9623                    .size(LabelSize::Small)
 9624                    .when(!has_keybind, |el| {
 9625                        el.color(cx.theme().status().error.into()).strikethrough()
 9626                    }),
 9627            )
 9628            .when(!has_keybind, |el| {
 9629                el.child(
 9630                    h_flex().ml_1().child(
 9631                        Icon::new(IconName::Info)
 9632                            .size(IconSize::Small)
 9633                            .color(cx.theme().status().error.into()),
 9634                    ),
 9635                )
 9636            })
 9637            .when_some(icon, |element, icon| {
 9638                element.child(
 9639                    div()
 9640                        .mt(px(1.5))
 9641                        .child(Icon::new(icon).size(IconSize::Small)),
 9642                )
 9643            })
 9644    }
 9645
 9646    fn render_edit_prediction_jump_outside_popover(
 9647        &self,
 9648        snapshot: &BufferSnapshot,
 9649        window: &mut Window,
 9650        cx: &mut App,
 9651    ) -> Stateful<Div> {
 9652        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9653        let has_keybind = keybind.is_some();
 9654
 9655        let file_name = snapshot
 9656            .file()
 9657            .map(|file| SharedString::new(file.file_name(cx)))
 9658            .unwrap_or(SharedString::new_static("untitled"));
 9659
 9660        h_flex()
 9661            .id("ep-jump-outside-popover")
 9662            .py_1()
 9663            .px_2()
 9664            .gap_1()
 9665            .rounded_md()
 9666            .border_1()
 9667            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9668            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9669            .shadow_xs()
 9670            .when(!has_keybind, |el| {
 9671                let status_colors = cx.theme().status();
 9672
 9673                el.bg(status_colors.error_background)
 9674                    .border_color(status_colors.error.opacity(0.6))
 9675                    .pl_2()
 9676                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9677                    .cursor_default()
 9678                    .hoverable_tooltip(move |_window, cx| {
 9679                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9680                    })
 9681            })
 9682            .children(keybind)
 9683            .child(
 9684                Label::new(file_name)
 9685                    .size(LabelSize::Small)
 9686                    .buffer_font(cx)
 9687                    .when(!has_keybind, |el| {
 9688                        el.color(cx.theme().status().error.into()).strikethrough()
 9689                    }),
 9690            )
 9691            .when(!has_keybind, |el| {
 9692                el.child(
 9693                    h_flex().ml_1().child(
 9694                        Icon::new(IconName::Info)
 9695                            .size(IconSize::Small)
 9696                            .color(cx.theme().status().error.into()),
 9697                    ),
 9698                )
 9699            })
 9700            .child(
 9701                div()
 9702                    .mt(px(1.5))
 9703                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9704            )
 9705    }
 9706
 9707    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9708        let accent_color = cx.theme().colors().text_accent;
 9709        let editor_bg_color = cx.theme().colors().editor_background;
 9710        editor_bg_color.blend(accent_color.opacity(0.1))
 9711    }
 9712
 9713    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9714        let accent_color = cx.theme().colors().text_accent;
 9715        let editor_bg_color = cx.theme().colors().editor_background;
 9716        editor_bg_color.blend(accent_color.opacity(0.6))
 9717    }
 9718    fn get_prediction_provider_icon_name(
 9719        provider: &Option<RegisteredEditPredictionDelegate>,
 9720    ) -> IconName {
 9721        match provider {
 9722            Some(provider) => match provider.provider.name() {
 9723                "copilot" => IconName::Copilot,
 9724                "supermaven" => IconName::Supermaven,
 9725                _ => IconName::ZedPredict,
 9726            },
 9727            None => IconName::ZedPredict,
 9728        }
 9729    }
 9730
 9731    fn render_edit_prediction_cursor_popover(
 9732        &self,
 9733        min_width: Pixels,
 9734        max_width: Pixels,
 9735        cursor_point: Point,
 9736        style: &EditorStyle,
 9737        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9738        _window: &Window,
 9739        cx: &mut Context<Editor>,
 9740    ) -> Option<AnyElement> {
 9741        let provider = self.edit_prediction_provider.as_ref()?;
 9742        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9743
 9744        let is_refreshing = provider.provider.is_refreshing(cx);
 9745
 9746        fn pending_completion_container(icon: IconName) -> Div {
 9747            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9748        }
 9749
 9750        let completion = match &self.active_edit_prediction {
 9751            Some(prediction) => {
 9752                if !self.has_visible_completions_menu() {
 9753                    const RADIUS: Pixels = px(6.);
 9754                    const BORDER_WIDTH: Pixels = px(1.);
 9755
 9756                    return Some(
 9757                        h_flex()
 9758                            .elevation_2(cx)
 9759                            .border(BORDER_WIDTH)
 9760                            .border_color(cx.theme().colors().border)
 9761                            .when(accept_keystroke.is_none(), |el| {
 9762                                el.border_color(cx.theme().status().error)
 9763                            })
 9764                            .rounded(RADIUS)
 9765                            .rounded_tl(px(0.))
 9766                            .overflow_hidden()
 9767                            .child(div().px_1p5().child(match &prediction.completion {
 9768                                EditPrediction::MoveWithin { target, snapshot } => {
 9769                                    use text::ToPoint as _;
 9770                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9771                                    {
 9772                                        Icon::new(IconName::ZedPredictDown)
 9773                                    } else {
 9774                                        Icon::new(IconName::ZedPredictUp)
 9775                                    }
 9776                                }
 9777                                EditPrediction::MoveOutside { .. } => {
 9778                                    // TODO [zeta2] custom icon for external jump?
 9779                                    Icon::new(provider_icon)
 9780                                }
 9781                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9782                            }))
 9783                            .child(
 9784                                h_flex()
 9785                                    .gap_1()
 9786                                    .py_1()
 9787                                    .px_2()
 9788                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9789                                    .border_l_1()
 9790                                    .border_color(cx.theme().colors().border)
 9791                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9792                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9793                                        el.child(
 9794                                            Label::new("Hold")
 9795                                                .size(LabelSize::Small)
 9796                                                .when(accept_keystroke.is_none(), |el| {
 9797                                                    el.strikethrough()
 9798                                                })
 9799                                                .line_height_style(LineHeightStyle::UiLabel),
 9800                                        )
 9801                                    })
 9802                                    .id("edit_prediction_cursor_popover_keybind")
 9803                                    .when(accept_keystroke.is_none(), |el| {
 9804                                        let status_colors = cx.theme().status();
 9805
 9806                                        el.bg(status_colors.error_background)
 9807                                            .border_color(status_colors.error.opacity(0.6))
 9808                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9809                                            .cursor_default()
 9810                                            .hoverable_tooltip(move |_window, cx| {
 9811                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9812                                                    .into()
 9813                                            })
 9814                                    })
 9815                                    .when_some(
 9816                                        accept_keystroke.as_ref(),
 9817                                        |el, accept_keystroke| {
 9818                                            el.child(h_flex().children(ui::render_modifiers(
 9819                                                accept_keystroke.modifiers(),
 9820                                                PlatformStyle::platform(),
 9821                                                Some(Color::Default),
 9822                                                Some(IconSize::XSmall.rems().into()),
 9823                                                false,
 9824                                            )))
 9825                                        },
 9826                                    ),
 9827                            )
 9828                            .into_any(),
 9829                    );
 9830                }
 9831
 9832                self.render_edit_prediction_cursor_popover_preview(
 9833                    prediction,
 9834                    cursor_point,
 9835                    style,
 9836                    cx,
 9837                )?
 9838            }
 9839
 9840            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9841                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9842                    stale_completion,
 9843                    cursor_point,
 9844                    style,
 9845                    cx,
 9846                )?,
 9847
 9848                None => pending_completion_container(provider_icon)
 9849                    .child(Label::new("...").size(LabelSize::Small)),
 9850            },
 9851
 9852            None => pending_completion_container(provider_icon)
 9853                .child(Label::new("...").size(LabelSize::Small)),
 9854        };
 9855
 9856        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9857            completion
 9858                .with_animation(
 9859                    "loading-completion",
 9860                    Animation::new(Duration::from_secs(2))
 9861                        .repeat()
 9862                        .with_easing(pulsating_between(0.4, 0.8)),
 9863                    |label, delta| label.opacity(delta),
 9864                )
 9865                .into_any_element()
 9866        } else {
 9867            completion.into_any_element()
 9868        };
 9869
 9870        let has_completion = self.active_edit_prediction.is_some();
 9871
 9872        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9873        Some(
 9874            h_flex()
 9875                .min_w(min_width)
 9876                .max_w(max_width)
 9877                .flex_1()
 9878                .elevation_2(cx)
 9879                .border_color(cx.theme().colors().border)
 9880                .child(
 9881                    div()
 9882                        .flex_1()
 9883                        .py_1()
 9884                        .px_2()
 9885                        .overflow_hidden()
 9886                        .child(completion),
 9887                )
 9888                .when_some(accept_keystroke, |el, accept_keystroke| {
 9889                    if !accept_keystroke.modifiers().modified() {
 9890                        return el;
 9891                    }
 9892
 9893                    el.child(
 9894                        h_flex()
 9895                            .h_full()
 9896                            .border_l_1()
 9897                            .rounded_r_lg()
 9898                            .border_color(cx.theme().colors().border)
 9899                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9900                            .gap_1()
 9901                            .py_1()
 9902                            .px_2()
 9903                            .child(
 9904                                h_flex()
 9905                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9906                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9907                                    .child(h_flex().children(ui::render_modifiers(
 9908                                        accept_keystroke.modifiers(),
 9909                                        PlatformStyle::platform(),
 9910                                        Some(if !has_completion {
 9911                                            Color::Muted
 9912                                        } else {
 9913                                            Color::Default
 9914                                        }),
 9915                                        None,
 9916                                        false,
 9917                                    ))),
 9918                            )
 9919                            .child(Label::new("Preview").into_any_element())
 9920                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9921                    )
 9922                })
 9923                .into_any(),
 9924        )
 9925    }
 9926
 9927    fn render_edit_prediction_cursor_popover_preview(
 9928        &self,
 9929        completion: &EditPredictionState,
 9930        cursor_point: Point,
 9931        style: &EditorStyle,
 9932        cx: &mut Context<Editor>,
 9933    ) -> Option<Div> {
 9934        use text::ToPoint as _;
 9935
 9936        fn render_relative_row_jump(
 9937            prefix: impl Into<String>,
 9938            current_row: u32,
 9939            target_row: u32,
 9940        ) -> Div {
 9941            let (row_diff, arrow) = if target_row < current_row {
 9942                (current_row - target_row, IconName::ArrowUp)
 9943            } else {
 9944                (target_row - current_row, IconName::ArrowDown)
 9945            };
 9946
 9947            h_flex()
 9948                .child(
 9949                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9950                        .color(Color::Muted)
 9951                        .size(LabelSize::Small),
 9952                )
 9953                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9954        }
 9955
 9956        let supports_jump = self
 9957            .edit_prediction_provider
 9958            .as_ref()
 9959            .map(|provider| provider.provider.supports_jump_to_edit())
 9960            .unwrap_or(true);
 9961
 9962        match &completion.completion {
 9963            EditPrediction::MoveWithin {
 9964                target, snapshot, ..
 9965            } => {
 9966                if !supports_jump {
 9967                    return None;
 9968                }
 9969
 9970                Some(
 9971                    h_flex()
 9972                        .px_2()
 9973                        .gap_2()
 9974                        .flex_1()
 9975                        .child(
 9976                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9977                                Icon::new(IconName::ZedPredictDown)
 9978                            } else {
 9979                                Icon::new(IconName::ZedPredictUp)
 9980                            },
 9981                        )
 9982                        .child(Label::new("Jump to Edit")),
 9983                )
 9984            }
 9985            EditPrediction::MoveOutside { snapshot, .. } => {
 9986                let file_name = snapshot
 9987                    .file()
 9988                    .map(|file| file.file_name(cx))
 9989                    .unwrap_or("untitled");
 9990                Some(
 9991                    h_flex()
 9992                        .px_2()
 9993                        .gap_2()
 9994                        .flex_1()
 9995                        .child(Icon::new(IconName::ZedPredict))
 9996                        .child(Label::new(format!("Jump to {file_name}"))),
 9997                )
 9998            }
 9999            EditPrediction::Edit {
10000                edits,
10001                edit_preview,
10002                snapshot,
10003                display_mode: _,
10004            } => {
10005                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10006
10007                let (highlighted_edits, has_more_lines) =
10008                    if let Some(edit_preview) = edit_preview.as_ref() {
10009                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10010                            .first_line_preview()
10011                    } else {
10012                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10013                    };
10014
10015                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10016                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10017
10018                let preview = h_flex()
10019                    .gap_1()
10020                    .min_w_16()
10021                    .child(styled_text)
10022                    .when(has_more_lines, |parent| parent.child(""));
10023
10024                let left = if supports_jump && first_edit_row != cursor_point.row {
10025                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10026                        .into_any_element()
10027                } else {
10028                    let icon_name =
10029                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10030                    Icon::new(icon_name).into_any_element()
10031                };
10032
10033                Some(
10034                    h_flex()
10035                        .h_full()
10036                        .flex_1()
10037                        .gap_2()
10038                        .pr_1()
10039                        .overflow_x_hidden()
10040                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10041                        .child(left)
10042                        .child(preview),
10043                )
10044            }
10045        }
10046    }
10047
10048    pub fn render_context_menu(
10049        &mut self,
10050        max_height_in_lines: u32,
10051        window: &mut Window,
10052        cx: &mut Context<Editor>,
10053    ) -> Option<AnyElement> {
10054        let menu = self.context_menu.borrow();
10055        let menu = menu.as_ref()?;
10056        if !menu.visible() {
10057            return None;
10058        };
10059        self.style
10060            .as_ref()
10061            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10062    }
10063
10064    fn render_context_menu_aside(
10065        &mut self,
10066        max_size: Size<Pixels>,
10067        window: &mut Window,
10068        cx: &mut Context<Editor>,
10069    ) -> Option<AnyElement> {
10070        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10071            if menu.visible() {
10072                menu.render_aside(max_size, window, cx)
10073            } else {
10074                None
10075            }
10076        })
10077    }
10078
10079    fn hide_context_menu(
10080        &mut self,
10081        window: &mut Window,
10082        cx: &mut Context<Self>,
10083    ) -> Option<CodeContextMenu> {
10084        cx.notify();
10085        self.completion_tasks.clear();
10086        let context_menu = self.context_menu.borrow_mut().take();
10087        self.stale_edit_prediction_in_menu.take();
10088        self.update_visible_edit_prediction(window, cx);
10089        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10090            && let Some(completion_provider) = &self.completion_provider
10091        {
10092            completion_provider.selection_changed(None, window, cx);
10093        }
10094        context_menu
10095    }
10096
10097    fn show_snippet_choices(
10098        &mut self,
10099        choices: &Vec<String>,
10100        selection: Range<Anchor>,
10101        cx: &mut Context<Self>,
10102    ) {
10103        let Some((_, buffer, _)) = self
10104            .buffer()
10105            .read(cx)
10106            .excerpt_containing(selection.start, cx)
10107        else {
10108            return;
10109        };
10110        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10111        else {
10112            return;
10113        };
10114        if buffer != end_buffer {
10115            log::error!("expected anchor range to have matching buffer IDs");
10116            return;
10117        }
10118
10119        let id = post_inc(&mut self.next_completion_id);
10120        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10121        let mut context_menu = self.context_menu.borrow_mut();
10122        let old_menu = context_menu.take();
10123        *context_menu = Some(CodeContextMenu::Completions(
10124            CompletionsMenu::new_snippet_choices(
10125                id,
10126                true,
10127                choices,
10128                selection,
10129                buffer,
10130                old_menu.map(|menu| menu.primary_scroll_handle()),
10131                snippet_sort_order,
10132            ),
10133        ));
10134    }
10135
10136    pub fn insert_snippet(
10137        &mut self,
10138        insertion_ranges: &[Range<MultiBufferOffset>],
10139        snippet: Snippet,
10140        window: &mut Window,
10141        cx: &mut Context<Self>,
10142    ) -> Result<()> {
10143        struct Tabstop<T> {
10144            is_end_tabstop: bool,
10145            ranges: Vec<Range<T>>,
10146            choices: Option<Vec<String>>,
10147        }
10148
10149        let tabstops = self.buffer.update(cx, |buffer, cx| {
10150            let snippet_text: Arc<str> = snippet.text.clone().into();
10151            let edits = insertion_ranges
10152                .iter()
10153                .cloned()
10154                .map(|range| (range, snippet_text.clone()));
10155            let autoindent_mode = AutoindentMode::Block {
10156                original_indent_columns: Vec::new(),
10157            };
10158            buffer.edit(edits, Some(autoindent_mode), cx);
10159
10160            let snapshot = &*buffer.read(cx);
10161            let snippet = &snippet;
10162            snippet
10163                .tabstops
10164                .iter()
10165                .map(|tabstop| {
10166                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10167                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10168                    });
10169                    let mut tabstop_ranges = tabstop
10170                        .ranges
10171                        .iter()
10172                        .flat_map(|tabstop_range| {
10173                            let mut delta = 0_isize;
10174                            insertion_ranges.iter().map(move |insertion_range| {
10175                                let insertion_start = insertion_range.start + delta;
10176                                delta += snippet.text.len() as isize
10177                                    - (insertion_range.end - insertion_range.start) as isize;
10178
10179                                let start =
10180                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10181                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10182                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10183                            })
10184                        })
10185                        .collect::<Vec<_>>();
10186                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10187
10188                    Tabstop {
10189                        is_end_tabstop,
10190                        ranges: tabstop_ranges,
10191                        choices: tabstop.choices.clone(),
10192                    }
10193                })
10194                .collect::<Vec<_>>()
10195        });
10196        if let Some(tabstop) = tabstops.first() {
10197            self.change_selections(Default::default(), window, cx, |s| {
10198                // Reverse order so that the first range is the newest created selection.
10199                // Completions will use it and autoscroll will prioritize it.
10200                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10201            });
10202
10203            if let Some(choices) = &tabstop.choices
10204                && let Some(selection) = tabstop.ranges.first()
10205            {
10206                self.show_snippet_choices(choices, selection.clone(), cx)
10207            }
10208
10209            // If we're already at the last tabstop and it's at the end of the snippet,
10210            // we're done, we don't need to keep the state around.
10211            if !tabstop.is_end_tabstop {
10212                let choices = tabstops
10213                    .iter()
10214                    .map(|tabstop| tabstop.choices.clone())
10215                    .collect();
10216
10217                let ranges = tabstops
10218                    .into_iter()
10219                    .map(|tabstop| tabstop.ranges)
10220                    .collect::<Vec<_>>();
10221
10222                self.snippet_stack.push(SnippetState {
10223                    active_index: 0,
10224                    ranges,
10225                    choices,
10226                });
10227            }
10228
10229            // Check whether the just-entered snippet ends with an auto-closable bracket.
10230            if self.autoclose_regions.is_empty() {
10231                let snapshot = self.buffer.read(cx).snapshot(cx);
10232                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10233                    let selection_head = selection.head();
10234                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10235                        continue;
10236                    };
10237
10238                    let mut bracket_pair = None;
10239                    let max_lookup_length = scope
10240                        .brackets()
10241                        .map(|(pair, _)| {
10242                            pair.start
10243                                .as_str()
10244                                .chars()
10245                                .count()
10246                                .max(pair.end.as_str().chars().count())
10247                        })
10248                        .max();
10249                    if let Some(max_lookup_length) = max_lookup_length {
10250                        let next_text = snapshot
10251                            .chars_at(selection_head)
10252                            .take(max_lookup_length)
10253                            .collect::<String>();
10254                        let prev_text = snapshot
10255                            .reversed_chars_at(selection_head)
10256                            .take(max_lookup_length)
10257                            .collect::<String>();
10258
10259                        for (pair, enabled) in scope.brackets() {
10260                            if enabled
10261                                && pair.close
10262                                && prev_text.starts_with(pair.start.as_str())
10263                                && next_text.starts_with(pair.end.as_str())
10264                            {
10265                                bracket_pair = Some(pair.clone());
10266                                break;
10267                            }
10268                        }
10269                    }
10270
10271                    if let Some(pair) = bracket_pair {
10272                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10273                        let autoclose_enabled =
10274                            self.use_autoclose && snapshot_settings.use_autoclose;
10275                        if autoclose_enabled {
10276                            let start = snapshot.anchor_after(selection_head);
10277                            let end = snapshot.anchor_after(selection_head);
10278                            self.autoclose_regions.push(AutocloseRegion {
10279                                selection_id: selection.id,
10280                                range: start..end,
10281                                pair,
10282                            });
10283                        }
10284                    }
10285                }
10286            }
10287        }
10288        Ok(())
10289    }
10290
10291    pub fn move_to_next_snippet_tabstop(
10292        &mut self,
10293        window: &mut Window,
10294        cx: &mut Context<Self>,
10295    ) -> bool {
10296        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10297    }
10298
10299    pub fn move_to_prev_snippet_tabstop(
10300        &mut self,
10301        window: &mut Window,
10302        cx: &mut Context<Self>,
10303    ) -> bool {
10304        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10305    }
10306
10307    pub fn move_to_snippet_tabstop(
10308        &mut self,
10309        bias: Bias,
10310        window: &mut Window,
10311        cx: &mut Context<Self>,
10312    ) -> bool {
10313        if let Some(mut snippet) = self.snippet_stack.pop() {
10314            match bias {
10315                Bias::Left => {
10316                    if snippet.active_index > 0 {
10317                        snippet.active_index -= 1;
10318                    } else {
10319                        self.snippet_stack.push(snippet);
10320                        return false;
10321                    }
10322                }
10323                Bias::Right => {
10324                    if snippet.active_index + 1 < snippet.ranges.len() {
10325                        snippet.active_index += 1;
10326                    } else {
10327                        self.snippet_stack.push(snippet);
10328                        return false;
10329                    }
10330                }
10331            }
10332            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10333                self.change_selections(Default::default(), window, cx, |s| {
10334                    // Reverse order so that the first range is the newest created selection.
10335                    // Completions will use it and autoscroll will prioritize it.
10336                    s.select_ranges(current_ranges.iter().rev().cloned())
10337                });
10338
10339                if let Some(choices) = &snippet.choices[snippet.active_index]
10340                    && let Some(selection) = current_ranges.first()
10341                {
10342                    self.show_snippet_choices(choices, selection.clone(), cx);
10343                }
10344
10345                // If snippet state is not at the last tabstop, push it back on the stack
10346                if snippet.active_index + 1 < snippet.ranges.len() {
10347                    self.snippet_stack.push(snippet);
10348                }
10349                return true;
10350            }
10351        }
10352
10353        false
10354    }
10355
10356    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10357        self.transact(window, cx, |this, window, cx| {
10358            this.select_all(&SelectAll, window, cx);
10359            this.insert("", window, cx);
10360        });
10361    }
10362
10363    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10364        if self.read_only(cx) {
10365            return;
10366        }
10367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10368        self.transact(window, cx, |this, window, cx| {
10369            this.select_autoclose_pair(window, cx);
10370
10371            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10372
10373            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10374            if !this.linked_edit_ranges.is_empty() {
10375                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10376                let snapshot = this.buffer.read(cx).snapshot(cx);
10377
10378                for selection in selections.iter() {
10379                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10380                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10381                    if selection_start.buffer_id != selection_end.buffer_id {
10382                        continue;
10383                    }
10384                    if let Some(ranges) =
10385                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10386                    {
10387                        for (buffer, entries) in ranges {
10388                            linked_ranges.entry(buffer).or_default().extend(entries);
10389                        }
10390                    }
10391                }
10392            }
10393
10394            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10395            for selection in &mut selections {
10396                if selection.is_empty() {
10397                    let old_head = selection.head();
10398                    let mut new_head =
10399                        movement::left(&display_map, old_head.to_display_point(&display_map))
10400                            .to_point(&display_map);
10401                    if let Some((buffer, line_buffer_range)) = display_map
10402                        .buffer_snapshot()
10403                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10404                    {
10405                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10406                        let indent_len = match indent_size.kind {
10407                            IndentKind::Space => {
10408                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10409                            }
10410                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10411                        };
10412                        if old_head.column <= indent_size.len && old_head.column > 0 {
10413                            let indent_len = indent_len.get();
10414                            new_head = cmp::min(
10415                                new_head,
10416                                MultiBufferPoint::new(
10417                                    old_head.row,
10418                                    ((old_head.column - 1) / indent_len) * indent_len,
10419                                ),
10420                            );
10421                        }
10422                    }
10423
10424                    selection.set_head(new_head, SelectionGoal::None);
10425                }
10426            }
10427
10428            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10429            this.insert("", window, cx);
10430            let empty_str: Arc<str> = Arc::from("");
10431            for (buffer, edits) in linked_ranges {
10432                let snapshot = buffer.read(cx).snapshot();
10433                use text::ToPoint as TP;
10434
10435                let edits = edits
10436                    .into_iter()
10437                    .map(|range| {
10438                        let end_point = TP::to_point(&range.end, &snapshot);
10439                        let mut start_point = TP::to_point(&range.start, &snapshot);
10440
10441                        if end_point == start_point {
10442                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10443                                .saturating_sub(1);
10444                            start_point =
10445                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10446                        };
10447
10448                        (start_point..end_point, empty_str.clone())
10449                    })
10450                    .sorted_by_key(|(range, _)| range.start)
10451                    .collect::<Vec<_>>();
10452                buffer.update(cx, |this, cx| {
10453                    this.edit(edits, None, cx);
10454                })
10455            }
10456            this.refresh_edit_prediction(true, false, window, cx);
10457            refresh_linked_ranges(this, window, cx);
10458        });
10459    }
10460
10461    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10462        if self.read_only(cx) {
10463            return;
10464        }
10465        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10466        self.transact(window, cx, |this, window, cx| {
10467            this.change_selections(Default::default(), window, cx, |s| {
10468                s.move_with(|map, selection| {
10469                    if selection.is_empty() {
10470                        let cursor = movement::right(map, selection.head());
10471                        selection.end = cursor;
10472                        selection.reversed = true;
10473                        selection.goal = SelectionGoal::None;
10474                    }
10475                })
10476            });
10477            this.insert("", window, cx);
10478            this.refresh_edit_prediction(true, false, window, cx);
10479        });
10480    }
10481
10482    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10483        if self.mode.is_single_line() {
10484            cx.propagate();
10485            return;
10486        }
10487
10488        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10489        if self.move_to_prev_snippet_tabstop(window, cx) {
10490            return;
10491        }
10492        self.outdent(&Outdent, window, cx);
10493    }
10494
10495    pub fn next_snippet_tabstop(
10496        &mut self,
10497        _: &NextSnippetTabstop,
10498        window: &mut Window,
10499        cx: &mut Context<Self>,
10500    ) {
10501        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10502            cx.propagate();
10503            return;
10504        }
10505
10506        if self.move_to_next_snippet_tabstop(window, cx) {
10507            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10508            return;
10509        }
10510        cx.propagate();
10511    }
10512
10513    pub fn previous_snippet_tabstop(
10514        &mut self,
10515        _: &PreviousSnippetTabstop,
10516        window: &mut Window,
10517        cx: &mut Context<Self>,
10518    ) {
10519        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10520            cx.propagate();
10521            return;
10522        }
10523
10524        if self.move_to_prev_snippet_tabstop(window, cx) {
10525            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10526            return;
10527        }
10528        cx.propagate();
10529    }
10530
10531    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10532        if self.mode.is_single_line() {
10533            cx.propagate();
10534            return;
10535        }
10536
10537        if self.move_to_next_snippet_tabstop(window, cx) {
10538            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10539            return;
10540        }
10541        if self.read_only(cx) {
10542            return;
10543        }
10544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10545        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10546        let buffer = self.buffer.read(cx);
10547        let snapshot = buffer.snapshot(cx);
10548        let rows_iter = selections.iter().map(|s| s.head().row);
10549        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10550
10551        let has_some_cursor_in_whitespace = selections
10552            .iter()
10553            .filter(|selection| selection.is_empty())
10554            .any(|selection| {
10555                let cursor = selection.head();
10556                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10557                cursor.column < current_indent.len
10558            });
10559
10560        let mut edits = Vec::new();
10561        let mut prev_edited_row = 0;
10562        let mut row_delta = 0;
10563        for selection in &mut selections {
10564            if selection.start.row != prev_edited_row {
10565                row_delta = 0;
10566            }
10567            prev_edited_row = selection.end.row;
10568
10569            // If the selection is non-empty, then increase the indentation of the selected lines.
10570            if !selection.is_empty() {
10571                row_delta =
10572                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10573                continue;
10574            }
10575
10576            let cursor = selection.head();
10577            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10578            if let Some(suggested_indent) =
10579                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10580            {
10581                // Don't do anything if already at suggested indent
10582                // and there is any other cursor which is not
10583                if has_some_cursor_in_whitespace
10584                    && cursor.column == current_indent.len
10585                    && current_indent.len == suggested_indent.len
10586                {
10587                    continue;
10588                }
10589
10590                // Adjust line and move cursor to suggested indent
10591                // if cursor is not at suggested indent
10592                if cursor.column < suggested_indent.len
10593                    && cursor.column <= current_indent.len
10594                    && current_indent.len <= suggested_indent.len
10595                {
10596                    selection.start = Point::new(cursor.row, suggested_indent.len);
10597                    selection.end = selection.start;
10598                    if row_delta == 0 {
10599                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10600                            cursor.row,
10601                            current_indent,
10602                            suggested_indent,
10603                        ));
10604                        row_delta = suggested_indent.len - current_indent.len;
10605                    }
10606                    continue;
10607                }
10608
10609                // If current indent is more than suggested indent
10610                // only move cursor to current indent and skip indent
10611                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10612                    selection.start = Point::new(cursor.row, current_indent.len);
10613                    selection.end = selection.start;
10614                    continue;
10615                }
10616            }
10617
10618            // Otherwise, insert a hard or soft tab.
10619            let settings = buffer.language_settings_at(cursor, cx);
10620            let tab_size = if settings.hard_tabs {
10621                IndentSize::tab()
10622            } else {
10623                let tab_size = settings.tab_size.get();
10624                let indent_remainder = snapshot
10625                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10626                    .flat_map(str::chars)
10627                    .fold(row_delta % tab_size, |counter: u32, c| {
10628                        if c == '\t' {
10629                            0
10630                        } else {
10631                            (counter + 1) % tab_size
10632                        }
10633                    });
10634
10635                let chars_to_next_tab_stop = tab_size - indent_remainder;
10636                IndentSize::spaces(chars_to_next_tab_stop)
10637            };
10638            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10639            selection.end = selection.start;
10640            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10641            row_delta += tab_size.len;
10642        }
10643
10644        self.transact(window, cx, |this, window, cx| {
10645            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10646            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10647            this.refresh_edit_prediction(true, false, window, cx);
10648        });
10649    }
10650
10651    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10652        if self.read_only(cx) {
10653            return;
10654        }
10655        if self.mode.is_single_line() {
10656            cx.propagate();
10657            return;
10658        }
10659
10660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10661        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10662        let mut prev_edited_row = 0;
10663        let mut row_delta = 0;
10664        let mut edits = Vec::new();
10665        let buffer = self.buffer.read(cx);
10666        let snapshot = buffer.snapshot(cx);
10667        for selection in &mut selections {
10668            if selection.start.row != prev_edited_row {
10669                row_delta = 0;
10670            }
10671            prev_edited_row = selection.end.row;
10672
10673            row_delta =
10674                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10675        }
10676
10677        self.transact(window, cx, |this, window, cx| {
10678            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10679            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10680        });
10681    }
10682
10683    fn indent_selection(
10684        buffer: &MultiBuffer,
10685        snapshot: &MultiBufferSnapshot,
10686        selection: &mut Selection<Point>,
10687        edits: &mut Vec<(Range<Point>, String)>,
10688        delta_for_start_row: u32,
10689        cx: &App,
10690    ) -> u32 {
10691        let settings = buffer.language_settings_at(selection.start, cx);
10692        let tab_size = settings.tab_size.get();
10693        let indent_kind = if settings.hard_tabs {
10694            IndentKind::Tab
10695        } else {
10696            IndentKind::Space
10697        };
10698        let mut start_row = selection.start.row;
10699        let mut end_row = selection.end.row + 1;
10700
10701        // If a selection ends at the beginning of a line, don't indent
10702        // that last line.
10703        if selection.end.column == 0 && selection.end.row > selection.start.row {
10704            end_row -= 1;
10705        }
10706
10707        // Avoid re-indenting a row that has already been indented by a
10708        // previous selection, but still update this selection's column
10709        // to reflect that indentation.
10710        if delta_for_start_row > 0 {
10711            start_row += 1;
10712            selection.start.column += delta_for_start_row;
10713            if selection.end.row == selection.start.row {
10714                selection.end.column += delta_for_start_row;
10715            }
10716        }
10717
10718        let mut delta_for_end_row = 0;
10719        let has_multiple_rows = start_row + 1 != end_row;
10720        for row in start_row..end_row {
10721            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10722            let indent_delta = match (current_indent.kind, indent_kind) {
10723                (IndentKind::Space, IndentKind::Space) => {
10724                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10725                    IndentSize::spaces(columns_to_next_tab_stop)
10726                }
10727                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10728                (_, IndentKind::Tab) => IndentSize::tab(),
10729            };
10730
10731            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10732                0
10733            } else {
10734                selection.start.column
10735            };
10736            let row_start = Point::new(row, start);
10737            edits.push((
10738                row_start..row_start,
10739                indent_delta.chars().collect::<String>(),
10740            ));
10741
10742            // Update this selection's endpoints to reflect the indentation.
10743            if row == selection.start.row {
10744                selection.start.column += indent_delta.len;
10745            }
10746            if row == selection.end.row {
10747                selection.end.column += indent_delta.len;
10748                delta_for_end_row = indent_delta.len;
10749            }
10750        }
10751
10752        if selection.start.row == selection.end.row {
10753            delta_for_start_row + delta_for_end_row
10754        } else {
10755            delta_for_end_row
10756        }
10757    }
10758
10759    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10760        if self.read_only(cx) {
10761            return;
10762        }
10763        if self.mode.is_single_line() {
10764            cx.propagate();
10765            return;
10766        }
10767
10768        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10769        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10770        let selections = self.selections.all::<Point>(&display_map);
10771        let mut deletion_ranges = Vec::new();
10772        let mut last_outdent = None;
10773        {
10774            let buffer = self.buffer.read(cx);
10775            let snapshot = buffer.snapshot(cx);
10776            for selection in &selections {
10777                let settings = buffer.language_settings_at(selection.start, cx);
10778                let tab_size = settings.tab_size.get();
10779                let mut rows = selection.spanned_rows(false, &display_map);
10780
10781                // Avoid re-outdenting a row that has already been outdented by a
10782                // previous selection.
10783                if let Some(last_row) = last_outdent
10784                    && last_row == rows.start
10785                {
10786                    rows.start = rows.start.next_row();
10787                }
10788                let has_multiple_rows = rows.len() > 1;
10789                for row in rows.iter_rows() {
10790                    let indent_size = snapshot.indent_size_for_line(row);
10791                    if indent_size.len > 0 {
10792                        let deletion_len = match indent_size.kind {
10793                            IndentKind::Space => {
10794                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10795                                if columns_to_prev_tab_stop == 0 {
10796                                    tab_size
10797                                } else {
10798                                    columns_to_prev_tab_stop
10799                                }
10800                            }
10801                            IndentKind::Tab => 1,
10802                        };
10803                        let start = if has_multiple_rows
10804                            || deletion_len > selection.start.column
10805                            || indent_size.len < selection.start.column
10806                        {
10807                            0
10808                        } else {
10809                            selection.start.column - deletion_len
10810                        };
10811                        deletion_ranges.push(
10812                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10813                        );
10814                        last_outdent = Some(row);
10815                    }
10816                }
10817            }
10818        }
10819
10820        self.transact(window, cx, |this, window, cx| {
10821            this.buffer.update(cx, |buffer, cx| {
10822                let empty_str: Arc<str> = Arc::default();
10823                buffer.edit(
10824                    deletion_ranges
10825                        .into_iter()
10826                        .map(|range| (range, empty_str.clone())),
10827                    None,
10828                    cx,
10829                );
10830            });
10831            let selections = this
10832                .selections
10833                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10834            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10835        });
10836    }
10837
10838    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10839        if self.read_only(cx) {
10840            return;
10841        }
10842        if self.mode.is_single_line() {
10843            cx.propagate();
10844            return;
10845        }
10846
10847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10848        let selections = self
10849            .selections
10850            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10851            .into_iter()
10852            .map(|s| s.range());
10853
10854        self.transact(window, cx, |this, window, cx| {
10855            this.buffer.update(cx, |buffer, cx| {
10856                buffer.autoindent_ranges(selections, cx);
10857            });
10858            let selections = this
10859                .selections
10860                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10861            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10862        });
10863    }
10864
10865    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10867        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10868        let selections = self.selections.all::<Point>(&display_map);
10869
10870        let mut new_cursors = Vec::new();
10871        let mut edit_ranges = Vec::new();
10872        let mut selections = selections.iter().peekable();
10873        while let Some(selection) = selections.next() {
10874            let mut rows = selection.spanned_rows(false, &display_map);
10875
10876            // Accumulate contiguous regions of rows that we want to delete.
10877            while let Some(next_selection) = selections.peek() {
10878                let next_rows = next_selection.spanned_rows(false, &display_map);
10879                if next_rows.start <= rows.end {
10880                    rows.end = next_rows.end;
10881                    selections.next().unwrap();
10882                } else {
10883                    break;
10884                }
10885            }
10886
10887            let buffer = display_map.buffer_snapshot();
10888            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10889            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10890                // If there's a line after the range, delete the \n from the end of the row range
10891                (
10892                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10893                    rows.end,
10894                )
10895            } else {
10896                // If there isn't a line after the range, delete the \n from the line before the
10897                // start of the row range
10898                edit_start = edit_start.saturating_sub_usize(1);
10899                (buffer.len(), rows.start.previous_row())
10900            };
10901
10902            let text_layout_details = self.text_layout_details(window);
10903            let x = display_map.x_for_display_point(
10904                selection.head().to_display_point(&display_map),
10905                &text_layout_details,
10906            );
10907            let row = Point::new(target_row.0, 0)
10908                .to_display_point(&display_map)
10909                .row();
10910            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10911
10912            new_cursors.push((
10913                selection.id,
10914                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10915                SelectionGoal::None,
10916            ));
10917            edit_ranges.push(edit_start..edit_end);
10918        }
10919
10920        self.transact(window, cx, |this, window, cx| {
10921            let buffer = this.buffer.update(cx, |buffer, cx| {
10922                let empty_str: Arc<str> = Arc::default();
10923                buffer.edit(
10924                    edit_ranges
10925                        .into_iter()
10926                        .map(|range| (range, empty_str.clone())),
10927                    None,
10928                    cx,
10929                );
10930                buffer.snapshot(cx)
10931            });
10932            let new_selections = new_cursors
10933                .into_iter()
10934                .map(|(id, cursor, goal)| {
10935                    let cursor = cursor.to_point(&buffer);
10936                    Selection {
10937                        id,
10938                        start: cursor,
10939                        end: cursor,
10940                        reversed: false,
10941                        goal,
10942                    }
10943                })
10944                .collect();
10945
10946            this.change_selections(Default::default(), window, cx, |s| {
10947                s.select(new_selections);
10948            });
10949        });
10950    }
10951
10952    pub fn join_lines_impl(
10953        &mut self,
10954        insert_whitespace: bool,
10955        window: &mut Window,
10956        cx: &mut Context<Self>,
10957    ) {
10958        if self.read_only(cx) {
10959            return;
10960        }
10961        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10962        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10963            let start = MultiBufferRow(selection.start.row);
10964            // Treat single line selections as if they include the next line. Otherwise this action
10965            // would do nothing for single line selections individual cursors.
10966            let end = if selection.start.row == selection.end.row {
10967                MultiBufferRow(selection.start.row + 1)
10968            } else {
10969                MultiBufferRow(selection.end.row)
10970            };
10971
10972            if let Some(last_row_range) = row_ranges.last_mut()
10973                && start <= last_row_range.end
10974            {
10975                last_row_range.end = end;
10976                continue;
10977            }
10978            row_ranges.push(start..end);
10979        }
10980
10981        let snapshot = self.buffer.read(cx).snapshot(cx);
10982        let mut cursor_positions = Vec::new();
10983        for row_range in &row_ranges {
10984            let anchor = snapshot.anchor_before(Point::new(
10985                row_range.end.previous_row().0,
10986                snapshot.line_len(row_range.end.previous_row()),
10987            ));
10988            cursor_positions.push(anchor..anchor);
10989        }
10990
10991        self.transact(window, cx, |this, window, cx| {
10992            for row_range in row_ranges.into_iter().rev() {
10993                for row in row_range.iter_rows().rev() {
10994                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10995                    let next_line_row = row.next_row();
10996                    let indent = snapshot.indent_size_for_line(next_line_row);
10997                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10998
10999                    let replace =
11000                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11001                            " "
11002                        } else {
11003                            ""
11004                        };
11005
11006                    this.buffer.update(cx, |buffer, cx| {
11007                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11008                    });
11009                }
11010            }
11011
11012            this.change_selections(Default::default(), window, cx, |s| {
11013                s.select_anchor_ranges(cursor_positions)
11014            });
11015        });
11016    }
11017
11018    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11020        self.join_lines_impl(true, window, cx);
11021    }
11022
11023    pub fn sort_lines_case_sensitive(
11024        &mut self,
11025        _: &SortLinesCaseSensitive,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028    ) {
11029        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11030    }
11031
11032    pub fn sort_lines_by_length(
11033        &mut self,
11034        _: &SortLinesByLength,
11035        window: &mut Window,
11036        cx: &mut Context<Self>,
11037    ) {
11038        self.manipulate_immutable_lines(window, cx, |lines| {
11039            lines.sort_by_key(|&line| line.chars().count())
11040        })
11041    }
11042
11043    pub fn sort_lines_case_insensitive(
11044        &mut self,
11045        _: &SortLinesCaseInsensitive,
11046        window: &mut Window,
11047        cx: &mut Context<Self>,
11048    ) {
11049        self.manipulate_immutable_lines(window, cx, |lines| {
11050            lines.sort_by_key(|line| line.to_lowercase())
11051        })
11052    }
11053
11054    pub fn unique_lines_case_insensitive(
11055        &mut self,
11056        _: &UniqueLinesCaseInsensitive,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.manipulate_immutable_lines(window, cx, |lines| {
11061            let mut seen = HashSet::default();
11062            lines.retain(|line| seen.insert(line.to_lowercase()));
11063        })
11064    }
11065
11066    pub fn unique_lines_case_sensitive(
11067        &mut self,
11068        _: &UniqueLinesCaseSensitive,
11069        window: &mut Window,
11070        cx: &mut Context<Self>,
11071    ) {
11072        self.manipulate_immutable_lines(window, cx, |lines| {
11073            let mut seen = HashSet::default();
11074            lines.retain(|line| seen.insert(*line));
11075        })
11076    }
11077
11078    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11079        let snapshot = self.buffer.read(cx).snapshot(cx);
11080        for selection in self.selections.disjoint_anchors_arc().iter() {
11081            if snapshot
11082                .language_at(selection.start)
11083                .and_then(|lang| lang.config().wrap_characters.as_ref())
11084                .is_some()
11085            {
11086                return true;
11087            }
11088        }
11089        false
11090    }
11091
11092    fn wrap_selections_in_tag(
11093        &mut self,
11094        _: &WrapSelectionsInTag,
11095        window: &mut Window,
11096        cx: &mut Context<Self>,
11097    ) {
11098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11099
11100        let snapshot = self.buffer.read(cx).snapshot(cx);
11101
11102        let mut edits = Vec::new();
11103        let mut boundaries = Vec::new();
11104
11105        for selection in self
11106            .selections
11107            .all_adjusted(&self.display_snapshot(cx))
11108            .iter()
11109        {
11110            let Some(wrap_config) = snapshot
11111                .language_at(selection.start)
11112                .and_then(|lang| lang.config().wrap_characters.clone())
11113            else {
11114                continue;
11115            };
11116
11117            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11118            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11119
11120            let start_before = snapshot.anchor_before(selection.start);
11121            let end_after = snapshot.anchor_after(selection.end);
11122
11123            edits.push((start_before..start_before, open_tag));
11124            edits.push((end_after..end_after, close_tag));
11125
11126            boundaries.push((
11127                start_before,
11128                end_after,
11129                wrap_config.start_prefix.len(),
11130                wrap_config.end_suffix.len(),
11131            ));
11132        }
11133
11134        if edits.is_empty() {
11135            return;
11136        }
11137
11138        self.transact(window, cx, |this, window, cx| {
11139            let buffer = this.buffer.update(cx, |buffer, cx| {
11140                buffer.edit(edits, None, cx);
11141                buffer.snapshot(cx)
11142            });
11143
11144            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11145            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11146                boundaries.into_iter()
11147            {
11148                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11149                let close_offset = end_after
11150                    .to_offset(&buffer)
11151                    .saturating_sub_usize(end_suffix_len);
11152                new_selections.push(open_offset..open_offset);
11153                new_selections.push(close_offset..close_offset);
11154            }
11155
11156            this.change_selections(Default::default(), window, cx, |s| {
11157                s.select_ranges(new_selections);
11158            });
11159
11160            this.request_autoscroll(Autoscroll::fit(), cx);
11161        });
11162    }
11163
11164    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11165        let Some(project) = self.project.clone() else {
11166            return;
11167        };
11168        self.reload(project, window, cx)
11169            .detach_and_notify_err(window, cx);
11170    }
11171
11172    pub fn restore_file(
11173        &mut self,
11174        _: &::git::RestoreFile,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11179        let mut buffer_ids = HashSet::default();
11180        let snapshot = self.buffer().read(cx).snapshot(cx);
11181        for selection in self
11182            .selections
11183            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11184        {
11185            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11186        }
11187
11188        let buffer = self.buffer().read(cx);
11189        let ranges = buffer_ids
11190            .into_iter()
11191            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11192            .collect::<Vec<_>>();
11193
11194        self.restore_hunks_in_ranges(ranges, window, cx);
11195    }
11196
11197    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11198        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11199        let selections = self
11200            .selections
11201            .all(&self.display_snapshot(cx))
11202            .into_iter()
11203            .map(|s| s.range())
11204            .collect();
11205        self.restore_hunks_in_ranges(selections, window, cx);
11206    }
11207
11208    pub fn restore_hunks_in_ranges(
11209        &mut self,
11210        ranges: Vec<Range<Point>>,
11211        window: &mut Window,
11212        cx: &mut Context<Editor>,
11213    ) {
11214        let mut revert_changes = HashMap::default();
11215        let chunk_by = self
11216            .snapshot(window, cx)
11217            .hunks_for_ranges(ranges)
11218            .into_iter()
11219            .chunk_by(|hunk| hunk.buffer_id);
11220        for (buffer_id, hunks) in &chunk_by {
11221            let hunks = hunks.collect::<Vec<_>>();
11222            for hunk in &hunks {
11223                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11224            }
11225            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11226        }
11227        drop(chunk_by);
11228        if !revert_changes.is_empty() {
11229            self.transact(window, cx, |editor, window, cx| {
11230                editor.restore(revert_changes, window, cx);
11231            });
11232        }
11233    }
11234
11235    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11236        if let Some(status) = self
11237            .addons
11238            .iter()
11239            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11240        {
11241            return Some(status);
11242        }
11243        self.project
11244            .as_ref()?
11245            .read(cx)
11246            .status_for_buffer_id(buffer_id, cx)
11247    }
11248
11249    pub fn open_active_item_in_terminal(
11250        &mut self,
11251        _: &OpenInTerminal,
11252        window: &mut Window,
11253        cx: &mut Context<Self>,
11254    ) {
11255        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11256            let project_path = buffer.read(cx).project_path(cx)?;
11257            let project = self.project()?.read(cx);
11258            let entry = project.entry_for_path(&project_path, cx)?;
11259            let parent = match &entry.canonical_path {
11260                Some(canonical_path) => canonical_path.to_path_buf(),
11261                None => project.absolute_path(&project_path, cx)?,
11262            }
11263            .parent()?
11264            .to_path_buf();
11265            Some(parent)
11266        }) {
11267            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11268        }
11269    }
11270
11271    fn set_breakpoint_context_menu(
11272        &mut self,
11273        display_row: DisplayRow,
11274        position: Option<Anchor>,
11275        clicked_point: gpui::Point<Pixels>,
11276        window: &mut Window,
11277        cx: &mut Context<Self>,
11278    ) {
11279        let source = self
11280            .buffer
11281            .read(cx)
11282            .snapshot(cx)
11283            .anchor_before(Point::new(display_row.0, 0u32));
11284
11285        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11286
11287        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11288            self,
11289            source,
11290            clicked_point,
11291            context_menu,
11292            window,
11293            cx,
11294        );
11295    }
11296
11297    fn add_edit_breakpoint_block(
11298        &mut self,
11299        anchor: Anchor,
11300        breakpoint: &Breakpoint,
11301        edit_action: BreakpointPromptEditAction,
11302        window: &mut Window,
11303        cx: &mut Context<Self>,
11304    ) {
11305        let weak_editor = cx.weak_entity();
11306        let bp_prompt = cx.new(|cx| {
11307            BreakpointPromptEditor::new(
11308                weak_editor,
11309                anchor,
11310                breakpoint.clone(),
11311                edit_action,
11312                window,
11313                cx,
11314            )
11315        });
11316
11317        let height = bp_prompt.update(cx, |this, cx| {
11318            this.prompt
11319                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11320        });
11321        let cloned_prompt = bp_prompt.clone();
11322        let blocks = vec![BlockProperties {
11323            style: BlockStyle::Sticky,
11324            placement: BlockPlacement::Above(anchor),
11325            height: Some(height),
11326            render: Arc::new(move |cx| {
11327                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11328                cloned_prompt.clone().into_any_element()
11329            }),
11330            priority: 0,
11331        }];
11332
11333        let focus_handle = bp_prompt.focus_handle(cx);
11334        window.focus(&focus_handle);
11335
11336        let block_ids = self.insert_blocks(blocks, None, cx);
11337        bp_prompt.update(cx, |prompt, _| {
11338            prompt.add_block_ids(block_ids);
11339        });
11340    }
11341
11342    pub(crate) fn breakpoint_at_row(
11343        &self,
11344        row: u32,
11345        window: &mut Window,
11346        cx: &mut Context<Self>,
11347    ) -> Option<(Anchor, Breakpoint)> {
11348        let snapshot = self.snapshot(window, cx);
11349        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11350
11351        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11352    }
11353
11354    pub(crate) fn breakpoint_at_anchor(
11355        &self,
11356        breakpoint_position: Anchor,
11357        snapshot: &EditorSnapshot,
11358        cx: &mut Context<Self>,
11359    ) -> Option<(Anchor, Breakpoint)> {
11360        let buffer = self
11361            .buffer
11362            .read(cx)
11363            .buffer_for_anchor(breakpoint_position, cx)?;
11364
11365        let enclosing_excerpt = breakpoint_position.excerpt_id;
11366        let buffer_snapshot = buffer.read(cx).snapshot();
11367
11368        let row = buffer_snapshot
11369            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11370            .row;
11371
11372        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11373        let anchor_end = snapshot
11374            .buffer_snapshot()
11375            .anchor_after(Point::new(row, line_len));
11376
11377        self.breakpoint_store
11378            .as_ref()?
11379            .read_with(cx, |breakpoint_store, cx| {
11380                breakpoint_store
11381                    .breakpoints(
11382                        &buffer,
11383                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11384                        &buffer_snapshot,
11385                        cx,
11386                    )
11387                    .next()
11388                    .and_then(|(bp, _)| {
11389                        let breakpoint_row = buffer_snapshot
11390                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11391                            .row;
11392
11393                        if breakpoint_row == row {
11394                            snapshot
11395                                .buffer_snapshot()
11396                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11397                                .map(|position| (position, bp.bp.clone()))
11398                        } else {
11399                            None
11400                        }
11401                    })
11402            })
11403    }
11404
11405    pub fn edit_log_breakpoint(
11406        &mut self,
11407        _: &EditLogBreakpoint,
11408        window: &mut Window,
11409        cx: &mut Context<Self>,
11410    ) {
11411        if self.breakpoint_store.is_none() {
11412            return;
11413        }
11414
11415        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11416            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11417                message: None,
11418                state: BreakpointState::Enabled,
11419                condition: None,
11420                hit_condition: None,
11421            });
11422
11423            self.add_edit_breakpoint_block(
11424                anchor,
11425                &breakpoint,
11426                BreakpointPromptEditAction::Log,
11427                window,
11428                cx,
11429            );
11430        }
11431    }
11432
11433    fn breakpoints_at_cursors(
11434        &self,
11435        window: &mut Window,
11436        cx: &mut Context<Self>,
11437    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11438        let snapshot = self.snapshot(window, cx);
11439        let cursors = self
11440            .selections
11441            .disjoint_anchors_arc()
11442            .iter()
11443            .map(|selection| {
11444                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11445
11446                let breakpoint_position = self
11447                    .breakpoint_at_row(cursor_position.row, window, cx)
11448                    .map(|bp| bp.0)
11449                    .unwrap_or_else(|| {
11450                        snapshot
11451                            .display_snapshot
11452                            .buffer_snapshot()
11453                            .anchor_after(Point::new(cursor_position.row, 0))
11454                    });
11455
11456                let breakpoint = self
11457                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11458                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11459
11460                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11461            })
11462            // 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.
11463            .collect::<HashMap<Anchor, _>>();
11464
11465        cursors.into_iter().collect()
11466    }
11467
11468    pub fn enable_breakpoint(
11469        &mut self,
11470        _: &crate::actions::EnableBreakpoint,
11471        window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) {
11474        if self.breakpoint_store.is_none() {
11475            return;
11476        }
11477
11478        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11479            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11480                continue;
11481            };
11482            self.edit_breakpoint_at_anchor(
11483                anchor,
11484                breakpoint,
11485                BreakpointEditAction::InvertState,
11486                cx,
11487            );
11488        }
11489    }
11490
11491    pub fn disable_breakpoint(
11492        &mut self,
11493        _: &crate::actions::DisableBreakpoint,
11494        window: &mut Window,
11495        cx: &mut Context<Self>,
11496    ) {
11497        if self.breakpoint_store.is_none() {
11498            return;
11499        }
11500
11501        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11502            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11503                continue;
11504            };
11505            self.edit_breakpoint_at_anchor(
11506                anchor,
11507                breakpoint,
11508                BreakpointEditAction::InvertState,
11509                cx,
11510            );
11511        }
11512    }
11513
11514    pub fn toggle_breakpoint(
11515        &mut self,
11516        _: &crate::actions::ToggleBreakpoint,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        if self.breakpoint_store.is_none() {
11521            return;
11522        }
11523
11524        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11525            if let Some(breakpoint) = breakpoint {
11526                self.edit_breakpoint_at_anchor(
11527                    anchor,
11528                    breakpoint,
11529                    BreakpointEditAction::Toggle,
11530                    cx,
11531                );
11532            } else {
11533                self.edit_breakpoint_at_anchor(
11534                    anchor,
11535                    Breakpoint::new_standard(),
11536                    BreakpointEditAction::Toggle,
11537                    cx,
11538                );
11539            }
11540        }
11541    }
11542
11543    pub fn edit_breakpoint_at_anchor(
11544        &mut self,
11545        breakpoint_position: Anchor,
11546        breakpoint: Breakpoint,
11547        edit_action: BreakpointEditAction,
11548        cx: &mut Context<Self>,
11549    ) {
11550        let Some(breakpoint_store) = &self.breakpoint_store else {
11551            return;
11552        };
11553
11554        let Some(buffer) = self
11555            .buffer
11556            .read(cx)
11557            .buffer_for_anchor(breakpoint_position, cx)
11558        else {
11559            return;
11560        };
11561
11562        breakpoint_store.update(cx, |breakpoint_store, cx| {
11563            breakpoint_store.toggle_breakpoint(
11564                buffer,
11565                BreakpointWithPosition {
11566                    position: breakpoint_position.text_anchor,
11567                    bp: breakpoint,
11568                },
11569                edit_action,
11570                cx,
11571            );
11572        });
11573
11574        cx.notify();
11575    }
11576
11577    #[cfg(any(test, feature = "test-support"))]
11578    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11579        self.breakpoint_store.clone()
11580    }
11581
11582    pub fn prepare_restore_change(
11583        &self,
11584        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11585        hunk: &MultiBufferDiffHunk,
11586        cx: &mut App,
11587    ) -> Option<()> {
11588        if hunk.is_created_file() {
11589            return None;
11590        }
11591        let buffer = self.buffer.read(cx);
11592        let diff = buffer.diff_for(hunk.buffer_id)?;
11593        let buffer = buffer.buffer(hunk.buffer_id)?;
11594        let buffer = buffer.read(cx);
11595        let original_text = diff
11596            .read(cx)
11597            .base_text()
11598            .as_rope()
11599            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11600        let buffer_snapshot = buffer.snapshot();
11601        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11602        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11603            probe
11604                .0
11605                .start
11606                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11607                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11608        }) {
11609            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11610            Some(())
11611        } else {
11612            None
11613        }
11614    }
11615
11616    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11617        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11618    }
11619
11620    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11621        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11622    }
11623
11624    pub fn rotate_selections_forward(
11625        &mut self,
11626        _: &RotateSelectionsForward,
11627        window: &mut Window,
11628        cx: &mut Context<Self>,
11629    ) {
11630        self.rotate_selections(window, cx, false)
11631    }
11632
11633    pub fn rotate_selections_backward(
11634        &mut self,
11635        _: &RotateSelectionsBackward,
11636        window: &mut Window,
11637        cx: &mut Context<Self>,
11638    ) {
11639        self.rotate_selections(window, cx, true)
11640    }
11641
11642    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11643        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11644        let display_snapshot = self.display_snapshot(cx);
11645        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11646
11647        if selections.len() < 2 {
11648            return;
11649        }
11650
11651        let (edits, new_selections) = {
11652            let buffer = self.buffer.read(cx).read(cx);
11653            let has_selections = selections.iter().any(|s| !s.is_empty());
11654            if has_selections {
11655                let mut selected_texts: Vec<String> = selections
11656                    .iter()
11657                    .map(|selection| {
11658                        buffer
11659                            .text_for_range(selection.start..selection.end)
11660                            .collect()
11661                    })
11662                    .collect();
11663
11664                if reverse {
11665                    selected_texts.rotate_left(1);
11666                } else {
11667                    selected_texts.rotate_right(1);
11668                }
11669
11670                let mut offset_delta: i64 = 0;
11671                let mut new_selections = Vec::new();
11672                let edits: Vec<_> = selections
11673                    .iter()
11674                    .zip(selected_texts.iter())
11675                    .map(|(selection, new_text)| {
11676                        let old_len = (selection.end.0 - selection.start.0) as i64;
11677                        let new_len = new_text.len() as i64;
11678                        let adjusted_start =
11679                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11680                        let adjusted_end =
11681                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11682
11683                        new_selections.push(Selection {
11684                            id: selection.id,
11685                            start: adjusted_start,
11686                            end: adjusted_end,
11687                            reversed: selection.reversed,
11688                            goal: selection.goal,
11689                        });
11690
11691                        offset_delta += new_len - old_len;
11692                        (selection.start..selection.end, new_text.clone())
11693                    })
11694                    .collect();
11695                (edits, new_selections)
11696            } else {
11697                let mut all_rows: Vec<u32> = selections
11698                    .iter()
11699                    .map(|selection| buffer.offset_to_point(selection.start).row)
11700                    .collect();
11701                all_rows.sort_unstable();
11702                all_rows.dedup();
11703
11704                if all_rows.len() < 2 {
11705                    return;
11706                }
11707
11708                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11709                    .iter()
11710                    .map(|&row| {
11711                        let start = Point::new(row, 0);
11712                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11713                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11714                    })
11715                    .collect();
11716
11717                let mut line_texts: Vec<String> = line_ranges
11718                    .iter()
11719                    .map(|range| buffer.text_for_range(range.clone()).collect())
11720                    .collect();
11721
11722                if reverse {
11723                    line_texts.rotate_left(1);
11724                } else {
11725                    line_texts.rotate_right(1);
11726                }
11727
11728                let edits = line_ranges
11729                    .iter()
11730                    .zip(line_texts.iter())
11731                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11732                    .collect();
11733
11734                let num_rows = all_rows.len();
11735                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11736                    .iter()
11737                    .enumerate()
11738                    .map(|(i, &row)| (row, i))
11739                    .collect();
11740
11741                // Compute new line start offsets after rotation (handles CRLF)
11742                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11743                let first_line_start = line_ranges[0].start.0;
11744                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11745                for text in line_texts.iter().take(num_rows - 1) {
11746                    let prev_start = *new_line_starts.last().unwrap();
11747                    new_line_starts.push(prev_start + text.len() + newline_len);
11748                }
11749
11750                let new_selections = selections
11751                    .iter()
11752                    .map(|selection| {
11753                        let point = buffer.offset_to_point(selection.start);
11754                        let old_index = row_to_index[&point.row];
11755                        let new_index = if reverse {
11756                            (old_index + num_rows - 1) % num_rows
11757                        } else {
11758                            (old_index + 1) % num_rows
11759                        };
11760                        let new_offset =
11761                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11762                        Selection {
11763                            id: selection.id,
11764                            start: new_offset,
11765                            end: new_offset,
11766                            reversed: selection.reversed,
11767                            goal: selection.goal,
11768                        }
11769                    })
11770                    .collect();
11771
11772                (edits, new_selections)
11773            }
11774        };
11775
11776        self.transact(window, cx, |this, window, cx| {
11777            this.buffer.update(cx, |buffer, cx| {
11778                buffer.edit(edits, None, cx);
11779            });
11780            this.change_selections(Default::default(), window, cx, |s| {
11781                s.select(new_selections);
11782            });
11783        });
11784    }
11785
11786    fn manipulate_lines<M>(
11787        &mut self,
11788        window: &mut Window,
11789        cx: &mut Context<Self>,
11790        mut manipulate: M,
11791    ) where
11792        M: FnMut(&str) -> LineManipulationResult,
11793    {
11794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11795
11796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11797        let buffer = self.buffer.read(cx).snapshot(cx);
11798
11799        let mut edits = Vec::new();
11800
11801        let selections = self.selections.all::<Point>(&display_map);
11802        let mut selections = selections.iter().peekable();
11803        let mut contiguous_row_selections = Vec::new();
11804        let mut new_selections = Vec::new();
11805        let mut added_lines = 0;
11806        let mut removed_lines = 0;
11807
11808        while let Some(selection) = selections.next() {
11809            let (start_row, end_row) = consume_contiguous_rows(
11810                &mut contiguous_row_selections,
11811                selection,
11812                &display_map,
11813                &mut selections,
11814            );
11815
11816            let start_point = Point::new(start_row.0, 0);
11817            let end_point = Point::new(
11818                end_row.previous_row().0,
11819                buffer.line_len(end_row.previous_row()),
11820            );
11821            let text = buffer
11822                .text_for_range(start_point..end_point)
11823                .collect::<String>();
11824
11825            let LineManipulationResult {
11826                new_text,
11827                line_count_before,
11828                line_count_after,
11829            } = manipulate(&text);
11830
11831            edits.push((start_point..end_point, new_text));
11832
11833            // Selections must change based on added and removed line count
11834            let start_row =
11835                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11836            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11837            new_selections.push(Selection {
11838                id: selection.id,
11839                start: start_row,
11840                end: end_row,
11841                goal: SelectionGoal::None,
11842                reversed: selection.reversed,
11843            });
11844
11845            if line_count_after > line_count_before {
11846                added_lines += line_count_after - line_count_before;
11847            } else if line_count_before > line_count_after {
11848                removed_lines += line_count_before - line_count_after;
11849            }
11850        }
11851
11852        self.transact(window, cx, |this, window, cx| {
11853            let buffer = this.buffer.update(cx, |buffer, cx| {
11854                buffer.edit(edits, None, cx);
11855                buffer.snapshot(cx)
11856            });
11857
11858            // Recalculate offsets on newly edited buffer
11859            let new_selections = new_selections
11860                .iter()
11861                .map(|s| {
11862                    let start_point = Point::new(s.start.0, 0);
11863                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11864                    Selection {
11865                        id: s.id,
11866                        start: buffer.point_to_offset(start_point),
11867                        end: buffer.point_to_offset(end_point),
11868                        goal: s.goal,
11869                        reversed: s.reversed,
11870                    }
11871                })
11872                .collect();
11873
11874            this.change_selections(Default::default(), window, cx, |s| {
11875                s.select(new_selections);
11876            });
11877
11878            this.request_autoscroll(Autoscroll::fit(), cx);
11879        });
11880    }
11881
11882    fn manipulate_immutable_lines<Fn>(
11883        &mut self,
11884        window: &mut Window,
11885        cx: &mut Context<Self>,
11886        mut callback: Fn,
11887    ) where
11888        Fn: FnMut(&mut Vec<&str>),
11889    {
11890        self.manipulate_lines(window, cx, |text| {
11891            let mut lines: Vec<&str> = text.split('\n').collect();
11892            let line_count_before = lines.len();
11893
11894            callback(&mut lines);
11895
11896            LineManipulationResult {
11897                new_text: lines.join("\n"),
11898                line_count_before,
11899                line_count_after: lines.len(),
11900            }
11901        });
11902    }
11903
11904    fn manipulate_mutable_lines<Fn>(
11905        &mut self,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908        mut callback: Fn,
11909    ) where
11910        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11911    {
11912        self.manipulate_lines(window, cx, |text| {
11913            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11914            let line_count_before = lines.len();
11915
11916            callback(&mut lines);
11917
11918            LineManipulationResult {
11919                new_text: lines.join("\n"),
11920                line_count_before,
11921                line_count_after: lines.len(),
11922            }
11923        });
11924    }
11925
11926    pub fn convert_indentation_to_spaces(
11927        &mut self,
11928        _: &ConvertIndentationToSpaces,
11929        window: &mut Window,
11930        cx: &mut Context<Self>,
11931    ) {
11932        let settings = self.buffer.read(cx).language_settings(cx);
11933        let tab_size = settings.tab_size.get() as usize;
11934
11935        self.manipulate_mutable_lines(window, cx, |lines| {
11936            // Allocates a reasonably sized scratch buffer once for the whole loop
11937            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11938            // Avoids recomputing spaces that could be inserted many times
11939            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11940                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11941                .collect();
11942
11943            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11944                let mut chars = line.as_ref().chars();
11945                let mut col = 0;
11946                let mut changed = false;
11947
11948                for ch in chars.by_ref() {
11949                    match ch {
11950                        ' ' => {
11951                            reindented_line.push(' ');
11952                            col += 1;
11953                        }
11954                        '\t' => {
11955                            // \t are converted to spaces depending on the current column
11956                            let spaces_len = tab_size - (col % tab_size);
11957                            reindented_line.extend(&space_cache[spaces_len - 1]);
11958                            col += spaces_len;
11959                            changed = true;
11960                        }
11961                        _ => {
11962                            // If we dont append before break, the character is consumed
11963                            reindented_line.push(ch);
11964                            break;
11965                        }
11966                    }
11967                }
11968
11969                if !changed {
11970                    reindented_line.clear();
11971                    continue;
11972                }
11973                // Append the rest of the line and replace old reference with new one
11974                reindented_line.extend(chars);
11975                *line = Cow::Owned(reindented_line.clone());
11976                reindented_line.clear();
11977            }
11978        });
11979    }
11980
11981    pub fn convert_indentation_to_tabs(
11982        &mut self,
11983        _: &ConvertIndentationToTabs,
11984        window: &mut Window,
11985        cx: &mut Context<Self>,
11986    ) {
11987        let settings = self.buffer.read(cx).language_settings(cx);
11988        let tab_size = settings.tab_size.get() as usize;
11989
11990        self.manipulate_mutable_lines(window, cx, |lines| {
11991            // Allocates a reasonably sized buffer once for the whole loop
11992            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11993            // Avoids recomputing spaces that could be inserted many times
11994            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11995                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11996                .collect();
11997
11998            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11999                let mut chars = line.chars();
12000                let mut spaces_count = 0;
12001                let mut first_non_indent_char = None;
12002                let mut changed = false;
12003
12004                for ch in chars.by_ref() {
12005                    match ch {
12006                        ' ' => {
12007                            // Keep track of spaces. Append \t when we reach tab_size
12008                            spaces_count += 1;
12009                            changed = true;
12010                            if spaces_count == tab_size {
12011                                reindented_line.push('\t');
12012                                spaces_count = 0;
12013                            }
12014                        }
12015                        '\t' => {
12016                            reindented_line.push('\t');
12017                            spaces_count = 0;
12018                        }
12019                        _ => {
12020                            // Dont append it yet, we might have remaining spaces
12021                            first_non_indent_char = Some(ch);
12022                            break;
12023                        }
12024                    }
12025                }
12026
12027                if !changed {
12028                    reindented_line.clear();
12029                    continue;
12030                }
12031                // Remaining spaces that didn't make a full tab stop
12032                if spaces_count > 0 {
12033                    reindented_line.extend(&space_cache[spaces_count - 1]);
12034                }
12035                // If we consume an extra character that was not indentation, add it back
12036                if let Some(extra_char) = first_non_indent_char {
12037                    reindented_line.push(extra_char);
12038                }
12039                // Append the rest of the line and replace old reference with new one
12040                reindented_line.extend(chars);
12041                *line = Cow::Owned(reindented_line.clone());
12042                reindented_line.clear();
12043            }
12044        });
12045    }
12046
12047    pub fn convert_to_upper_case(
12048        &mut self,
12049        _: &ConvertToUpperCase,
12050        window: &mut Window,
12051        cx: &mut Context<Self>,
12052    ) {
12053        self.manipulate_text(window, cx, |text| text.to_uppercase())
12054    }
12055
12056    pub fn convert_to_lower_case(
12057        &mut self,
12058        _: &ConvertToLowerCase,
12059        window: &mut Window,
12060        cx: &mut Context<Self>,
12061    ) {
12062        self.manipulate_text(window, cx, |text| text.to_lowercase())
12063    }
12064
12065    pub fn convert_to_title_case(
12066        &mut self,
12067        _: &ConvertToTitleCase,
12068        window: &mut Window,
12069        cx: &mut Context<Self>,
12070    ) {
12071        self.manipulate_text(window, cx, |text| {
12072            text.split('\n')
12073                .map(|line| line.to_case(Case::Title))
12074                .join("\n")
12075        })
12076    }
12077
12078    pub fn convert_to_snake_case(
12079        &mut self,
12080        _: &ConvertToSnakeCase,
12081        window: &mut Window,
12082        cx: &mut Context<Self>,
12083    ) {
12084        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12085    }
12086
12087    pub fn convert_to_kebab_case(
12088        &mut self,
12089        _: &ConvertToKebabCase,
12090        window: &mut Window,
12091        cx: &mut Context<Self>,
12092    ) {
12093        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12094    }
12095
12096    pub fn convert_to_upper_camel_case(
12097        &mut self,
12098        _: &ConvertToUpperCamelCase,
12099        window: &mut Window,
12100        cx: &mut Context<Self>,
12101    ) {
12102        self.manipulate_text(window, cx, |text| {
12103            text.split('\n')
12104                .map(|line| line.to_case(Case::UpperCamel))
12105                .join("\n")
12106        })
12107    }
12108
12109    pub fn convert_to_lower_camel_case(
12110        &mut self,
12111        _: &ConvertToLowerCamelCase,
12112        window: &mut Window,
12113        cx: &mut Context<Self>,
12114    ) {
12115        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12116    }
12117
12118    pub fn convert_to_opposite_case(
12119        &mut self,
12120        _: &ConvertToOppositeCase,
12121        window: &mut Window,
12122        cx: &mut Context<Self>,
12123    ) {
12124        self.manipulate_text(window, cx, |text| {
12125            text.chars()
12126                .fold(String::with_capacity(text.len()), |mut t, c| {
12127                    if c.is_uppercase() {
12128                        t.extend(c.to_lowercase());
12129                    } else {
12130                        t.extend(c.to_uppercase());
12131                    }
12132                    t
12133                })
12134        })
12135    }
12136
12137    pub fn convert_to_sentence_case(
12138        &mut self,
12139        _: &ConvertToSentenceCase,
12140        window: &mut Window,
12141        cx: &mut Context<Self>,
12142    ) {
12143        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12144    }
12145
12146    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12147        self.manipulate_text(window, cx, |text| {
12148            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12149            if has_upper_case_characters {
12150                text.to_lowercase()
12151            } else {
12152                text.to_uppercase()
12153            }
12154        })
12155    }
12156
12157    pub fn convert_to_rot13(
12158        &mut self,
12159        _: &ConvertToRot13,
12160        window: &mut Window,
12161        cx: &mut Context<Self>,
12162    ) {
12163        self.manipulate_text(window, cx, |text| {
12164            text.chars()
12165                .map(|c| match c {
12166                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12167                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12168                    _ => c,
12169                })
12170                .collect()
12171        })
12172    }
12173
12174    pub fn convert_to_rot47(
12175        &mut self,
12176        _: &ConvertToRot47,
12177        window: &mut Window,
12178        cx: &mut Context<Self>,
12179    ) {
12180        self.manipulate_text(window, cx, |text| {
12181            text.chars()
12182                .map(|c| {
12183                    let code_point = c as u32;
12184                    if code_point >= 33 && code_point <= 126 {
12185                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12186                    }
12187                    c
12188                })
12189                .collect()
12190        })
12191    }
12192
12193    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12194    where
12195        Fn: FnMut(&str) -> String,
12196    {
12197        let buffer = self.buffer.read(cx).snapshot(cx);
12198
12199        let mut new_selections = Vec::new();
12200        let mut edits = Vec::new();
12201        let mut selection_adjustment = 0isize;
12202
12203        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12204            let selection_is_empty = selection.is_empty();
12205
12206            let (start, end) = if selection_is_empty {
12207                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12208                (word_range.start, word_range.end)
12209            } else {
12210                (
12211                    buffer.point_to_offset(selection.start),
12212                    buffer.point_to_offset(selection.end),
12213                )
12214            };
12215
12216            let text = buffer.text_for_range(start..end).collect::<String>();
12217            let old_length = text.len() as isize;
12218            let text = callback(&text);
12219
12220            new_selections.push(Selection {
12221                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12222                end: MultiBufferOffset(
12223                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12224                ),
12225                goal: SelectionGoal::None,
12226                id: selection.id,
12227                reversed: selection.reversed,
12228            });
12229
12230            selection_adjustment += old_length - text.len() as isize;
12231
12232            edits.push((start..end, text));
12233        }
12234
12235        self.transact(window, cx, |this, window, cx| {
12236            this.buffer.update(cx, |buffer, cx| {
12237                buffer.edit(edits, None, cx);
12238            });
12239
12240            this.change_selections(Default::default(), window, cx, |s| {
12241                s.select(new_selections);
12242            });
12243
12244            this.request_autoscroll(Autoscroll::fit(), cx);
12245        });
12246    }
12247
12248    pub fn move_selection_on_drop(
12249        &mut self,
12250        selection: &Selection<Anchor>,
12251        target: DisplayPoint,
12252        is_cut: bool,
12253        window: &mut Window,
12254        cx: &mut Context<Self>,
12255    ) {
12256        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12257        let buffer = display_map.buffer_snapshot();
12258        let mut edits = Vec::new();
12259        let insert_point = display_map
12260            .clip_point(target, Bias::Left)
12261            .to_point(&display_map);
12262        let text = buffer
12263            .text_for_range(selection.start..selection.end)
12264            .collect::<String>();
12265        if is_cut {
12266            edits.push(((selection.start..selection.end), String::new()));
12267        }
12268        let insert_anchor = buffer.anchor_before(insert_point);
12269        edits.push(((insert_anchor..insert_anchor), text));
12270        let last_edit_start = insert_anchor.bias_left(buffer);
12271        let last_edit_end = insert_anchor.bias_right(buffer);
12272        self.transact(window, cx, |this, window, cx| {
12273            this.buffer.update(cx, |buffer, cx| {
12274                buffer.edit(edits, None, cx);
12275            });
12276            this.change_selections(Default::default(), window, cx, |s| {
12277                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12278            });
12279        });
12280    }
12281
12282    pub fn clear_selection_drag_state(&mut self) {
12283        self.selection_drag_state = SelectionDragState::None;
12284    }
12285
12286    pub fn duplicate(
12287        &mut self,
12288        upwards: bool,
12289        whole_lines: bool,
12290        window: &mut Window,
12291        cx: &mut Context<Self>,
12292    ) {
12293        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12294
12295        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12296        let buffer = display_map.buffer_snapshot();
12297        let selections = self.selections.all::<Point>(&display_map);
12298
12299        let mut edits = Vec::new();
12300        let mut selections_iter = selections.iter().peekable();
12301        while let Some(selection) = selections_iter.next() {
12302            let mut rows = selection.spanned_rows(false, &display_map);
12303            // duplicate line-wise
12304            if whole_lines || selection.start == selection.end {
12305                // Avoid duplicating the same lines twice.
12306                while let Some(next_selection) = selections_iter.peek() {
12307                    let next_rows = next_selection.spanned_rows(false, &display_map);
12308                    if next_rows.start < rows.end {
12309                        rows.end = next_rows.end;
12310                        selections_iter.next().unwrap();
12311                    } else {
12312                        break;
12313                    }
12314                }
12315
12316                // Copy the text from the selected row region and splice it either at the start
12317                // or end of the region.
12318                let start = Point::new(rows.start.0, 0);
12319                let end = Point::new(
12320                    rows.end.previous_row().0,
12321                    buffer.line_len(rows.end.previous_row()),
12322                );
12323
12324                let mut text = buffer.text_for_range(start..end).collect::<String>();
12325
12326                let insert_location = if upwards {
12327                    // When duplicating upward, we need to insert before the current line.
12328                    // If we're on the last line and it doesn't end with a newline,
12329                    // we need to add a newline before the duplicated content.
12330                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12331                        && buffer.max_point().column > 0
12332                        && !text.ends_with('\n');
12333
12334                    if needs_leading_newline {
12335                        text.insert(0, '\n');
12336                        end
12337                    } else {
12338                        text.push('\n');
12339                        Point::new(rows.start.0, 0)
12340                    }
12341                } else {
12342                    text.push('\n');
12343                    start
12344                };
12345                edits.push((insert_location..insert_location, text));
12346            } else {
12347                // duplicate character-wise
12348                let start = selection.start;
12349                let end = selection.end;
12350                let text = buffer.text_for_range(start..end).collect::<String>();
12351                edits.push((selection.end..selection.end, text));
12352            }
12353        }
12354
12355        self.transact(window, cx, |this, window, cx| {
12356            this.buffer.update(cx, |buffer, cx| {
12357                buffer.edit(edits, None, cx);
12358            });
12359
12360            // When duplicating upward with whole lines, move the cursor to the duplicated line
12361            if upwards && whole_lines {
12362                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12363
12364                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12365                    let mut new_ranges = Vec::new();
12366                    let selections = s.all::<Point>(&display_map);
12367                    let mut selections_iter = selections.iter().peekable();
12368
12369                    while let Some(first_selection) = selections_iter.next() {
12370                        // Group contiguous selections together to find the total row span
12371                        let mut group_selections = vec![first_selection];
12372                        let mut rows = first_selection.spanned_rows(false, &display_map);
12373
12374                        while let Some(next_selection) = selections_iter.peek() {
12375                            let next_rows = next_selection.spanned_rows(false, &display_map);
12376                            if next_rows.start < rows.end {
12377                                rows.end = next_rows.end;
12378                                group_selections.push(selections_iter.next().unwrap());
12379                            } else {
12380                                break;
12381                            }
12382                        }
12383
12384                        let row_count = rows.end.0 - rows.start.0;
12385
12386                        // Move all selections in this group up by the total number of duplicated rows
12387                        for selection in group_selections {
12388                            let new_start = Point::new(
12389                                selection.start.row.saturating_sub(row_count),
12390                                selection.start.column,
12391                            );
12392
12393                            let new_end = Point::new(
12394                                selection.end.row.saturating_sub(row_count),
12395                                selection.end.column,
12396                            );
12397
12398                            new_ranges.push(new_start..new_end);
12399                        }
12400                    }
12401
12402                    s.select_ranges(new_ranges);
12403                });
12404            }
12405
12406            this.request_autoscroll(Autoscroll::fit(), cx);
12407        });
12408    }
12409
12410    pub fn duplicate_line_up(
12411        &mut self,
12412        _: &DuplicateLineUp,
12413        window: &mut Window,
12414        cx: &mut Context<Self>,
12415    ) {
12416        self.duplicate(true, true, window, cx);
12417    }
12418
12419    pub fn duplicate_line_down(
12420        &mut self,
12421        _: &DuplicateLineDown,
12422        window: &mut Window,
12423        cx: &mut Context<Self>,
12424    ) {
12425        self.duplicate(false, true, window, cx);
12426    }
12427
12428    pub fn duplicate_selection(
12429        &mut self,
12430        _: &DuplicateSelection,
12431        window: &mut Window,
12432        cx: &mut Context<Self>,
12433    ) {
12434        self.duplicate(false, false, window, cx);
12435    }
12436
12437    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12439        if self.mode.is_single_line() {
12440            cx.propagate();
12441            return;
12442        }
12443
12444        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12445        let buffer = self.buffer.read(cx).snapshot(cx);
12446
12447        let mut edits = Vec::new();
12448        let mut unfold_ranges = Vec::new();
12449        let mut refold_creases = Vec::new();
12450
12451        let selections = self.selections.all::<Point>(&display_map);
12452        let mut selections = selections.iter().peekable();
12453        let mut contiguous_row_selections = Vec::new();
12454        let mut new_selections = Vec::new();
12455
12456        while let Some(selection) = selections.next() {
12457            // Find all the selections that span a contiguous row range
12458            let (start_row, end_row) = consume_contiguous_rows(
12459                &mut contiguous_row_selections,
12460                selection,
12461                &display_map,
12462                &mut selections,
12463            );
12464
12465            // Move the text spanned by the row range to be before the line preceding the row range
12466            if start_row.0 > 0 {
12467                let range_to_move = Point::new(
12468                    start_row.previous_row().0,
12469                    buffer.line_len(start_row.previous_row()),
12470                )
12471                    ..Point::new(
12472                        end_row.previous_row().0,
12473                        buffer.line_len(end_row.previous_row()),
12474                    );
12475                let insertion_point = display_map
12476                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12477                    .0;
12478
12479                // Don't move lines across excerpts
12480                if buffer
12481                    .excerpt_containing(insertion_point..range_to_move.end)
12482                    .is_some()
12483                {
12484                    let text = buffer
12485                        .text_for_range(range_to_move.clone())
12486                        .flat_map(|s| s.chars())
12487                        .skip(1)
12488                        .chain(['\n'])
12489                        .collect::<String>();
12490
12491                    edits.push((
12492                        buffer.anchor_after(range_to_move.start)
12493                            ..buffer.anchor_before(range_to_move.end),
12494                        String::new(),
12495                    ));
12496                    let insertion_anchor = buffer.anchor_after(insertion_point);
12497                    edits.push((insertion_anchor..insertion_anchor, text));
12498
12499                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12500
12501                    // Move selections up
12502                    new_selections.extend(contiguous_row_selections.drain(..).map(
12503                        |mut selection| {
12504                            selection.start.row -= row_delta;
12505                            selection.end.row -= row_delta;
12506                            selection
12507                        },
12508                    ));
12509
12510                    // Move folds up
12511                    unfold_ranges.push(range_to_move.clone());
12512                    for fold in display_map.folds_in_range(
12513                        buffer.anchor_before(range_to_move.start)
12514                            ..buffer.anchor_after(range_to_move.end),
12515                    ) {
12516                        let mut start = fold.range.start.to_point(&buffer);
12517                        let mut end = fold.range.end.to_point(&buffer);
12518                        start.row -= row_delta;
12519                        end.row -= row_delta;
12520                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12521                    }
12522                }
12523            }
12524
12525            // If we didn't move line(s), preserve the existing selections
12526            new_selections.append(&mut contiguous_row_selections);
12527        }
12528
12529        self.transact(window, cx, |this, window, cx| {
12530            this.unfold_ranges(&unfold_ranges, true, true, cx);
12531            this.buffer.update(cx, |buffer, cx| {
12532                for (range, text) in edits {
12533                    buffer.edit([(range, text)], None, cx);
12534                }
12535            });
12536            this.fold_creases(refold_creases, true, window, cx);
12537            this.change_selections(Default::default(), window, cx, |s| {
12538                s.select(new_selections);
12539            })
12540        });
12541    }
12542
12543    pub fn move_line_down(
12544        &mut self,
12545        _: &MoveLineDown,
12546        window: &mut Window,
12547        cx: &mut Context<Self>,
12548    ) {
12549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12550        if self.mode.is_single_line() {
12551            cx.propagate();
12552            return;
12553        }
12554
12555        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12556        let buffer = self.buffer.read(cx).snapshot(cx);
12557
12558        let mut edits = Vec::new();
12559        let mut unfold_ranges = Vec::new();
12560        let mut refold_creases = Vec::new();
12561
12562        let selections = self.selections.all::<Point>(&display_map);
12563        let mut selections = selections.iter().peekable();
12564        let mut contiguous_row_selections = Vec::new();
12565        let mut new_selections = Vec::new();
12566
12567        while let Some(selection) = selections.next() {
12568            // Find all the selections that span a contiguous row range
12569            let (start_row, end_row) = consume_contiguous_rows(
12570                &mut contiguous_row_selections,
12571                selection,
12572                &display_map,
12573                &mut selections,
12574            );
12575
12576            // Move the text spanned by the row range to be after the last line of the row range
12577            if end_row.0 <= buffer.max_point().row {
12578                let range_to_move =
12579                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12580                let insertion_point = display_map
12581                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12582                    .0;
12583
12584                // Don't move lines across excerpt boundaries
12585                if buffer
12586                    .excerpt_containing(range_to_move.start..insertion_point)
12587                    .is_some()
12588                {
12589                    let mut text = String::from("\n");
12590                    text.extend(buffer.text_for_range(range_to_move.clone()));
12591                    text.pop(); // Drop trailing newline
12592                    edits.push((
12593                        buffer.anchor_after(range_to_move.start)
12594                            ..buffer.anchor_before(range_to_move.end),
12595                        String::new(),
12596                    ));
12597                    let insertion_anchor = buffer.anchor_after(insertion_point);
12598                    edits.push((insertion_anchor..insertion_anchor, text));
12599
12600                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12601
12602                    // Move selections down
12603                    new_selections.extend(contiguous_row_selections.drain(..).map(
12604                        |mut selection| {
12605                            selection.start.row += row_delta;
12606                            selection.end.row += row_delta;
12607                            selection
12608                        },
12609                    ));
12610
12611                    // Move folds down
12612                    unfold_ranges.push(range_to_move.clone());
12613                    for fold in display_map.folds_in_range(
12614                        buffer.anchor_before(range_to_move.start)
12615                            ..buffer.anchor_after(range_to_move.end),
12616                    ) {
12617                        let mut start = fold.range.start.to_point(&buffer);
12618                        let mut end = fold.range.end.to_point(&buffer);
12619                        start.row += row_delta;
12620                        end.row += row_delta;
12621                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12622                    }
12623                }
12624            }
12625
12626            // If we didn't move line(s), preserve the existing selections
12627            new_selections.append(&mut contiguous_row_selections);
12628        }
12629
12630        self.transact(window, cx, |this, window, cx| {
12631            this.unfold_ranges(&unfold_ranges, true, true, cx);
12632            this.buffer.update(cx, |buffer, cx| {
12633                for (range, text) in edits {
12634                    buffer.edit([(range, text)], None, cx);
12635                }
12636            });
12637            this.fold_creases(refold_creases, true, window, cx);
12638            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12639        });
12640    }
12641
12642    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12643        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12644        let text_layout_details = &self.text_layout_details(window);
12645        self.transact(window, cx, |this, window, cx| {
12646            let edits = this.change_selections(Default::default(), window, cx, |s| {
12647                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12648                s.move_with(|display_map, selection| {
12649                    if !selection.is_empty() {
12650                        return;
12651                    }
12652
12653                    let mut head = selection.head();
12654                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12655                    if head.column() == display_map.line_len(head.row()) {
12656                        transpose_offset = display_map
12657                            .buffer_snapshot()
12658                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12659                    }
12660
12661                    if transpose_offset == MultiBufferOffset(0) {
12662                        return;
12663                    }
12664
12665                    *head.column_mut() += 1;
12666                    head = display_map.clip_point(head, Bias::Right);
12667                    let goal = SelectionGoal::HorizontalPosition(
12668                        display_map
12669                            .x_for_display_point(head, text_layout_details)
12670                            .into(),
12671                    );
12672                    selection.collapse_to(head, goal);
12673
12674                    let transpose_start = display_map
12675                        .buffer_snapshot()
12676                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12677                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12678                        let transpose_end = display_map
12679                            .buffer_snapshot()
12680                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12681                        if let Some(ch) = display_map
12682                            .buffer_snapshot()
12683                            .chars_at(transpose_start)
12684                            .next()
12685                        {
12686                            edits.push((transpose_start..transpose_offset, String::new()));
12687                            edits.push((transpose_end..transpose_end, ch.to_string()));
12688                        }
12689                    }
12690                });
12691                edits
12692            });
12693            this.buffer
12694                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12695            let selections = this
12696                .selections
12697                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12698            this.change_selections(Default::default(), window, cx, |s| {
12699                s.select(selections);
12700            });
12701        });
12702    }
12703
12704    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12705        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12706        if self.mode.is_single_line() {
12707            cx.propagate();
12708            return;
12709        }
12710
12711        self.rewrap_impl(RewrapOptions::default(), cx)
12712    }
12713
12714    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12715        let buffer = self.buffer.read(cx).snapshot(cx);
12716        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12717
12718        #[derive(Clone, Debug, PartialEq)]
12719        enum CommentFormat {
12720            /// single line comment, with prefix for line
12721            Line(String),
12722            /// single line within a block comment, with prefix for line
12723            BlockLine(String),
12724            /// a single line of a block comment that includes the initial delimiter
12725            BlockCommentWithStart(BlockCommentConfig),
12726            /// a single line of a block comment that includes the ending delimiter
12727            BlockCommentWithEnd(BlockCommentConfig),
12728        }
12729
12730        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12731        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12732            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12733                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12734                .peekable();
12735
12736            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12737                row
12738            } else {
12739                return Vec::new();
12740            };
12741
12742            let language_settings = buffer.language_settings_at(selection.head(), cx);
12743            let language_scope = buffer.language_scope_at(selection.head());
12744
12745            let indent_and_prefix_for_row =
12746                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12747                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12748                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12749                        &language_scope
12750                    {
12751                        let indent_end = Point::new(row, indent.len);
12752                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12753                        let line_text_after_indent = buffer
12754                            .text_for_range(indent_end..line_end)
12755                            .collect::<String>();
12756
12757                        let is_within_comment_override = buffer
12758                            .language_scope_at(indent_end)
12759                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12760                        let comment_delimiters = if is_within_comment_override {
12761                            // we are within a comment syntax node, but we don't
12762                            // yet know what kind of comment: block, doc or line
12763                            match (
12764                                language_scope.documentation_comment(),
12765                                language_scope.block_comment(),
12766                            ) {
12767                                (Some(config), _) | (_, Some(config))
12768                                    if buffer.contains_str_at(indent_end, &config.start) =>
12769                                {
12770                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12771                                }
12772                                (Some(config), _) | (_, Some(config))
12773                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12774                                {
12775                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12776                                }
12777                                (Some(config), _) | (_, Some(config))
12778                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12779                                {
12780                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12781                                }
12782                                (_, _) => language_scope
12783                                    .line_comment_prefixes()
12784                                    .iter()
12785                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12786                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12787                            }
12788                        } else {
12789                            // we not in an overridden comment node, but we may
12790                            // be within a non-overridden line comment node
12791                            language_scope
12792                                .line_comment_prefixes()
12793                                .iter()
12794                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12795                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12796                        };
12797
12798                        let rewrap_prefix = language_scope
12799                            .rewrap_prefixes()
12800                            .iter()
12801                            .find_map(|prefix_regex| {
12802                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12803                                    if mat.start() == 0 {
12804                                        Some(mat.as_str().to_string())
12805                                    } else {
12806                                        None
12807                                    }
12808                                })
12809                            })
12810                            .flatten();
12811                        (comment_delimiters, rewrap_prefix)
12812                    } else {
12813                        (None, None)
12814                    };
12815                    (indent, comment_prefix, rewrap_prefix)
12816                };
12817
12818            let mut ranges = Vec::new();
12819            let from_empty_selection = selection.is_empty();
12820
12821            let mut current_range_start = first_row;
12822            let mut prev_row = first_row;
12823            let (
12824                mut current_range_indent,
12825                mut current_range_comment_delimiters,
12826                mut current_range_rewrap_prefix,
12827            ) = indent_and_prefix_for_row(first_row);
12828
12829            for row in non_blank_rows_iter.skip(1) {
12830                let has_paragraph_break = row > prev_row + 1;
12831
12832                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12833                    indent_and_prefix_for_row(row);
12834
12835                let has_indent_change = row_indent != current_range_indent;
12836                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12837
12838                let has_boundary_change = has_comment_change
12839                    || row_rewrap_prefix.is_some()
12840                    || (has_indent_change && current_range_comment_delimiters.is_some());
12841
12842                if has_paragraph_break || has_boundary_change {
12843                    ranges.push((
12844                        language_settings.clone(),
12845                        Point::new(current_range_start, 0)
12846                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12847                        current_range_indent,
12848                        current_range_comment_delimiters.clone(),
12849                        current_range_rewrap_prefix.clone(),
12850                        from_empty_selection,
12851                    ));
12852                    current_range_start = row;
12853                    current_range_indent = row_indent;
12854                    current_range_comment_delimiters = row_comment_delimiters;
12855                    current_range_rewrap_prefix = row_rewrap_prefix;
12856                }
12857                prev_row = row;
12858            }
12859
12860            ranges.push((
12861                language_settings.clone(),
12862                Point::new(current_range_start, 0)
12863                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12864                current_range_indent,
12865                current_range_comment_delimiters,
12866                current_range_rewrap_prefix,
12867                from_empty_selection,
12868            ));
12869
12870            ranges
12871        });
12872
12873        let mut edits = Vec::new();
12874        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12875
12876        for (
12877            language_settings,
12878            wrap_range,
12879            mut indent_size,
12880            comment_prefix,
12881            rewrap_prefix,
12882            from_empty_selection,
12883        ) in wrap_ranges
12884        {
12885            let mut start_row = wrap_range.start.row;
12886            let mut end_row = wrap_range.end.row;
12887
12888            // Skip selections that overlap with a range that has already been rewrapped.
12889            let selection_range = start_row..end_row;
12890            if rewrapped_row_ranges
12891                .iter()
12892                .any(|range| range.overlaps(&selection_range))
12893            {
12894                continue;
12895            }
12896
12897            let tab_size = language_settings.tab_size;
12898
12899            let (line_prefix, inside_comment) = match &comment_prefix {
12900                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12901                    (Some(prefix.as_str()), true)
12902                }
12903                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12904                    (Some(prefix.as_ref()), true)
12905                }
12906                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12907                    start: _,
12908                    end: _,
12909                    prefix,
12910                    tab_size,
12911                })) => {
12912                    indent_size.len += tab_size;
12913                    (Some(prefix.as_ref()), true)
12914                }
12915                None => (None, false),
12916            };
12917            let indent_prefix = indent_size.chars().collect::<String>();
12918            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12919
12920            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12921                RewrapBehavior::InComments => inside_comment,
12922                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12923                RewrapBehavior::Anywhere => true,
12924            };
12925
12926            let should_rewrap = options.override_language_settings
12927                || allow_rewrap_based_on_language
12928                || self.hard_wrap.is_some();
12929            if !should_rewrap {
12930                continue;
12931            }
12932
12933            if from_empty_selection {
12934                'expand_upwards: while start_row > 0 {
12935                    let prev_row = start_row - 1;
12936                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12937                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12938                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12939                    {
12940                        start_row = prev_row;
12941                    } else {
12942                        break 'expand_upwards;
12943                    }
12944                }
12945
12946                'expand_downwards: while end_row < buffer.max_point().row {
12947                    let next_row = end_row + 1;
12948                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12949                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12950                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12951                    {
12952                        end_row = next_row;
12953                    } else {
12954                        break 'expand_downwards;
12955                    }
12956                }
12957            }
12958
12959            let start = Point::new(start_row, 0);
12960            let start_offset = ToOffset::to_offset(&start, &buffer);
12961            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12962            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12963            let mut first_line_delimiter = None;
12964            let mut last_line_delimiter = None;
12965            let Some(lines_without_prefixes) = selection_text
12966                .lines()
12967                .enumerate()
12968                .map(|(ix, line)| {
12969                    let line_trimmed = line.trim_start();
12970                    if rewrap_prefix.is_some() && ix > 0 {
12971                        Ok(line_trimmed)
12972                    } else if let Some(
12973                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12974                            start,
12975                            prefix,
12976                            end,
12977                            tab_size,
12978                        })
12979                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12980                            start,
12981                            prefix,
12982                            end,
12983                            tab_size,
12984                        }),
12985                    ) = &comment_prefix
12986                    {
12987                        let line_trimmed = line_trimmed
12988                            .strip_prefix(start.as_ref())
12989                            .map(|s| {
12990                                let mut indent_size = indent_size;
12991                                indent_size.len -= tab_size;
12992                                let indent_prefix: String = indent_size.chars().collect();
12993                                first_line_delimiter = Some((indent_prefix, start));
12994                                s.trim_start()
12995                            })
12996                            .unwrap_or(line_trimmed);
12997                        let line_trimmed = line_trimmed
12998                            .strip_suffix(end.as_ref())
12999                            .map(|s| {
13000                                last_line_delimiter = Some(end);
13001                                s.trim_end()
13002                            })
13003                            .unwrap_or(line_trimmed);
13004                        let line_trimmed = line_trimmed
13005                            .strip_prefix(prefix.as_ref())
13006                            .unwrap_or(line_trimmed);
13007                        Ok(line_trimmed)
13008                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13009                        line_trimmed.strip_prefix(prefix).with_context(|| {
13010                            format!("line did not start with prefix {prefix:?}: {line:?}")
13011                        })
13012                    } else {
13013                        line_trimmed
13014                            .strip_prefix(&line_prefix.trim_start())
13015                            .with_context(|| {
13016                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13017                            })
13018                    }
13019                })
13020                .collect::<Result<Vec<_>, _>>()
13021                .log_err()
13022            else {
13023                continue;
13024            };
13025
13026            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13027                buffer
13028                    .language_settings_at(Point::new(start_row, 0), cx)
13029                    .preferred_line_length as usize
13030            });
13031
13032            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13033                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13034            } else {
13035                line_prefix.clone()
13036            };
13037
13038            let wrapped_text = {
13039                let mut wrapped_text = wrap_with_prefix(
13040                    line_prefix,
13041                    subsequent_lines_prefix,
13042                    lines_without_prefixes.join("\n"),
13043                    wrap_column,
13044                    tab_size,
13045                    options.preserve_existing_whitespace,
13046                );
13047
13048                if let Some((indent, delimiter)) = first_line_delimiter {
13049                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13050                }
13051                if let Some(last_line) = last_line_delimiter {
13052                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13053                }
13054
13055                wrapped_text
13056            };
13057
13058            // TODO: should always use char-based diff while still supporting cursor behavior that
13059            // matches vim.
13060            let mut diff_options = DiffOptions::default();
13061            if options.override_language_settings {
13062                diff_options.max_word_diff_len = 0;
13063                diff_options.max_word_diff_line_count = 0;
13064            } else {
13065                diff_options.max_word_diff_len = usize::MAX;
13066                diff_options.max_word_diff_line_count = usize::MAX;
13067            }
13068
13069            for (old_range, new_text) in
13070                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13071            {
13072                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13073                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13074                edits.push((edit_start..edit_end, new_text));
13075            }
13076
13077            rewrapped_row_ranges.push(start_row..=end_row);
13078        }
13079
13080        self.buffer
13081            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13082    }
13083
13084    pub fn cut_common(
13085        &mut self,
13086        cut_no_selection_line: bool,
13087        window: &mut Window,
13088        cx: &mut Context<Self>,
13089    ) -> ClipboardItem {
13090        let mut text = String::new();
13091        let buffer = self.buffer.read(cx).snapshot(cx);
13092        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13093        let mut clipboard_selections = Vec::with_capacity(selections.len());
13094        {
13095            let max_point = buffer.max_point();
13096            let mut is_first = true;
13097            let mut prev_selection_was_entire_line = false;
13098            for selection in &mut selections {
13099                let is_entire_line =
13100                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13101                if is_entire_line {
13102                    selection.start = Point::new(selection.start.row, 0);
13103                    if !selection.is_empty() && selection.end.column == 0 {
13104                        selection.end = cmp::min(max_point, selection.end);
13105                    } else {
13106                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13107                    }
13108                    selection.goal = SelectionGoal::None;
13109                }
13110                if is_first {
13111                    is_first = false;
13112                } else if !prev_selection_was_entire_line {
13113                    text += "\n";
13114                }
13115                prev_selection_was_entire_line = is_entire_line;
13116                let mut len = 0;
13117                for chunk in buffer.text_for_range(selection.start..selection.end) {
13118                    text.push_str(chunk);
13119                    len += chunk.len();
13120                }
13121
13122                clipboard_selections.push(ClipboardSelection::for_buffer(
13123                    len,
13124                    is_entire_line,
13125                    selection.range(),
13126                    &buffer,
13127                    self.project.as_ref(),
13128                    cx,
13129                ));
13130            }
13131        }
13132
13133        self.transact(window, cx, |this, window, cx| {
13134            this.change_selections(Default::default(), window, cx, |s| {
13135                s.select(selections);
13136            });
13137            this.insert("", window, cx);
13138        });
13139        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13140    }
13141
13142    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13144        let item = self.cut_common(true, window, cx);
13145        cx.write_to_clipboard(item);
13146    }
13147
13148    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13149        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13150        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13151            s.move_with(|snapshot, sel| {
13152                if sel.is_empty() {
13153                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13154                }
13155                if sel.is_empty() {
13156                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13157                }
13158            });
13159        });
13160        let item = self.cut_common(false, window, cx);
13161        cx.set_global(KillRing(item))
13162    }
13163
13164    pub fn kill_ring_yank(
13165        &mut self,
13166        _: &KillRingYank,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13171        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13172            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13173                (kill_ring.text().to_string(), kill_ring.metadata_json())
13174            } else {
13175                return;
13176            }
13177        } else {
13178            return;
13179        };
13180        self.do_paste(&text, metadata, false, window, cx);
13181    }
13182
13183    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13184        self.do_copy(true, cx);
13185    }
13186
13187    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13188        self.do_copy(false, cx);
13189    }
13190
13191    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13192        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13193        let buffer = self.buffer.read(cx).read(cx);
13194        let mut text = String::new();
13195
13196        let mut clipboard_selections = Vec::with_capacity(selections.len());
13197        {
13198            let max_point = buffer.max_point();
13199            let mut is_first = true;
13200            let mut prev_selection_was_entire_line = false;
13201            for selection in &selections {
13202                let mut start = selection.start;
13203                let mut end = selection.end;
13204                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13205                let mut add_trailing_newline = false;
13206                if is_entire_line {
13207                    start = Point::new(start.row, 0);
13208                    let next_line_start = Point::new(end.row + 1, 0);
13209                    if next_line_start <= max_point {
13210                        end = next_line_start;
13211                    } else {
13212                        // We're on the last line without a trailing newline.
13213                        // Copy to the end of the line and add a newline afterwards.
13214                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13215                        add_trailing_newline = true;
13216                    }
13217                }
13218
13219                let mut trimmed_selections = Vec::new();
13220                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13221                    let row = MultiBufferRow(start.row);
13222                    let first_indent = buffer.indent_size_for_line(row);
13223                    if first_indent.len == 0 || start.column > first_indent.len {
13224                        trimmed_selections.push(start..end);
13225                    } else {
13226                        trimmed_selections.push(
13227                            Point::new(row.0, first_indent.len)
13228                                ..Point::new(row.0, buffer.line_len(row)),
13229                        );
13230                        for row in start.row + 1..=end.row {
13231                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13232                            if row == end.row {
13233                                line_len = end.column;
13234                            }
13235                            if line_len == 0 {
13236                                trimmed_selections
13237                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13238                                continue;
13239                            }
13240                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13241                            if row_indent_size.len >= first_indent.len {
13242                                trimmed_selections.push(
13243                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13244                                );
13245                            } else {
13246                                trimmed_selections.clear();
13247                                trimmed_selections.push(start..end);
13248                                break;
13249                            }
13250                        }
13251                    }
13252                } else {
13253                    trimmed_selections.push(start..end);
13254                }
13255
13256                for trimmed_range in trimmed_selections {
13257                    if is_first {
13258                        is_first = false;
13259                    } else if !prev_selection_was_entire_line {
13260                        text += "\n";
13261                    }
13262                    prev_selection_was_entire_line = is_entire_line;
13263                    let mut len = 0;
13264                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13265                        text.push_str(chunk);
13266                        len += chunk.len();
13267                    }
13268                    if add_trailing_newline {
13269                        text.push('\n');
13270                        len += 1;
13271                    }
13272                    clipboard_selections.push(ClipboardSelection::for_buffer(
13273                        len,
13274                        is_entire_line,
13275                        trimmed_range,
13276                        &buffer,
13277                        self.project.as_ref(),
13278                        cx,
13279                    ));
13280                }
13281            }
13282        }
13283
13284        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13285            text,
13286            clipboard_selections,
13287        ));
13288    }
13289
13290    pub fn do_paste(
13291        &mut self,
13292        text: &String,
13293        clipboard_selections: Option<Vec<ClipboardSelection>>,
13294        handle_entire_lines: bool,
13295        window: &mut Window,
13296        cx: &mut Context<Self>,
13297    ) {
13298        if self.read_only(cx) {
13299            return;
13300        }
13301
13302        let clipboard_text = Cow::Borrowed(text.as_str());
13303
13304        self.transact(window, cx, |this, window, cx| {
13305            let had_active_edit_prediction = this.has_active_edit_prediction();
13306            let display_map = this.display_snapshot(cx);
13307            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13308            let cursor_offset = this
13309                .selections
13310                .last::<MultiBufferOffset>(&display_map)
13311                .head();
13312
13313            if let Some(mut clipboard_selections) = clipboard_selections {
13314                let all_selections_were_entire_line =
13315                    clipboard_selections.iter().all(|s| s.is_entire_line);
13316                let first_selection_indent_column =
13317                    clipboard_selections.first().map(|s| s.first_line_indent);
13318                if clipboard_selections.len() != old_selections.len() {
13319                    clipboard_selections.drain(..);
13320                }
13321                let mut auto_indent_on_paste = true;
13322
13323                this.buffer.update(cx, |buffer, cx| {
13324                    let snapshot = buffer.read(cx);
13325                    auto_indent_on_paste = snapshot
13326                        .language_settings_at(cursor_offset, cx)
13327                        .auto_indent_on_paste;
13328
13329                    let mut start_offset = 0;
13330                    let mut edits = Vec::new();
13331                    let mut original_indent_columns = Vec::new();
13332                    for (ix, selection) in old_selections.iter().enumerate() {
13333                        let to_insert;
13334                        let entire_line;
13335                        let original_indent_column;
13336                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13337                            let end_offset = start_offset + clipboard_selection.len;
13338                            to_insert = &clipboard_text[start_offset..end_offset];
13339                            entire_line = clipboard_selection.is_entire_line;
13340                            start_offset = if entire_line {
13341                                end_offset
13342                            } else {
13343                                end_offset + 1
13344                            };
13345                            original_indent_column = Some(clipboard_selection.first_line_indent);
13346                        } else {
13347                            to_insert = &*clipboard_text;
13348                            entire_line = all_selections_were_entire_line;
13349                            original_indent_column = first_selection_indent_column
13350                        }
13351
13352                        let (range, to_insert) =
13353                            if selection.is_empty() && handle_entire_lines && entire_line {
13354                                // If the corresponding selection was empty when this slice of the
13355                                // clipboard text was written, then the entire line containing the
13356                                // selection was copied. If this selection is also currently empty,
13357                                // then paste the line before the current line of the buffer.
13358                                let column = selection.start.to_point(&snapshot).column as usize;
13359                                let line_start = selection.start - column;
13360                                (line_start..line_start, Cow::Borrowed(to_insert))
13361                            } else {
13362                                let language = snapshot.language_at(selection.head());
13363                                let range = selection.range();
13364                                if let Some(language) = language
13365                                    && language.name() == "Markdown".into()
13366                                {
13367                                    edit_for_markdown_paste(
13368                                        &snapshot,
13369                                        range,
13370                                        to_insert,
13371                                        url::Url::parse(to_insert).ok(),
13372                                    )
13373                                } else {
13374                                    (range, Cow::Borrowed(to_insert))
13375                                }
13376                            };
13377
13378                        edits.push((range, to_insert));
13379                        original_indent_columns.push(original_indent_column);
13380                    }
13381                    drop(snapshot);
13382
13383                    buffer.edit(
13384                        edits,
13385                        if auto_indent_on_paste {
13386                            Some(AutoindentMode::Block {
13387                                original_indent_columns,
13388                            })
13389                        } else {
13390                            None
13391                        },
13392                        cx,
13393                    );
13394                });
13395
13396                let selections = this
13397                    .selections
13398                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13399                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13400            } else {
13401                let url = url::Url::parse(&clipboard_text).ok();
13402
13403                let auto_indent_mode = if !clipboard_text.is_empty() {
13404                    Some(AutoindentMode::Block {
13405                        original_indent_columns: Vec::new(),
13406                    })
13407                } else {
13408                    None
13409                };
13410
13411                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13412                    let snapshot = buffer.snapshot(cx);
13413
13414                    let anchors = old_selections
13415                        .iter()
13416                        .map(|s| {
13417                            let anchor = snapshot.anchor_after(s.head());
13418                            s.map(|_| anchor)
13419                        })
13420                        .collect::<Vec<_>>();
13421
13422                    let mut edits = Vec::new();
13423
13424                    for selection in old_selections.iter() {
13425                        let language = snapshot.language_at(selection.head());
13426                        let range = selection.range();
13427
13428                        let (edit_range, edit_text) = if let Some(language) = language
13429                            && language.name() == "Markdown".into()
13430                        {
13431                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13432                        } else {
13433                            (range, clipboard_text.clone())
13434                        };
13435
13436                        edits.push((edit_range, edit_text));
13437                    }
13438
13439                    drop(snapshot);
13440                    buffer.edit(edits, auto_indent_mode, cx);
13441
13442                    anchors
13443                });
13444
13445                this.change_selections(Default::default(), window, cx, |s| {
13446                    s.select_anchors(selection_anchors);
13447                });
13448            }
13449
13450            //   🤔                 |    ..     | show_in_menu |
13451            // | ..                  |   true        true
13452            // | had_edit_prediction |   false       true
13453
13454            let trigger_in_words =
13455                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13456
13457            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13458        });
13459    }
13460
13461    pub fn diff_clipboard_with_selection(
13462        &mut self,
13463        _: &DiffClipboardWithSelection,
13464        window: &mut Window,
13465        cx: &mut Context<Self>,
13466    ) {
13467        let selections = self
13468            .selections
13469            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13470
13471        if selections.is_empty() {
13472            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13473            return;
13474        };
13475
13476        let clipboard_text = match cx.read_from_clipboard() {
13477            Some(item) => match item.entries().first() {
13478                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13479                _ => None,
13480            },
13481            None => None,
13482        };
13483
13484        let Some(clipboard_text) = clipboard_text else {
13485            log::warn!("Clipboard doesn't contain text.");
13486            return;
13487        };
13488
13489        window.dispatch_action(
13490            Box::new(DiffClipboardWithSelectionData {
13491                clipboard_text,
13492                editor: cx.entity(),
13493            }),
13494            cx,
13495        );
13496    }
13497
13498    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13499        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13500        if let Some(item) = cx.read_from_clipboard() {
13501            let entries = item.entries();
13502
13503            match entries.first() {
13504                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13505                // of all the pasted entries.
13506                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13507                    .do_paste(
13508                        clipboard_string.text(),
13509                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13510                        true,
13511                        window,
13512                        cx,
13513                    ),
13514                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13515            }
13516        }
13517    }
13518
13519    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13520        if self.read_only(cx) {
13521            return;
13522        }
13523
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13525
13526        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13527            if let Some((selections, _)) =
13528                self.selection_history.transaction(transaction_id).cloned()
13529            {
13530                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13531                    s.select_anchors(selections.to_vec());
13532                });
13533            } else {
13534                log::error!(
13535                    "No entry in selection_history found for undo. \
13536                     This may correspond to a bug where undo does not update the selection. \
13537                     If this is occurring, please add details to \
13538                     https://github.com/zed-industries/zed/issues/22692"
13539                );
13540            }
13541            self.request_autoscroll(Autoscroll::fit(), cx);
13542            self.unmark_text(window, cx);
13543            self.refresh_edit_prediction(true, false, window, cx);
13544            cx.emit(EditorEvent::Edited { transaction_id });
13545            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13546        }
13547    }
13548
13549    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13550        if self.read_only(cx) {
13551            return;
13552        }
13553
13554        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13555
13556        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13557            if let Some((_, Some(selections))) =
13558                self.selection_history.transaction(transaction_id).cloned()
13559            {
13560                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13561                    s.select_anchors(selections.to_vec());
13562                });
13563            } else {
13564                log::error!(
13565                    "No entry in selection_history found for redo. \
13566                     This may correspond to a bug where undo does not update the selection. \
13567                     If this is occurring, please add details to \
13568                     https://github.com/zed-industries/zed/issues/22692"
13569                );
13570            }
13571            self.request_autoscroll(Autoscroll::fit(), cx);
13572            self.unmark_text(window, cx);
13573            self.refresh_edit_prediction(true, false, window, cx);
13574            cx.emit(EditorEvent::Edited { transaction_id });
13575        }
13576    }
13577
13578    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13579        self.buffer
13580            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13581    }
13582
13583    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13584        self.buffer
13585            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13586    }
13587
13588    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_with(|map, selection| {
13592                let cursor = if selection.is_empty() {
13593                    movement::left(map, selection.start)
13594                } else {
13595                    selection.start
13596                };
13597                selection.collapse_to(cursor, SelectionGoal::None);
13598            });
13599        })
13600    }
13601
13602    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13604        self.change_selections(Default::default(), window, cx, |s| {
13605            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13606        })
13607    }
13608
13609    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                let cursor = if selection.is_empty() {
13614                    movement::right(map, selection.end)
13615                } else {
13616                    selection.end
13617                };
13618                selection.collapse_to(cursor, SelectionGoal::None)
13619            });
13620        })
13621    }
13622
13623    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13625        self.change_selections(Default::default(), window, cx, |s| {
13626            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13627        });
13628    }
13629
13630    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13631        if self.take_rename(true, window, cx).is_some() {
13632            return;
13633        }
13634
13635        if self.mode.is_single_line() {
13636            cx.propagate();
13637            return;
13638        }
13639
13640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13641
13642        let text_layout_details = &self.text_layout_details(window);
13643        let selection_count = self.selections.count();
13644        let first_selection = self.selections.first_anchor();
13645
13646        self.change_selections(Default::default(), window, cx, |s| {
13647            s.move_with(|map, selection| {
13648                if !selection.is_empty() {
13649                    selection.goal = SelectionGoal::None;
13650                }
13651                let (cursor, goal) = movement::up(
13652                    map,
13653                    selection.start,
13654                    selection.goal,
13655                    false,
13656                    text_layout_details,
13657                );
13658                selection.collapse_to(cursor, goal);
13659            });
13660        });
13661
13662        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13663        {
13664            cx.propagate();
13665        }
13666    }
13667
13668    pub fn move_up_by_lines(
13669        &mut self,
13670        action: &MoveUpByLines,
13671        window: &mut Window,
13672        cx: &mut Context<Self>,
13673    ) {
13674        if self.take_rename(true, window, cx).is_some() {
13675            return;
13676        }
13677
13678        if self.mode.is_single_line() {
13679            cx.propagate();
13680            return;
13681        }
13682
13683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13684
13685        let text_layout_details = &self.text_layout_details(window);
13686
13687        self.change_selections(Default::default(), window, cx, |s| {
13688            s.move_with(|map, selection| {
13689                if !selection.is_empty() {
13690                    selection.goal = SelectionGoal::None;
13691                }
13692                let (cursor, goal) = movement::up_by_rows(
13693                    map,
13694                    selection.start,
13695                    action.lines,
13696                    selection.goal,
13697                    false,
13698                    text_layout_details,
13699                );
13700                selection.collapse_to(cursor, goal);
13701            });
13702        })
13703    }
13704
13705    pub fn move_down_by_lines(
13706        &mut self,
13707        action: &MoveDownByLines,
13708        window: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        if self.take_rename(true, window, cx).is_some() {
13712            return;
13713        }
13714
13715        if self.mode.is_single_line() {
13716            cx.propagate();
13717            return;
13718        }
13719
13720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13721
13722        let text_layout_details = &self.text_layout_details(window);
13723
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                if !selection.is_empty() {
13727                    selection.goal = SelectionGoal::None;
13728                }
13729                let (cursor, goal) = movement::down_by_rows(
13730                    map,
13731                    selection.start,
13732                    action.lines,
13733                    selection.goal,
13734                    false,
13735                    text_layout_details,
13736                );
13737                selection.collapse_to(cursor, goal);
13738            });
13739        })
13740    }
13741
13742    pub fn select_down_by_lines(
13743        &mut self,
13744        action: &SelectDownByLines,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13749        let text_layout_details = &self.text_layout_details(window);
13750        self.change_selections(Default::default(), window, cx, |s| {
13751            s.move_heads_with(|map, head, goal| {
13752                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13753            })
13754        })
13755    }
13756
13757    pub fn select_up_by_lines(
13758        &mut self,
13759        action: &SelectUpByLines,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) {
13763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13764        let text_layout_details = &self.text_layout_details(window);
13765        self.change_selections(Default::default(), window, cx, |s| {
13766            s.move_heads_with(|map, head, goal| {
13767                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13768            })
13769        })
13770    }
13771
13772    pub fn select_page_up(
13773        &mut self,
13774        _: &SelectPageUp,
13775        window: &mut Window,
13776        cx: &mut Context<Self>,
13777    ) {
13778        let Some(row_count) = self.visible_row_count() else {
13779            return;
13780        };
13781
13782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13783
13784        let text_layout_details = &self.text_layout_details(window);
13785
13786        self.change_selections(Default::default(), window, cx, |s| {
13787            s.move_heads_with(|map, head, goal| {
13788                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13789            })
13790        })
13791    }
13792
13793    pub fn move_page_up(
13794        &mut self,
13795        action: &MovePageUp,
13796        window: &mut Window,
13797        cx: &mut Context<Self>,
13798    ) {
13799        if self.take_rename(true, window, cx).is_some() {
13800            return;
13801        }
13802
13803        if self
13804            .context_menu
13805            .borrow_mut()
13806            .as_mut()
13807            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13808            .unwrap_or(false)
13809        {
13810            return;
13811        }
13812
13813        if matches!(self.mode, EditorMode::SingleLine) {
13814            cx.propagate();
13815            return;
13816        }
13817
13818        let Some(row_count) = self.visible_row_count() else {
13819            return;
13820        };
13821
13822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13823
13824        let effects = if action.center_cursor {
13825            SelectionEffects::scroll(Autoscroll::center())
13826        } else {
13827            SelectionEffects::default()
13828        };
13829
13830        let text_layout_details = &self.text_layout_details(window);
13831
13832        self.change_selections(effects, window, cx, |s| {
13833            s.move_with(|map, selection| {
13834                if !selection.is_empty() {
13835                    selection.goal = SelectionGoal::None;
13836                }
13837                let (cursor, goal) = movement::up_by_rows(
13838                    map,
13839                    selection.end,
13840                    row_count,
13841                    selection.goal,
13842                    false,
13843                    text_layout_details,
13844                );
13845                selection.collapse_to(cursor, goal);
13846            });
13847        });
13848    }
13849
13850    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13852        let text_layout_details = &self.text_layout_details(window);
13853        self.change_selections(Default::default(), window, cx, |s| {
13854            s.move_heads_with(|map, head, goal| {
13855                movement::up(map, head, goal, false, text_layout_details)
13856            })
13857        })
13858    }
13859
13860    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13861        self.take_rename(true, window, cx);
13862
13863        if self.mode.is_single_line() {
13864            cx.propagate();
13865            return;
13866        }
13867
13868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13869
13870        let text_layout_details = &self.text_layout_details(window);
13871        let selection_count = self.selections.count();
13872        let first_selection = self.selections.first_anchor();
13873
13874        self.change_selections(Default::default(), window, cx, |s| {
13875            s.move_with(|map, selection| {
13876                if !selection.is_empty() {
13877                    selection.goal = SelectionGoal::None;
13878                }
13879                let (cursor, goal) = movement::down(
13880                    map,
13881                    selection.end,
13882                    selection.goal,
13883                    false,
13884                    text_layout_details,
13885                );
13886                selection.collapse_to(cursor, goal);
13887            });
13888        });
13889
13890        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13891        {
13892            cx.propagate();
13893        }
13894    }
13895
13896    pub fn select_page_down(
13897        &mut self,
13898        _: &SelectPageDown,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) {
13902        let Some(row_count) = self.visible_row_count() else {
13903            return;
13904        };
13905
13906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13907
13908        let text_layout_details = &self.text_layout_details(window);
13909
13910        self.change_selections(Default::default(), window, cx, |s| {
13911            s.move_heads_with(|map, head, goal| {
13912                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13913            })
13914        })
13915    }
13916
13917    pub fn move_page_down(
13918        &mut self,
13919        action: &MovePageDown,
13920        window: &mut Window,
13921        cx: &mut Context<Self>,
13922    ) {
13923        if self.take_rename(true, window, cx).is_some() {
13924            return;
13925        }
13926
13927        if self
13928            .context_menu
13929            .borrow_mut()
13930            .as_mut()
13931            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13932            .unwrap_or(false)
13933        {
13934            return;
13935        }
13936
13937        if matches!(self.mode, EditorMode::SingleLine) {
13938            cx.propagate();
13939            return;
13940        }
13941
13942        let Some(row_count) = self.visible_row_count() else {
13943            return;
13944        };
13945
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947
13948        let effects = if action.center_cursor {
13949            SelectionEffects::scroll(Autoscroll::center())
13950        } else {
13951            SelectionEffects::default()
13952        };
13953
13954        let text_layout_details = &self.text_layout_details(window);
13955        self.change_selections(effects, window, cx, |s| {
13956            s.move_with(|map, selection| {
13957                if !selection.is_empty() {
13958                    selection.goal = SelectionGoal::None;
13959                }
13960                let (cursor, goal) = movement::down_by_rows(
13961                    map,
13962                    selection.end,
13963                    row_count,
13964                    selection.goal,
13965                    false,
13966                    text_layout_details,
13967                );
13968                selection.collapse_to(cursor, goal);
13969            });
13970        });
13971    }
13972
13973    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13975        let text_layout_details = &self.text_layout_details(window);
13976        self.change_selections(Default::default(), window, cx, |s| {
13977            s.move_heads_with(|map, head, goal| {
13978                movement::down(map, head, goal, false, text_layout_details)
13979            })
13980        });
13981    }
13982
13983    pub fn context_menu_first(
13984        &mut self,
13985        _: &ContextMenuFirst,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13990            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13991        }
13992    }
13993
13994    pub fn context_menu_prev(
13995        &mut self,
13996        _: &ContextMenuPrevious,
13997        window: &mut Window,
13998        cx: &mut Context<Self>,
13999    ) {
14000        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14001            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14002        }
14003    }
14004
14005    pub fn context_menu_next(
14006        &mut self,
14007        _: &ContextMenuNext,
14008        window: &mut Window,
14009        cx: &mut Context<Self>,
14010    ) {
14011        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14012            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14013        }
14014    }
14015
14016    pub fn context_menu_last(
14017        &mut self,
14018        _: &ContextMenuLast,
14019        window: &mut Window,
14020        cx: &mut Context<Self>,
14021    ) {
14022        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14023            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14024        }
14025    }
14026
14027    pub fn signature_help_prev(
14028        &mut self,
14029        _: &SignatureHelpPrevious,
14030        _: &mut Window,
14031        cx: &mut Context<Self>,
14032    ) {
14033        if let Some(popover) = self.signature_help_state.popover_mut() {
14034            if popover.current_signature == 0 {
14035                popover.current_signature = popover.signatures.len() - 1;
14036            } else {
14037                popover.current_signature -= 1;
14038            }
14039            cx.notify();
14040        }
14041    }
14042
14043    pub fn signature_help_next(
14044        &mut self,
14045        _: &SignatureHelpNext,
14046        _: &mut Window,
14047        cx: &mut Context<Self>,
14048    ) {
14049        if let Some(popover) = self.signature_help_state.popover_mut() {
14050            if popover.current_signature + 1 == popover.signatures.len() {
14051                popover.current_signature = 0;
14052            } else {
14053                popover.current_signature += 1;
14054            }
14055            cx.notify();
14056        }
14057    }
14058
14059    pub fn move_to_previous_word_start(
14060        &mut self,
14061        _: &MoveToPreviousWordStart,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) {
14065        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14066        self.change_selections(Default::default(), window, cx, |s| {
14067            s.move_cursors_with(|map, head, _| {
14068                (
14069                    movement::previous_word_start(map, head),
14070                    SelectionGoal::None,
14071                )
14072            });
14073        })
14074    }
14075
14076    pub fn move_to_previous_subword_start(
14077        &mut self,
14078        _: &MoveToPreviousSubwordStart,
14079        window: &mut Window,
14080        cx: &mut Context<Self>,
14081    ) {
14082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14083        self.change_selections(Default::default(), window, cx, |s| {
14084            s.move_cursors_with(|map, head, _| {
14085                (
14086                    movement::previous_subword_start(map, head),
14087                    SelectionGoal::None,
14088                )
14089            });
14090        })
14091    }
14092
14093    pub fn select_to_previous_word_start(
14094        &mut self,
14095        _: &SelectToPreviousWordStart,
14096        window: &mut Window,
14097        cx: &mut Context<Self>,
14098    ) {
14099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14100        self.change_selections(Default::default(), window, cx, |s| {
14101            s.move_heads_with(|map, head, _| {
14102                (
14103                    movement::previous_word_start(map, head),
14104                    SelectionGoal::None,
14105                )
14106            });
14107        })
14108    }
14109
14110    pub fn select_to_previous_subword_start(
14111        &mut self,
14112        _: &SelectToPreviousSubwordStart,
14113        window: &mut Window,
14114        cx: &mut Context<Self>,
14115    ) {
14116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14117        self.change_selections(Default::default(), window, cx, |s| {
14118            s.move_heads_with(|map, head, _| {
14119                (
14120                    movement::previous_subword_start(map, head),
14121                    SelectionGoal::None,
14122                )
14123            });
14124        })
14125    }
14126
14127    pub fn delete_to_previous_word_start(
14128        &mut self,
14129        action: &DeleteToPreviousWordStart,
14130        window: &mut Window,
14131        cx: &mut Context<Self>,
14132    ) {
14133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14134        self.transact(window, cx, |this, window, cx| {
14135            this.select_autoclose_pair(window, cx);
14136            this.change_selections(Default::default(), window, cx, |s| {
14137                s.move_with(|map, selection| {
14138                    if selection.is_empty() {
14139                        let mut cursor = if action.ignore_newlines {
14140                            movement::previous_word_start(map, selection.head())
14141                        } else {
14142                            movement::previous_word_start_or_newline(map, selection.head())
14143                        };
14144                        cursor = movement::adjust_greedy_deletion(
14145                            map,
14146                            selection.head(),
14147                            cursor,
14148                            action.ignore_brackets,
14149                        );
14150                        selection.set_head(cursor, SelectionGoal::None);
14151                    }
14152                });
14153            });
14154            this.insert("", window, cx);
14155        });
14156    }
14157
14158    pub fn delete_to_previous_subword_start(
14159        &mut self,
14160        _: &DeleteToPreviousSubwordStart,
14161        window: &mut Window,
14162        cx: &mut Context<Self>,
14163    ) {
14164        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14165        self.transact(window, cx, |this, window, cx| {
14166            this.select_autoclose_pair(window, cx);
14167            this.change_selections(Default::default(), window, cx, |s| {
14168                s.move_with(|map, selection| {
14169                    if selection.is_empty() {
14170                        let mut cursor = movement::previous_subword_start(map, selection.head());
14171                        cursor =
14172                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14173                        selection.set_head(cursor, SelectionGoal::None);
14174                    }
14175                });
14176            });
14177            this.insert("", window, cx);
14178        });
14179    }
14180
14181    pub fn move_to_next_word_end(
14182        &mut self,
14183        _: &MoveToNextWordEnd,
14184        window: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) {
14187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14188        self.change_selections(Default::default(), window, cx, |s| {
14189            s.move_cursors_with(|map, head, _| {
14190                (movement::next_word_end(map, head), SelectionGoal::None)
14191            });
14192        })
14193    }
14194
14195    pub fn move_to_next_subword_end(
14196        &mut self,
14197        _: &MoveToNextSubwordEnd,
14198        window: &mut Window,
14199        cx: &mut Context<Self>,
14200    ) {
14201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14202        self.change_selections(Default::default(), window, cx, |s| {
14203            s.move_cursors_with(|map, head, _| {
14204                (movement::next_subword_end(map, head), SelectionGoal::None)
14205            });
14206        })
14207    }
14208
14209    pub fn select_to_next_word_end(
14210        &mut self,
14211        _: &SelectToNextWordEnd,
14212        window: &mut Window,
14213        cx: &mut Context<Self>,
14214    ) {
14215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14216        self.change_selections(Default::default(), window, cx, |s| {
14217            s.move_heads_with(|map, head, _| {
14218                (movement::next_word_end(map, head), SelectionGoal::None)
14219            });
14220        })
14221    }
14222
14223    pub fn select_to_next_subword_end(
14224        &mut self,
14225        _: &SelectToNextSubwordEnd,
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                (movement::next_subword_end(map, head), SelectionGoal::None)
14233            });
14234        })
14235    }
14236
14237    pub fn delete_to_next_word_end(
14238        &mut self,
14239        action: &DeleteToNextWordEnd,
14240        window: &mut Window,
14241        cx: &mut Context<Self>,
14242    ) {
14243        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14244        self.transact(window, cx, |this, window, cx| {
14245            this.change_selections(Default::default(), window, cx, |s| {
14246                s.move_with(|map, selection| {
14247                    if selection.is_empty() {
14248                        let mut cursor = if action.ignore_newlines {
14249                            movement::next_word_end(map, selection.head())
14250                        } else {
14251                            movement::next_word_end_or_newline(map, selection.head())
14252                        };
14253                        cursor = movement::adjust_greedy_deletion(
14254                            map,
14255                            selection.head(),
14256                            cursor,
14257                            action.ignore_brackets,
14258                        );
14259                        selection.set_head(cursor, SelectionGoal::None);
14260                    }
14261                });
14262            });
14263            this.insert("", window, cx);
14264        });
14265    }
14266
14267    pub fn delete_to_next_subword_end(
14268        &mut self,
14269        _: &DeleteToNextSubwordEnd,
14270        window: &mut Window,
14271        cx: &mut Context<Self>,
14272    ) {
14273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14274        self.transact(window, cx, |this, window, cx| {
14275            this.change_selections(Default::default(), window, cx, |s| {
14276                s.move_with(|map, selection| {
14277                    if selection.is_empty() {
14278                        let mut cursor = movement::next_subword_end(map, selection.head());
14279                        cursor =
14280                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14281                        selection.set_head(cursor, SelectionGoal::None);
14282                    }
14283                });
14284            });
14285            this.insert("", window, cx);
14286        });
14287    }
14288
14289    pub fn move_to_beginning_of_line(
14290        &mut self,
14291        action: &MoveToBeginningOfLine,
14292        window: &mut Window,
14293        cx: &mut Context<Self>,
14294    ) {
14295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14296        self.change_selections(Default::default(), window, cx, |s| {
14297            s.move_cursors_with(|map, head, _| {
14298                (
14299                    movement::indented_line_beginning(
14300                        map,
14301                        head,
14302                        action.stop_at_soft_wraps,
14303                        action.stop_at_indent,
14304                    ),
14305                    SelectionGoal::None,
14306                )
14307            });
14308        })
14309    }
14310
14311    pub fn select_to_beginning_of_line(
14312        &mut self,
14313        action: &SelectToBeginningOfLine,
14314        window: &mut Window,
14315        cx: &mut Context<Self>,
14316    ) {
14317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14318        self.change_selections(Default::default(), window, cx, |s| {
14319            s.move_heads_with(|map, head, _| {
14320                (
14321                    movement::indented_line_beginning(
14322                        map,
14323                        head,
14324                        action.stop_at_soft_wraps,
14325                        action.stop_at_indent,
14326                    ),
14327                    SelectionGoal::None,
14328                )
14329            });
14330        });
14331    }
14332
14333    pub fn delete_to_beginning_of_line(
14334        &mut self,
14335        action: &DeleteToBeginningOfLine,
14336        window: &mut Window,
14337        cx: &mut Context<Self>,
14338    ) {
14339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14340        self.transact(window, cx, |this, window, cx| {
14341            this.change_selections(Default::default(), window, cx, |s| {
14342                s.move_with(|_, selection| {
14343                    selection.reversed = true;
14344                });
14345            });
14346
14347            this.select_to_beginning_of_line(
14348                &SelectToBeginningOfLine {
14349                    stop_at_soft_wraps: false,
14350                    stop_at_indent: action.stop_at_indent,
14351                },
14352                window,
14353                cx,
14354            );
14355            this.backspace(&Backspace, window, cx);
14356        });
14357    }
14358
14359    pub fn move_to_end_of_line(
14360        &mut self,
14361        action: &MoveToEndOfLine,
14362        window: &mut Window,
14363        cx: &mut Context<Self>,
14364    ) {
14365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14366        self.change_selections(Default::default(), window, cx, |s| {
14367            s.move_cursors_with(|map, head, _| {
14368                (
14369                    movement::line_end(map, head, action.stop_at_soft_wraps),
14370                    SelectionGoal::None,
14371                )
14372            });
14373        })
14374    }
14375
14376    pub fn select_to_end_of_line(
14377        &mut self,
14378        action: &SelectToEndOfLine,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14383        self.change_selections(Default::default(), window, cx, |s| {
14384            s.move_heads_with(|map, head, _| {
14385                (
14386                    movement::line_end(map, head, action.stop_at_soft_wraps),
14387                    SelectionGoal::None,
14388                )
14389            });
14390        })
14391    }
14392
14393    pub fn delete_to_end_of_line(
14394        &mut self,
14395        _: &DeleteToEndOfLine,
14396        window: &mut Window,
14397        cx: &mut Context<Self>,
14398    ) {
14399        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14400        self.transact(window, cx, |this, window, cx| {
14401            this.select_to_end_of_line(
14402                &SelectToEndOfLine {
14403                    stop_at_soft_wraps: false,
14404                },
14405                window,
14406                cx,
14407            );
14408            this.delete(&Delete, window, cx);
14409        });
14410    }
14411
14412    pub fn cut_to_end_of_line(
14413        &mut self,
14414        action: &CutToEndOfLine,
14415        window: &mut Window,
14416        cx: &mut Context<Self>,
14417    ) {
14418        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14419        self.transact(window, cx, |this, window, cx| {
14420            this.select_to_end_of_line(
14421                &SelectToEndOfLine {
14422                    stop_at_soft_wraps: false,
14423                },
14424                window,
14425                cx,
14426            );
14427            if !action.stop_at_newlines {
14428                this.change_selections(Default::default(), window, cx, |s| {
14429                    s.move_with(|_, sel| {
14430                        if sel.is_empty() {
14431                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14432                        }
14433                    });
14434                });
14435            }
14436            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14437            let item = this.cut_common(false, window, cx);
14438            cx.write_to_clipboard(item);
14439        });
14440    }
14441
14442    pub fn move_to_start_of_paragraph(
14443        &mut self,
14444        _: &MoveToStartOfParagraph,
14445        window: &mut Window,
14446        cx: &mut Context<Self>,
14447    ) {
14448        if matches!(self.mode, EditorMode::SingleLine) {
14449            cx.propagate();
14450            return;
14451        }
14452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14453        self.change_selections(Default::default(), window, cx, |s| {
14454            s.move_with(|map, selection| {
14455                selection.collapse_to(
14456                    movement::start_of_paragraph(map, selection.head(), 1),
14457                    SelectionGoal::None,
14458                )
14459            });
14460        })
14461    }
14462
14463    pub fn move_to_end_of_paragraph(
14464        &mut self,
14465        _: &MoveToEndOfParagraph,
14466        window: &mut Window,
14467        cx: &mut Context<Self>,
14468    ) {
14469        if matches!(self.mode, EditorMode::SingleLine) {
14470            cx.propagate();
14471            return;
14472        }
14473        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14474        self.change_selections(Default::default(), window, cx, |s| {
14475            s.move_with(|map, selection| {
14476                selection.collapse_to(
14477                    movement::end_of_paragraph(map, selection.head(), 1),
14478                    SelectionGoal::None,
14479                )
14480            });
14481        })
14482    }
14483
14484    pub fn select_to_start_of_paragraph(
14485        &mut self,
14486        _: &SelectToStartOfParagraph,
14487        window: &mut Window,
14488        cx: &mut Context<Self>,
14489    ) {
14490        if matches!(self.mode, EditorMode::SingleLine) {
14491            cx.propagate();
14492            return;
14493        }
14494        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14495        self.change_selections(Default::default(), window, cx, |s| {
14496            s.move_heads_with(|map, head, _| {
14497                (
14498                    movement::start_of_paragraph(map, head, 1),
14499                    SelectionGoal::None,
14500                )
14501            });
14502        })
14503    }
14504
14505    pub fn select_to_end_of_paragraph(
14506        &mut self,
14507        _: &SelectToEndOfParagraph,
14508        window: &mut Window,
14509        cx: &mut Context<Self>,
14510    ) {
14511        if matches!(self.mode, EditorMode::SingleLine) {
14512            cx.propagate();
14513            return;
14514        }
14515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14516        self.change_selections(Default::default(), window, cx, |s| {
14517            s.move_heads_with(|map, head, _| {
14518                (
14519                    movement::end_of_paragraph(map, head, 1),
14520                    SelectionGoal::None,
14521                )
14522            });
14523        })
14524    }
14525
14526    pub fn move_to_start_of_excerpt(
14527        &mut self,
14528        _: &MoveToStartOfExcerpt,
14529        window: &mut Window,
14530        cx: &mut Context<Self>,
14531    ) {
14532        if matches!(self.mode, EditorMode::SingleLine) {
14533            cx.propagate();
14534            return;
14535        }
14536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14537        self.change_selections(Default::default(), window, cx, |s| {
14538            s.move_with(|map, selection| {
14539                selection.collapse_to(
14540                    movement::start_of_excerpt(
14541                        map,
14542                        selection.head(),
14543                        workspace::searchable::Direction::Prev,
14544                    ),
14545                    SelectionGoal::None,
14546                )
14547            });
14548        })
14549    }
14550
14551    pub fn move_to_start_of_next_excerpt(
14552        &mut self,
14553        _: &MoveToStartOfNextExcerpt,
14554        window: &mut Window,
14555        cx: &mut Context<Self>,
14556    ) {
14557        if matches!(self.mode, EditorMode::SingleLine) {
14558            cx.propagate();
14559            return;
14560        }
14561
14562        self.change_selections(Default::default(), window, cx, |s| {
14563            s.move_with(|map, selection| {
14564                selection.collapse_to(
14565                    movement::start_of_excerpt(
14566                        map,
14567                        selection.head(),
14568                        workspace::searchable::Direction::Next,
14569                    ),
14570                    SelectionGoal::None,
14571                )
14572            });
14573        })
14574    }
14575
14576    pub fn move_to_end_of_excerpt(
14577        &mut self,
14578        _: &MoveToEndOfExcerpt,
14579        window: &mut Window,
14580        cx: &mut Context<Self>,
14581    ) {
14582        if matches!(self.mode, EditorMode::SingleLine) {
14583            cx.propagate();
14584            return;
14585        }
14586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14587        self.change_selections(Default::default(), window, cx, |s| {
14588            s.move_with(|map, selection| {
14589                selection.collapse_to(
14590                    movement::end_of_excerpt(
14591                        map,
14592                        selection.head(),
14593                        workspace::searchable::Direction::Next,
14594                    ),
14595                    SelectionGoal::None,
14596                )
14597            });
14598        })
14599    }
14600
14601    pub fn move_to_end_of_previous_excerpt(
14602        &mut self,
14603        _: &MoveToEndOfPreviousExcerpt,
14604        window: &mut Window,
14605        cx: &mut Context<Self>,
14606    ) {
14607        if matches!(self.mode, EditorMode::SingleLine) {
14608            cx.propagate();
14609            return;
14610        }
14611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14612        self.change_selections(Default::default(), window, cx, |s| {
14613            s.move_with(|map, selection| {
14614                selection.collapse_to(
14615                    movement::end_of_excerpt(
14616                        map,
14617                        selection.head(),
14618                        workspace::searchable::Direction::Prev,
14619                    ),
14620                    SelectionGoal::None,
14621                )
14622            });
14623        })
14624    }
14625
14626    pub fn select_to_start_of_excerpt(
14627        &mut self,
14628        _: &SelectToStartOfExcerpt,
14629        window: &mut Window,
14630        cx: &mut Context<Self>,
14631    ) {
14632        if matches!(self.mode, EditorMode::SingleLine) {
14633            cx.propagate();
14634            return;
14635        }
14636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14637        self.change_selections(Default::default(), window, cx, |s| {
14638            s.move_heads_with(|map, head, _| {
14639                (
14640                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14641                    SelectionGoal::None,
14642                )
14643            });
14644        })
14645    }
14646
14647    pub fn select_to_start_of_next_excerpt(
14648        &mut self,
14649        _: &SelectToStartOfNextExcerpt,
14650        window: &mut Window,
14651        cx: &mut Context<Self>,
14652    ) {
14653        if matches!(self.mode, EditorMode::SingleLine) {
14654            cx.propagate();
14655            return;
14656        }
14657        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14658        self.change_selections(Default::default(), window, cx, |s| {
14659            s.move_heads_with(|map, head, _| {
14660                (
14661                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14662                    SelectionGoal::None,
14663                )
14664            });
14665        })
14666    }
14667
14668    pub fn select_to_end_of_excerpt(
14669        &mut self,
14670        _: &SelectToEndOfExcerpt,
14671        window: &mut Window,
14672        cx: &mut Context<Self>,
14673    ) {
14674        if matches!(self.mode, EditorMode::SingleLine) {
14675            cx.propagate();
14676            return;
14677        }
14678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14679        self.change_selections(Default::default(), window, cx, |s| {
14680            s.move_heads_with(|map, head, _| {
14681                (
14682                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14683                    SelectionGoal::None,
14684                )
14685            });
14686        })
14687    }
14688
14689    pub fn select_to_end_of_previous_excerpt(
14690        &mut self,
14691        _: &SelectToEndOfPreviousExcerpt,
14692        window: &mut Window,
14693        cx: &mut Context<Self>,
14694    ) {
14695        if matches!(self.mode, EditorMode::SingleLine) {
14696            cx.propagate();
14697            return;
14698        }
14699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14700        self.change_selections(Default::default(), window, cx, |s| {
14701            s.move_heads_with(|map, head, _| {
14702                (
14703                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14704                    SelectionGoal::None,
14705                )
14706            });
14707        })
14708    }
14709
14710    pub fn move_to_beginning(
14711        &mut self,
14712        _: &MoveToBeginning,
14713        window: &mut Window,
14714        cx: &mut Context<Self>,
14715    ) {
14716        if matches!(self.mode, EditorMode::SingleLine) {
14717            cx.propagate();
14718            return;
14719        }
14720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14721        self.change_selections(Default::default(), window, cx, |s| {
14722            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14723        });
14724    }
14725
14726    pub fn select_to_beginning(
14727        &mut self,
14728        _: &SelectToBeginning,
14729        window: &mut Window,
14730        cx: &mut Context<Self>,
14731    ) {
14732        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14733        selection.set_head(Point::zero(), SelectionGoal::None);
14734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14735        self.change_selections(Default::default(), window, cx, |s| {
14736            s.select(vec![selection]);
14737        });
14738    }
14739
14740    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14741        if matches!(self.mode, EditorMode::SingleLine) {
14742            cx.propagate();
14743            return;
14744        }
14745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14746        let cursor = self.buffer.read(cx).read(cx).len();
14747        self.change_selections(Default::default(), window, cx, |s| {
14748            s.select_ranges(vec![cursor..cursor])
14749        });
14750    }
14751
14752    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14753        self.nav_history = nav_history;
14754    }
14755
14756    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14757        self.nav_history.as_ref()
14758    }
14759
14760    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14761        self.push_to_nav_history(
14762            self.selections.newest_anchor().head(),
14763            None,
14764            false,
14765            true,
14766            cx,
14767        );
14768    }
14769
14770    fn push_to_nav_history(
14771        &mut self,
14772        cursor_anchor: Anchor,
14773        new_position: Option<Point>,
14774        is_deactivate: bool,
14775        always: bool,
14776        cx: &mut Context<Self>,
14777    ) {
14778        if let Some(nav_history) = self.nav_history.as_mut() {
14779            let buffer = self.buffer.read(cx).read(cx);
14780            let cursor_position = cursor_anchor.to_point(&buffer);
14781            let scroll_state = self.scroll_manager.anchor();
14782            let scroll_top_row = scroll_state.top_row(&buffer);
14783            drop(buffer);
14784
14785            if let Some(new_position) = new_position {
14786                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14787                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14788                    return;
14789                }
14790            }
14791
14792            nav_history.push(
14793                Some(NavigationData {
14794                    cursor_anchor,
14795                    cursor_position,
14796                    scroll_anchor: scroll_state,
14797                    scroll_top_row,
14798                }),
14799                cx,
14800            );
14801            cx.emit(EditorEvent::PushedToNavHistory {
14802                anchor: cursor_anchor,
14803                is_deactivate,
14804            })
14805        }
14806    }
14807
14808    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14810        let buffer = self.buffer.read(cx).snapshot(cx);
14811        let mut selection = self
14812            .selections
14813            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14814        selection.set_head(buffer.len(), SelectionGoal::None);
14815        self.change_selections(Default::default(), window, cx, |s| {
14816            s.select(vec![selection]);
14817        });
14818    }
14819
14820    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14822        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14823            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14824        });
14825    }
14826
14827    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14828        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14830        let mut selections = self.selections.all::<Point>(&display_map);
14831        let max_point = display_map.buffer_snapshot().max_point();
14832        for selection in &mut selections {
14833            let rows = selection.spanned_rows(true, &display_map);
14834            selection.start = Point::new(rows.start.0, 0);
14835            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14836            selection.reversed = false;
14837        }
14838        self.change_selections(Default::default(), window, cx, |s| {
14839            s.select(selections);
14840        });
14841    }
14842
14843    pub fn split_selection_into_lines(
14844        &mut self,
14845        action: &SplitSelectionIntoLines,
14846        window: &mut Window,
14847        cx: &mut Context<Self>,
14848    ) {
14849        let selections = self
14850            .selections
14851            .all::<Point>(&self.display_snapshot(cx))
14852            .into_iter()
14853            .map(|selection| selection.start..selection.end)
14854            .collect::<Vec<_>>();
14855        self.unfold_ranges(&selections, true, true, cx);
14856
14857        let mut new_selection_ranges = Vec::new();
14858        {
14859            let buffer = self.buffer.read(cx).read(cx);
14860            for selection in selections {
14861                for row in selection.start.row..selection.end.row {
14862                    let line_start = Point::new(row, 0);
14863                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14864
14865                    if action.keep_selections {
14866                        // Keep the selection range for each line
14867                        let selection_start = if row == selection.start.row {
14868                            selection.start
14869                        } else {
14870                            line_start
14871                        };
14872                        new_selection_ranges.push(selection_start..line_end);
14873                    } else {
14874                        // Collapse to cursor at end of line
14875                        new_selection_ranges.push(line_end..line_end);
14876                    }
14877                }
14878
14879                let is_multiline_selection = selection.start.row != selection.end.row;
14880                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14881                // so this action feels more ergonomic when paired with other selection operations
14882                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14883                if !should_skip_last {
14884                    if action.keep_selections {
14885                        if is_multiline_selection {
14886                            let line_start = Point::new(selection.end.row, 0);
14887                            new_selection_ranges.push(line_start..selection.end);
14888                        } else {
14889                            new_selection_ranges.push(selection.start..selection.end);
14890                        }
14891                    } else {
14892                        new_selection_ranges.push(selection.end..selection.end);
14893                    }
14894                }
14895            }
14896        }
14897        self.change_selections(Default::default(), window, cx, |s| {
14898            s.select_ranges(new_selection_ranges);
14899        });
14900    }
14901
14902    pub fn add_selection_above(
14903        &mut self,
14904        action: &AddSelectionAbove,
14905        window: &mut Window,
14906        cx: &mut Context<Self>,
14907    ) {
14908        self.add_selection(true, action.skip_soft_wrap, window, cx);
14909    }
14910
14911    pub fn add_selection_below(
14912        &mut self,
14913        action: &AddSelectionBelow,
14914        window: &mut Window,
14915        cx: &mut Context<Self>,
14916    ) {
14917        self.add_selection(false, action.skip_soft_wrap, window, cx);
14918    }
14919
14920    fn add_selection(
14921        &mut self,
14922        above: bool,
14923        skip_soft_wrap: bool,
14924        window: &mut Window,
14925        cx: &mut Context<Self>,
14926    ) {
14927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14928
14929        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14930        let all_selections = self.selections.all::<Point>(&display_map);
14931        let text_layout_details = self.text_layout_details(window);
14932
14933        let (mut columnar_selections, new_selections_to_columnarize) = {
14934            if let Some(state) = self.add_selections_state.as_ref() {
14935                let columnar_selection_ids: HashSet<_> = state
14936                    .groups
14937                    .iter()
14938                    .flat_map(|group| group.stack.iter())
14939                    .copied()
14940                    .collect();
14941
14942                all_selections
14943                    .into_iter()
14944                    .partition(|s| columnar_selection_ids.contains(&s.id))
14945            } else {
14946                (Vec::new(), all_selections)
14947            }
14948        };
14949
14950        let mut state = self
14951            .add_selections_state
14952            .take()
14953            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14954
14955        for selection in new_selections_to_columnarize {
14956            let range = selection.display_range(&display_map).sorted();
14957            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14958            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14959            let positions = start_x.min(end_x)..start_x.max(end_x);
14960            let mut stack = Vec::new();
14961            for row in range.start.row().0..=range.end.row().0 {
14962                if let Some(selection) = self.selections.build_columnar_selection(
14963                    &display_map,
14964                    DisplayRow(row),
14965                    &positions,
14966                    selection.reversed,
14967                    &text_layout_details,
14968                ) {
14969                    stack.push(selection.id);
14970                    columnar_selections.push(selection);
14971                }
14972            }
14973            if !stack.is_empty() {
14974                if above {
14975                    stack.reverse();
14976                }
14977                state.groups.push(AddSelectionsGroup { above, stack });
14978            }
14979        }
14980
14981        let mut final_selections = Vec::new();
14982        let end_row = if above {
14983            DisplayRow(0)
14984        } else {
14985            display_map.max_point().row()
14986        };
14987
14988        let mut last_added_item_per_group = HashMap::default();
14989        for group in state.groups.iter_mut() {
14990            if let Some(last_id) = group.stack.last() {
14991                last_added_item_per_group.insert(*last_id, group);
14992            }
14993        }
14994
14995        for selection in columnar_selections {
14996            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14997                if above == group.above {
14998                    let range = selection.display_range(&display_map).sorted();
14999                    debug_assert_eq!(range.start.row(), range.end.row());
15000                    let mut row = range.start.row();
15001                    let positions =
15002                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15003                            Pixels::from(start)..Pixels::from(end)
15004                        } else {
15005                            let start_x =
15006                                display_map.x_for_display_point(range.start, &text_layout_details);
15007                            let end_x =
15008                                display_map.x_for_display_point(range.end, &text_layout_details);
15009                            start_x.min(end_x)..start_x.max(end_x)
15010                        };
15011
15012                    let mut maybe_new_selection = None;
15013                    let direction = if above { -1 } else { 1 };
15014
15015                    while row != end_row {
15016                        if skip_soft_wrap {
15017                            row = display_map
15018                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
15019                                .row();
15020                        } else if above {
15021                            row.0 -= 1;
15022                        } else {
15023                            row.0 += 1;
15024                        }
15025
15026                        if let Some(new_selection) = self.selections.build_columnar_selection(
15027                            &display_map,
15028                            row,
15029                            &positions,
15030                            selection.reversed,
15031                            &text_layout_details,
15032                        ) {
15033                            maybe_new_selection = Some(new_selection);
15034                            break;
15035                        }
15036                    }
15037
15038                    if let Some(new_selection) = maybe_new_selection {
15039                        group.stack.push(new_selection.id);
15040                        if above {
15041                            final_selections.push(new_selection);
15042                            final_selections.push(selection);
15043                        } else {
15044                            final_selections.push(selection);
15045                            final_selections.push(new_selection);
15046                        }
15047                    } else {
15048                        final_selections.push(selection);
15049                    }
15050                } else {
15051                    group.stack.pop();
15052                }
15053            } else {
15054                final_selections.push(selection);
15055            }
15056        }
15057
15058        self.change_selections(Default::default(), window, cx, |s| {
15059            s.select(final_selections);
15060        });
15061
15062        let final_selection_ids: HashSet<_> = self
15063            .selections
15064            .all::<Point>(&display_map)
15065            .iter()
15066            .map(|s| s.id)
15067            .collect();
15068        state.groups.retain_mut(|group| {
15069            // selections might get merged above so we remove invalid items from stacks
15070            group.stack.retain(|id| final_selection_ids.contains(id));
15071
15072            // single selection in stack can be treated as initial state
15073            group.stack.len() > 1
15074        });
15075
15076        if !state.groups.is_empty() {
15077            self.add_selections_state = Some(state);
15078        }
15079    }
15080
15081    pub fn insert_snippet_at_selections(
15082        &mut self,
15083        action: &InsertSnippet,
15084        window: &mut Window,
15085        cx: &mut Context<Self>,
15086    ) {
15087        self.try_insert_snippet_at_selections(action, window, cx)
15088            .log_err();
15089    }
15090
15091    fn try_insert_snippet_at_selections(
15092        &mut self,
15093        action: &InsertSnippet,
15094        window: &mut Window,
15095        cx: &mut Context<Self>,
15096    ) -> Result<()> {
15097        let insertion_ranges = self
15098            .selections
15099            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15100            .into_iter()
15101            .map(|selection| selection.range())
15102            .collect_vec();
15103
15104        let snippet = if let Some(snippet_body) = &action.snippet {
15105            if action.language.is_none() && action.name.is_none() {
15106                Snippet::parse(snippet_body)?
15107            } else {
15108                bail!("`snippet` is mutually exclusive with `language` and `name`")
15109            }
15110        } else if let Some(name) = &action.name {
15111            let project = self.project().context("no project")?;
15112            let snippet_store = project.read(cx).snippets().read(cx);
15113            let snippet = snippet_store
15114                .snippets_for(action.language.clone(), cx)
15115                .into_iter()
15116                .find(|snippet| snippet.name == *name)
15117                .context("snippet not found")?;
15118            Snippet::parse(&snippet.body)?
15119        } else {
15120            // todo(andrew): open modal to select snippet
15121            bail!("`name` or `snippet` is required")
15122        };
15123
15124        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15125    }
15126
15127    fn select_match_ranges(
15128        &mut self,
15129        range: Range<MultiBufferOffset>,
15130        reversed: bool,
15131        replace_newest: bool,
15132        auto_scroll: Option<Autoscroll>,
15133        window: &mut Window,
15134        cx: &mut Context<Editor>,
15135    ) {
15136        self.unfold_ranges(
15137            std::slice::from_ref(&range),
15138            false,
15139            auto_scroll.is_some(),
15140            cx,
15141        );
15142        let effects = if let Some(scroll) = auto_scroll {
15143            SelectionEffects::scroll(scroll)
15144        } else {
15145            SelectionEffects::no_scroll()
15146        };
15147        self.change_selections(effects, window, cx, |s| {
15148            if replace_newest {
15149                s.delete(s.newest_anchor().id);
15150            }
15151            if reversed {
15152                s.insert_range(range.end..range.start);
15153            } else {
15154                s.insert_range(range);
15155            }
15156        });
15157    }
15158
15159    pub fn select_next_match_internal(
15160        &mut self,
15161        display_map: &DisplaySnapshot,
15162        replace_newest: bool,
15163        autoscroll: Option<Autoscroll>,
15164        window: &mut Window,
15165        cx: &mut Context<Self>,
15166    ) -> Result<()> {
15167        let buffer = display_map.buffer_snapshot();
15168        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15169        if let Some(mut select_next_state) = self.select_next_state.take() {
15170            let query = &select_next_state.query;
15171            if !select_next_state.done {
15172                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15173                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15174                let mut next_selected_range = None;
15175
15176                let bytes_after_last_selection =
15177                    buffer.bytes_in_range(last_selection.end..buffer.len());
15178                let bytes_before_first_selection =
15179                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15180                let query_matches = query
15181                    .stream_find_iter(bytes_after_last_selection)
15182                    .map(|result| (last_selection.end, result))
15183                    .chain(
15184                        query
15185                            .stream_find_iter(bytes_before_first_selection)
15186                            .map(|result| (MultiBufferOffset(0), result)),
15187                    );
15188
15189                for (start_offset, query_match) in query_matches {
15190                    let query_match = query_match.unwrap(); // can only fail due to I/O
15191                    let offset_range =
15192                        start_offset + query_match.start()..start_offset + query_match.end();
15193
15194                    if !select_next_state.wordwise
15195                        || (!buffer.is_inside_word(offset_range.start, None)
15196                            && !buffer.is_inside_word(offset_range.end, None))
15197                    {
15198                        let idx = selections
15199                            .partition_point(|selection| selection.end <= offset_range.start);
15200                        let overlaps = selections
15201                            .get(idx)
15202                            .map_or(false, |selection| selection.start < offset_range.end);
15203
15204                        if !overlaps {
15205                            next_selected_range = Some(offset_range);
15206                            break;
15207                        }
15208                    }
15209                }
15210
15211                if let Some(next_selected_range) = next_selected_range {
15212                    self.select_match_ranges(
15213                        next_selected_range,
15214                        last_selection.reversed,
15215                        replace_newest,
15216                        autoscroll,
15217                        window,
15218                        cx,
15219                    );
15220                } else {
15221                    select_next_state.done = true;
15222                }
15223            }
15224
15225            self.select_next_state = Some(select_next_state);
15226        } else {
15227            let mut only_carets = true;
15228            let mut same_text_selected = true;
15229            let mut selected_text = None;
15230
15231            let mut selections_iter = selections.iter().peekable();
15232            while let Some(selection) = selections_iter.next() {
15233                if selection.start != selection.end {
15234                    only_carets = false;
15235                }
15236
15237                if same_text_selected {
15238                    if selected_text.is_none() {
15239                        selected_text =
15240                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15241                    }
15242
15243                    if let Some(next_selection) = selections_iter.peek() {
15244                        if next_selection.len() == selection.len() {
15245                            let next_selected_text = buffer
15246                                .text_for_range(next_selection.range())
15247                                .collect::<String>();
15248                            if Some(next_selected_text) != selected_text {
15249                                same_text_selected = false;
15250                                selected_text = None;
15251                            }
15252                        } else {
15253                            same_text_selected = false;
15254                            selected_text = None;
15255                        }
15256                    }
15257                }
15258            }
15259
15260            if only_carets {
15261                for selection in &mut selections {
15262                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15263                    selection.start = word_range.start;
15264                    selection.end = word_range.end;
15265                    selection.goal = SelectionGoal::None;
15266                    selection.reversed = false;
15267                    self.select_match_ranges(
15268                        selection.start..selection.end,
15269                        selection.reversed,
15270                        replace_newest,
15271                        autoscroll,
15272                        window,
15273                        cx,
15274                    );
15275                }
15276
15277                if selections.len() == 1 {
15278                    let selection = selections
15279                        .last()
15280                        .expect("ensured that there's only one selection");
15281                    let query = buffer
15282                        .text_for_range(selection.start..selection.end)
15283                        .collect::<String>();
15284                    let is_empty = query.is_empty();
15285                    let select_state = SelectNextState {
15286                        query: self.build_query(&[query], cx)?,
15287                        wordwise: true,
15288                        done: is_empty,
15289                    };
15290                    self.select_next_state = Some(select_state);
15291                } else {
15292                    self.select_next_state = None;
15293                }
15294            } else if let Some(selected_text) = selected_text {
15295                self.select_next_state = Some(SelectNextState {
15296                    query: self.build_query(&[selected_text], cx)?,
15297                    wordwise: false,
15298                    done: false,
15299                });
15300                self.select_next_match_internal(
15301                    display_map,
15302                    replace_newest,
15303                    autoscroll,
15304                    window,
15305                    cx,
15306                )?;
15307            }
15308        }
15309        Ok(())
15310    }
15311
15312    pub fn select_all_matches(
15313        &mut self,
15314        _action: &SelectAllMatches,
15315        window: &mut Window,
15316        cx: &mut Context<Self>,
15317    ) -> Result<()> {
15318        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15319
15320        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15321
15322        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15323        let Some(select_next_state) = self.select_next_state.as_mut() else {
15324            return Ok(());
15325        };
15326        if select_next_state.done {
15327            return Ok(());
15328        }
15329
15330        let mut new_selections = Vec::new();
15331
15332        let reversed = self
15333            .selections
15334            .oldest::<MultiBufferOffset>(&display_map)
15335            .reversed;
15336        let buffer = display_map.buffer_snapshot();
15337        let query_matches = select_next_state
15338            .query
15339            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15340
15341        for query_match in query_matches.into_iter() {
15342            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15343            let offset_range = if reversed {
15344                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15345            } else {
15346                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15347            };
15348
15349            if !select_next_state.wordwise
15350                || (!buffer.is_inside_word(offset_range.start, None)
15351                    && !buffer.is_inside_word(offset_range.end, None))
15352            {
15353                new_selections.push(offset_range.start..offset_range.end);
15354            }
15355        }
15356
15357        select_next_state.done = true;
15358
15359        if new_selections.is_empty() {
15360            log::error!("bug: new_selections is empty in select_all_matches");
15361            return Ok(());
15362        }
15363
15364        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15365        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15366            selections.select_ranges(new_selections)
15367        });
15368
15369        Ok(())
15370    }
15371
15372    pub fn select_next(
15373        &mut self,
15374        action: &SelectNext,
15375        window: &mut Window,
15376        cx: &mut Context<Self>,
15377    ) -> Result<()> {
15378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15379        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15380        self.select_next_match_internal(
15381            &display_map,
15382            action.replace_newest,
15383            Some(Autoscroll::newest()),
15384            window,
15385            cx,
15386        )?;
15387        Ok(())
15388    }
15389
15390    pub fn select_previous(
15391        &mut self,
15392        action: &SelectPrevious,
15393        window: &mut Window,
15394        cx: &mut Context<Self>,
15395    ) -> Result<()> {
15396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15397        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15398        let buffer = display_map.buffer_snapshot();
15399        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15400        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15401            let query = &select_prev_state.query;
15402            if !select_prev_state.done {
15403                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15404                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15405                let mut next_selected_range = None;
15406                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15407                let bytes_before_last_selection =
15408                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15409                let bytes_after_first_selection =
15410                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15411                let query_matches = query
15412                    .stream_find_iter(bytes_before_last_selection)
15413                    .map(|result| (last_selection.start, result))
15414                    .chain(
15415                        query
15416                            .stream_find_iter(bytes_after_first_selection)
15417                            .map(|result| (buffer.len(), result)),
15418                    );
15419                for (end_offset, query_match) in query_matches {
15420                    let query_match = query_match.unwrap(); // can only fail due to I/O
15421                    let offset_range =
15422                        end_offset - query_match.end()..end_offset - query_match.start();
15423
15424                    if !select_prev_state.wordwise
15425                        || (!buffer.is_inside_word(offset_range.start, None)
15426                            && !buffer.is_inside_word(offset_range.end, None))
15427                    {
15428                        next_selected_range = Some(offset_range);
15429                        break;
15430                    }
15431                }
15432
15433                if let Some(next_selected_range) = next_selected_range {
15434                    self.select_match_ranges(
15435                        next_selected_range,
15436                        last_selection.reversed,
15437                        action.replace_newest,
15438                        Some(Autoscroll::newest()),
15439                        window,
15440                        cx,
15441                    );
15442                } else {
15443                    select_prev_state.done = true;
15444                }
15445            }
15446
15447            self.select_prev_state = Some(select_prev_state);
15448        } else {
15449            let mut only_carets = true;
15450            let mut same_text_selected = true;
15451            let mut selected_text = None;
15452
15453            let mut selections_iter = selections.iter().peekable();
15454            while let Some(selection) = selections_iter.next() {
15455                if selection.start != selection.end {
15456                    only_carets = false;
15457                }
15458
15459                if same_text_selected {
15460                    if selected_text.is_none() {
15461                        selected_text =
15462                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15463                    }
15464
15465                    if let Some(next_selection) = selections_iter.peek() {
15466                        if next_selection.len() == selection.len() {
15467                            let next_selected_text = buffer
15468                                .text_for_range(next_selection.range())
15469                                .collect::<String>();
15470                            if Some(next_selected_text) != selected_text {
15471                                same_text_selected = false;
15472                                selected_text = None;
15473                            }
15474                        } else {
15475                            same_text_selected = false;
15476                            selected_text = None;
15477                        }
15478                    }
15479                }
15480            }
15481
15482            if only_carets {
15483                for selection in &mut selections {
15484                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15485                    selection.start = word_range.start;
15486                    selection.end = word_range.end;
15487                    selection.goal = SelectionGoal::None;
15488                    selection.reversed = false;
15489                    self.select_match_ranges(
15490                        selection.start..selection.end,
15491                        selection.reversed,
15492                        action.replace_newest,
15493                        Some(Autoscroll::newest()),
15494                        window,
15495                        cx,
15496                    );
15497                }
15498                if selections.len() == 1 {
15499                    let selection = selections
15500                        .last()
15501                        .expect("ensured that there's only one selection");
15502                    let query = buffer
15503                        .text_for_range(selection.start..selection.end)
15504                        .collect::<String>();
15505                    let is_empty = query.is_empty();
15506                    let select_state = SelectNextState {
15507                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15508                        wordwise: true,
15509                        done: is_empty,
15510                    };
15511                    self.select_prev_state = Some(select_state);
15512                } else {
15513                    self.select_prev_state = None;
15514                }
15515            } else if let Some(selected_text) = selected_text {
15516                self.select_prev_state = Some(SelectNextState {
15517                    query: self
15518                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15519                    wordwise: false,
15520                    done: false,
15521                });
15522                self.select_previous(action, window, cx)?;
15523            }
15524        }
15525        Ok(())
15526    }
15527
15528    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15529    /// setting the case sensitivity based on the global
15530    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15531    /// editor's settings.
15532    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15533    where
15534        I: IntoIterator<Item = P>,
15535        P: AsRef<[u8]>,
15536    {
15537        let case_sensitive = self
15538            .select_next_is_case_sensitive
15539            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15540
15541        let mut builder = AhoCorasickBuilder::new();
15542        builder.ascii_case_insensitive(!case_sensitive);
15543        builder.build(patterns)
15544    }
15545
15546    pub fn find_next_match(
15547        &mut self,
15548        _: &FindNextMatch,
15549        window: &mut Window,
15550        cx: &mut Context<Self>,
15551    ) -> Result<()> {
15552        let selections = self.selections.disjoint_anchors_arc();
15553        match selections.first() {
15554            Some(first) if selections.len() >= 2 => {
15555                self.change_selections(Default::default(), window, cx, |s| {
15556                    s.select_ranges([first.range()]);
15557                });
15558            }
15559            _ => self.select_next(
15560                &SelectNext {
15561                    replace_newest: true,
15562                },
15563                window,
15564                cx,
15565            )?,
15566        }
15567        Ok(())
15568    }
15569
15570    pub fn find_previous_match(
15571        &mut self,
15572        _: &FindPreviousMatch,
15573        window: &mut Window,
15574        cx: &mut Context<Self>,
15575    ) -> Result<()> {
15576        let selections = self.selections.disjoint_anchors_arc();
15577        match selections.last() {
15578            Some(last) if selections.len() >= 2 => {
15579                self.change_selections(Default::default(), window, cx, |s| {
15580                    s.select_ranges([last.range()]);
15581                });
15582            }
15583            _ => self.select_previous(
15584                &SelectPrevious {
15585                    replace_newest: true,
15586                },
15587                window,
15588                cx,
15589            )?,
15590        }
15591        Ok(())
15592    }
15593
15594    pub fn toggle_comments(
15595        &mut self,
15596        action: &ToggleComments,
15597        window: &mut Window,
15598        cx: &mut Context<Self>,
15599    ) {
15600        if self.read_only(cx) {
15601            return;
15602        }
15603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15604        let text_layout_details = &self.text_layout_details(window);
15605        self.transact(window, cx, |this, window, cx| {
15606            let mut selections = this
15607                .selections
15608                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15609            let mut edits = Vec::new();
15610            let mut selection_edit_ranges = Vec::new();
15611            let mut last_toggled_row = None;
15612            let snapshot = this.buffer.read(cx).read(cx);
15613            let empty_str: Arc<str> = Arc::default();
15614            let mut suffixes_inserted = Vec::new();
15615            let ignore_indent = action.ignore_indent;
15616
15617            fn comment_prefix_range(
15618                snapshot: &MultiBufferSnapshot,
15619                row: MultiBufferRow,
15620                comment_prefix: &str,
15621                comment_prefix_whitespace: &str,
15622                ignore_indent: bool,
15623            ) -> Range<Point> {
15624                let indent_size = if ignore_indent {
15625                    0
15626                } else {
15627                    snapshot.indent_size_for_line(row).len
15628                };
15629
15630                let start = Point::new(row.0, indent_size);
15631
15632                let mut line_bytes = snapshot
15633                    .bytes_in_range(start..snapshot.max_point())
15634                    .flatten()
15635                    .copied();
15636
15637                // If this line currently begins with the line comment prefix, then record
15638                // the range containing the prefix.
15639                if line_bytes
15640                    .by_ref()
15641                    .take(comment_prefix.len())
15642                    .eq(comment_prefix.bytes())
15643                {
15644                    // Include any whitespace that matches the comment prefix.
15645                    let matching_whitespace_len = line_bytes
15646                        .zip(comment_prefix_whitespace.bytes())
15647                        .take_while(|(a, b)| a == b)
15648                        .count() as u32;
15649                    let end = Point::new(
15650                        start.row,
15651                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15652                    );
15653                    start..end
15654                } else {
15655                    start..start
15656                }
15657            }
15658
15659            fn comment_suffix_range(
15660                snapshot: &MultiBufferSnapshot,
15661                row: MultiBufferRow,
15662                comment_suffix: &str,
15663                comment_suffix_has_leading_space: bool,
15664            ) -> Range<Point> {
15665                let end = Point::new(row.0, snapshot.line_len(row));
15666                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15667
15668                let mut line_end_bytes = snapshot
15669                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15670                    .flatten()
15671                    .copied();
15672
15673                let leading_space_len = if suffix_start_column > 0
15674                    && line_end_bytes.next() == Some(b' ')
15675                    && comment_suffix_has_leading_space
15676                {
15677                    1
15678                } else {
15679                    0
15680                };
15681
15682                // If this line currently begins with the line comment prefix, then record
15683                // the range containing the prefix.
15684                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15685                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15686                    start..end
15687                } else {
15688                    end..end
15689                }
15690            }
15691
15692            // TODO: Handle selections that cross excerpts
15693            for selection in &mut selections {
15694                let start_column = snapshot
15695                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15696                    .len;
15697                let language = if let Some(language) =
15698                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15699                {
15700                    language
15701                } else {
15702                    continue;
15703                };
15704
15705                selection_edit_ranges.clear();
15706
15707                // If multiple selections contain a given row, avoid processing that
15708                // row more than once.
15709                let mut start_row = MultiBufferRow(selection.start.row);
15710                if last_toggled_row == Some(start_row) {
15711                    start_row = start_row.next_row();
15712                }
15713                let end_row =
15714                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15715                        MultiBufferRow(selection.end.row - 1)
15716                    } else {
15717                        MultiBufferRow(selection.end.row)
15718                    };
15719                last_toggled_row = Some(end_row);
15720
15721                if start_row > end_row {
15722                    continue;
15723                }
15724
15725                // If the language has line comments, toggle those.
15726                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15727
15728                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15729                if ignore_indent {
15730                    full_comment_prefixes = full_comment_prefixes
15731                        .into_iter()
15732                        .map(|s| Arc::from(s.trim_end()))
15733                        .collect();
15734                }
15735
15736                if !full_comment_prefixes.is_empty() {
15737                    let first_prefix = full_comment_prefixes
15738                        .first()
15739                        .expect("prefixes is non-empty");
15740                    let prefix_trimmed_lengths = full_comment_prefixes
15741                        .iter()
15742                        .map(|p| p.trim_end_matches(' ').len())
15743                        .collect::<SmallVec<[usize; 4]>>();
15744
15745                    let mut all_selection_lines_are_comments = true;
15746
15747                    for row in start_row.0..=end_row.0 {
15748                        let row = MultiBufferRow(row);
15749                        if start_row < end_row && snapshot.is_line_blank(row) {
15750                            continue;
15751                        }
15752
15753                        let prefix_range = full_comment_prefixes
15754                            .iter()
15755                            .zip(prefix_trimmed_lengths.iter().copied())
15756                            .map(|(prefix, trimmed_prefix_len)| {
15757                                comment_prefix_range(
15758                                    snapshot.deref(),
15759                                    row,
15760                                    &prefix[..trimmed_prefix_len],
15761                                    &prefix[trimmed_prefix_len..],
15762                                    ignore_indent,
15763                                )
15764                            })
15765                            .max_by_key(|range| range.end.column - range.start.column)
15766                            .expect("prefixes is non-empty");
15767
15768                        if prefix_range.is_empty() {
15769                            all_selection_lines_are_comments = false;
15770                        }
15771
15772                        selection_edit_ranges.push(prefix_range);
15773                    }
15774
15775                    if all_selection_lines_are_comments {
15776                        edits.extend(
15777                            selection_edit_ranges
15778                                .iter()
15779                                .cloned()
15780                                .map(|range| (range, empty_str.clone())),
15781                        );
15782                    } else {
15783                        let min_column = selection_edit_ranges
15784                            .iter()
15785                            .map(|range| range.start.column)
15786                            .min()
15787                            .unwrap_or(0);
15788                        edits.extend(selection_edit_ranges.iter().map(|range| {
15789                            let position = Point::new(range.start.row, min_column);
15790                            (position..position, first_prefix.clone())
15791                        }));
15792                    }
15793                } else if let Some(BlockCommentConfig {
15794                    start: full_comment_prefix,
15795                    end: comment_suffix,
15796                    ..
15797                }) = language.block_comment()
15798                {
15799                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15800                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15801                    let prefix_range = comment_prefix_range(
15802                        snapshot.deref(),
15803                        start_row,
15804                        comment_prefix,
15805                        comment_prefix_whitespace,
15806                        ignore_indent,
15807                    );
15808                    let suffix_range = comment_suffix_range(
15809                        snapshot.deref(),
15810                        end_row,
15811                        comment_suffix.trim_start_matches(' '),
15812                        comment_suffix.starts_with(' '),
15813                    );
15814
15815                    if prefix_range.is_empty() || suffix_range.is_empty() {
15816                        edits.push((
15817                            prefix_range.start..prefix_range.start,
15818                            full_comment_prefix.clone(),
15819                        ));
15820                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15821                        suffixes_inserted.push((end_row, comment_suffix.len()));
15822                    } else {
15823                        edits.push((prefix_range, empty_str.clone()));
15824                        edits.push((suffix_range, empty_str.clone()));
15825                    }
15826                } else {
15827                    continue;
15828                }
15829            }
15830
15831            drop(snapshot);
15832            this.buffer.update(cx, |buffer, cx| {
15833                buffer.edit(edits, None, cx);
15834            });
15835
15836            // Adjust selections so that they end before any comment suffixes that
15837            // were inserted.
15838            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15839            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15840            let snapshot = this.buffer.read(cx).read(cx);
15841            for selection in &mut selections {
15842                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15843                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15844                        Ordering::Less => {
15845                            suffixes_inserted.next();
15846                            continue;
15847                        }
15848                        Ordering::Greater => break,
15849                        Ordering::Equal => {
15850                            if selection.end.column == snapshot.line_len(row) {
15851                                if selection.is_empty() {
15852                                    selection.start.column -= suffix_len as u32;
15853                                }
15854                                selection.end.column -= suffix_len as u32;
15855                            }
15856                            break;
15857                        }
15858                    }
15859                }
15860            }
15861
15862            drop(snapshot);
15863            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15864
15865            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15866            let selections_on_single_row = selections.windows(2).all(|selections| {
15867                selections[0].start.row == selections[1].start.row
15868                    && selections[0].end.row == selections[1].end.row
15869                    && selections[0].start.row == selections[0].end.row
15870            });
15871            let selections_selecting = selections
15872                .iter()
15873                .any(|selection| selection.start != selection.end);
15874            let advance_downwards = action.advance_downwards
15875                && selections_on_single_row
15876                && !selections_selecting
15877                && !matches!(this.mode, EditorMode::SingleLine);
15878
15879            if advance_downwards {
15880                let snapshot = this.buffer.read(cx).snapshot(cx);
15881
15882                this.change_selections(Default::default(), window, cx, |s| {
15883                    s.move_cursors_with(|display_snapshot, display_point, _| {
15884                        let mut point = display_point.to_point(display_snapshot);
15885                        point.row += 1;
15886                        point = snapshot.clip_point(point, Bias::Left);
15887                        let display_point = point.to_display_point(display_snapshot);
15888                        let goal = SelectionGoal::HorizontalPosition(
15889                            display_snapshot
15890                                .x_for_display_point(display_point, text_layout_details)
15891                                .into(),
15892                        );
15893                        (display_point, goal)
15894                    })
15895                });
15896            }
15897        });
15898    }
15899
15900    pub fn select_enclosing_symbol(
15901        &mut self,
15902        _: &SelectEnclosingSymbol,
15903        window: &mut Window,
15904        cx: &mut Context<Self>,
15905    ) {
15906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15907
15908        let buffer = self.buffer.read(cx).snapshot(cx);
15909        let old_selections = self
15910            .selections
15911            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15912            .into_boxed_slice();
15913
15914        fn update_selection(
15915            selection: &Selection<MultiBufferOffset>,
15916            buffer_snap: &MultiBufferSnapshot,
15917        ) -> Option<Selection<MultiBufferOffset>> {
15918            let cursor = selection.head();
15919            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15920            for symbol in symbols.iter().rev() {
15921                let start = symbol.range.start.to_offset(buffer_snap);
15922                let end = symbol.range.end.to_offset(buffer_snap);
15923                let new_range = start..end;
15924                if start < selection.start || end > selection.end {
15925                    return Some(Selection {
15926                        id: selection.id,
15927                        start: new_range.start,
15928                        end: new_range.end,
15929                        goal: SelectionGoal::None,
15930                        reversed: selection.reversed,
15931                    });
15932                }
15933            }
15934            None
15935        }
15936
15937        let mut selected_larger_symbol = false;
15938        let new_selections = old_selections
15939            .iter()
15940            .map(|selection| match update_selection(selection, &buffer) {
15941                Some(new_selection) => {
15942                    if new_selection.range() != selection.range() {
15943                        selected_larger_symbol = true;
15944                    }
15945                    new_selection
15946                }
15947                None => selection.clone(),
15948            })
15949            .collect::<Vec<_>>();
15950
15951        if selected_larger_symbol {
15952            self.change_selections(Default::default(), window, cx, |s| {
15953                s.select(new_selections);
15954            });
15955        }
15956    }
15957
15958    pub fn select_larger_syntax_node(
15959        &mut self,
15960        _: &SelectLargerSyntaxNode,
15961        window: &mut Window,
15962        cx: &mut Context<Self>,
15963    ) {
15964        let Some(visible_row_count) = self.visible_row_count() else {
15965            return;
15966        };
15967        let old_selections: Box<[_]> = self
15968            .selections
15969            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15970            .into();
15971        if old_selections.is_empty() {
15972            return;
15973        }
15974
15975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15976
15977        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15978        let buffer = self.buffer.read(cx).snapshot(cx);
15979
15980        let mut selected_larger_node = false;
15981        let mut new_selections = old_selections
15982            .iter()
15983            .map(|selection| {
15984                let old_range = selection.start..selection.end;
15985
15986                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15987                    // manually select word at selection
15988                    if ["string_content", "inline"].contains(&node.kind()) {
15989                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15990                        // ignore if word is already selected
15991                        if !word_range.is_empty() && old_range != word_range {
15992                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15993                            // only select word if start and end point belongs to same word
15994                            if word_range == last_word_range {
15995                                selected_larger_node = true;
15996                                return Selection {
15997                                    id: selection.id,
15998                                    start: word_range.start,
15999                                    end: word_range.end,
16000                                    goal: SelectionGoal::None,
16001                                    reversed: selection.reversed,
16002                                };
16003                            }
16004                        }
16005                    }
16006                }
16007
16008                let mut new_range = old_range.clone();
16009                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16010                    new_range = range;
16011                    if !node.is_named() {
16012                        continue;
16013                    }
16014                    if !display_map.intersects_fold(new_range.start)
16015                        && !display_map.intersects_fold(new_range.end)
16016                    {
16017                        break;
16018                    }
16019                }
16020
16021                selected_larger_node |= new_range != old_range;
16022                Selection {
16023                    id: selection.id,
16024                    start: new_range.start,
16025                    end: new_range.end,
16026                    goal: SelectionGoal::None,
16027                    reversed: selection.reversed,
16028                }
16029            })
16030            .collect::<Vec<_>>();
16031
16032        if !selected_larger_node {
16033            return; // don't put this call in the history
16034        }
16035
16036        // scroll based on transformation done to the last selection created by the user
16037        let (last_old, last_new) = old_selections
16038            .last()
16039            .zip(new_selections.last().cloned())
16040            .expect("old_selections isn't empty");
16041
16042        // revert selection
16043        let is_selection_reversed = {
16044            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16045            new_selections.last_mut().expect("checked above").reversed =
16046                should_newest_selection_be_reversed;
16047            should_newest_selection_be_reversed
16048        };
16049
16050        if selected_larger_node {
16051            self.select_syntax_node_history.disable_clearing = true;
16052            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16053                s.select(new_selections.clone());
16054            });
16055            self.select_syntax_node_history.disable_clearing = false;
16056        }
16057
16058        let start_row = last_new.start.to_display_point(&display_map).row().0;
16059        let end_row = last_new.end.to_display_point(&display_map).row().0;
16060        let selection_height = end_row - start_row + 1;
16061        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16062
16063        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16064        let scroll_behavior = if fits_on_the_screen {
16065            self.request_autoscroll(Autoscroll::fit(), cx);
16066            SelectSyntaxNodeScrollBehavior::FitSelection
16067        } else if is_selection_reversed {
16068            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16069            SelectSyntaxNodeScrollBehavior::CursorTop
16070        } else {
16071            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16072            SelectSyntaxNodeScrollBehavior::CursorBottom
16073        };
16074
16075        self.select_syntax_node_history.push((
16076            old_selections,
16077            scroll_behavior,
16078            is_selection_reversed,
16079        ));
16080    }
16081
16082    pub fn select_smaller_syntax_node(
16083        &mut self,
16084        _: &SelectSmallerSyntaxNode,
16085        window: &mut Window,
16086        cx: &mut Context<Self>,
16087    ) {
16088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16089
16090        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16091            self.select_syntax_node_history.pop()
16092        {
16093            if let Some(selection) = selections.last_mut() {
16094                selection.reversed = is_selection_reversed;
16095            }
16096
16097            self.select_syntax_node_history.disable_clearing = true;
16098            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16099                s.select(selections.to_vec());
16100            });
16101            self.select_syntax_node_history.disable_clearing = false;
16102
16103            match scroll_behavior {
16104                SelectSyntaxNodeScrollBehavior::CursorTop => {
16105                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16106                }
16107                SelectSyntaxNodeScrollBehavior::FitSelection => {
16108                    self.request_autoscroll(Autoscroll::fit(), cx);
16109                }
16110                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16111                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16112                }
16113            }
16114        }
16115    }
16116
16117    pub fn unwrap_syntax_node(
16118        &mut self,
16119        _: &UnwrapSyntaxNode,
16120        window: &mut Window,
16121        cx: &mut Context<Self>,
16122    ) {
16123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16124
16125        let buffer = self.buffer.read(cx).snapshot(cx);
16126        let selections = self
16127            .selections
16128            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16129            .into_iter()
16130            // subtracting the offset requires sorting
16131            .sorted_by_key(|i| i.start);
16132
16133        let full_edits = selections
16134            .into_iter()
16135            .filter_map(|selection| {
16136                let child = if selection.is_empty()
16137                    && let Some((_, ancestor_range)) =
16138                        buffer.syntax_ancestor(selection.start..selection.end)
16139                {
16140                    ancestor_range
16141                } else {
16142                    selection.range()
16143                };
16144
16145                let mut parent = child.clone();
16146                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16147                    parent = ancestor_range;
16148                    if parent.start < child.start || parent.end > child.end {
16149                        break;
16150                    }
16151                }
16152
16153                if parent == child {
16154                    return None;
16155                }
16156                let text = buffer.text_for_range(child).collect::<String>();
16157                Some((selection.id, parent, text))
16158            })
16159            .collect::<Vec<_>>();
16160        if full_edits.is_empty() {
16161            return;
16162        }
16163
16164        self.transact(window, cx, |this, window, cx| {
16165            this.buffer.update(cx, |buffer, cx| {
16166                buffer.edit(
16167                    full_edits
16168                        .iter()
16169                        .map(|(_, p, t)| (p.clone(), t.clone()))
16170                        .collect::<Vec<_>>(),
16171                    None,
16172                    cx,
16173                );
16174            });
16175            this.change_selections(Default::default(), window, cx, |s| {
16176                let mut offset = 0;
16177                let mut selections = vec![];
16178                for (id, parent, text) in full_edits {
16179                    let start = parent.start - offset;
16180                    offset += (parent.end - parent.start) - text.len();
16181                    selections.push(Selection {
16182                        id,
16183                        start,
16184                        end: start + text.len(),
16185                        reversed: false,
16186                        goal: Default::default(),
16187                    });
16188                }
16189                s.select(selections);
16190            });
16191        });
16192    }
16193
16194    pub fn select_next_syntax_node(
16195        &mut self,
16196        _: &SelectNextSyntaxNode,
16197        window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) {
16200        let old_selections: Box<[_]> = self
16201            .selections
16202            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16203            .into();
16204        if old_selections.is_empty() {
16205            return;
16206        }
16207
16208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16209
16210        let buffer = self.buffer.read(cx).snapshot(cx);
16211        let mut selected_sibling = false;
16212
16213        let new_selections = old_selections
16214            .iter()
16215            .map(|selection| {
16216                let old_range = selection.start..selection.end;
16217
16218                let old_range =
16219                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16220                let excerpt = buffer.excerpt_containing(old_range.clone());
16221
16222                if let Some(mut excerpt) = excerpt
16223                    && let Some(node) = excerpt
16224                        .buffer()
16225                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16226                {
16227                    let new_range = excerpt.map_range_from_buffer(
16228                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16229                    );
16230                    selected_sibling = true;
16231                    Selection {
16232                        id: selection.id,
16233                        start: new_range.start,
16234                        end: new_range.end,
16235                        goal: SelectionGoal::None,
16236                        reversed: selection.reversed,
16237                    }
16238                } else {
16239                    selection.clone()
16240                }
16241            })
16242            .collect::<Vec<_>>();
16243
16244        if selected_sibling {
16245            self.change_selections(
16246                SelectionEffects::scroll(Autoscroll::fit()),
16247                window,
16248                cx,
16249                |s| {
16250                    s.select(new_selections);
16251                },
16252            );
16253        }
16254    }
16255
16256    pub fn select_prev_syntax_node(
16257        &mut self,
16258        _: &SelectPreviousSyntaxNode,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) {
16262        let old_selections: Box<[_]> = self
16263            .selections
16264            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16265            .into();
16266        if old_selections.is_empty() {
16267            return;
16268        }
16269
16270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16271
16272        let buffer = self.buffer.read(cx).snapshot(cx);
16273        let mut selected_sibling = false;
16274
16275        let new_selections = old_selections
16276            .iter()
16277            .map(|selection| {
16278                let old_range = selection.start..selection.end;
16279                let old_range =
16280                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16281                let excerpt = buffer.excerpt_containing(old_range.clone());
16282
16283                if let Some(mut excerpt) = excerpt
16284                    && let Some(node) = excerpt
16285                        .buffer()
16286                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16287                {
16288                    let new_range = excerpt.map_range_from_buffer(
16289                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16290                    );
16291                    selected_sibling = true;
16292                    Selection {
16293                        id: selection.id,
16294                        start: new_range.start,
16295                        end: new_range.end,
16296                        goal: SelectionGoal::None,
16297                        reversed: selection.reversed,
16298                    }
16299                } else {
16300                    selection.clone()
16301                }
16302            })
16303            .collect::<Vec<_>>();
16304
16305        if selected_sibling {
16306            self.change_selections(
16307                SelectionEffects::scroll(Autoscroll::fit()),
16308                window,
16309                cx,
16310                |s| {
16311                    s.select(new_selections);
16312                },
16313            );
16314        }
16315    }
16316
16317    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16318        if !EditorSettings::get_global(cx).gutter.runnables {
16319            self.clear_tasks();
16320            return Task::ready(());
16321        }
16322        let project = self.project().map(Entity::downgrade);
16323        let task_sources = self.lsp_task_sources(cx);
16324        let multi_buffer = self.buffer.downgrade();
16325        cx.spawn_in(window, async move |editor, cx| {
16326            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16327            let Some(project) = project.and_then(|p| p.upgrade()) else {
16328                return;
16329            };
16330            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16331                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16332            }) else {
16333                return;
16334            };
16335
16336            let hide_runnables = project
16337                .update(cx, |project, _| project.is_via_collab())
16338                .unwrap_or(true);
16339            if hide_runnables {
16340                return;
16341            }
16342            let new_rows =
16343                cx.background_spawn({
16344                    let snapshot = display_snapshot.clone();
16345                    async move {
16346                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16347                    }
16348                })
16349                    .await;
16350            let Ok(lsp_tasks) =
16351                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16352            else {
16353                return;
16354            };
16355            let lsp_tasks = lsp_tasks.await;
16356
16357            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16358                lsp_tasks
16359                    .into_iter()
16360                    .flat_map(|(kind, tasks)| {
16361                        tasks.into_iter().filter_map(move |(location, task)| {
16362                            Some((kind.clone(), location?, task))
16363                        })
16364                    })
16365                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16366                        let buffer = location.target.buffer;
16367                        let buffer_snapshot = buffer.read(cx).snapshot();
16368                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16369                            |(excerpt_id, snapshot, _)| {
16370                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16371                                    display_snapshot
16372                                        .buffer_snapshot()
16373                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16374                                } else {
16375                                    None
16376                                }
16377                            },
16378                        );
16379                        if let Some(offset) = offset {
16380                            let task_buffer_range =
16381                                location.target.range.to_point(&buffer_snapshot);
16382                            let context_buffer_range =
16383                                task_buffer_range.to_offset(&buffer_snapshot);
16384                            let context_range = BufferOffset(context_buffer_range.start)
16385                                ..BufferOffset(context_buffer_range.end);
16386
16387                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16388                                .or_insert_with(|| RunnableTasks {
16389                                    templates: Vec::new(),
16390                                    offset,
16391                                    column: task_buffer_range.start.column,
16392                                    extra_variables: HashMap::default(),
16393                                    context_range,
16394                                })
16395                                .templates
16396                                .push((kind, task.original_task().clone()));
16397                        }
16398
16399                        acc
16400                    })
16401            }) else {
16402                return;
16403            };
16404
16405            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16406                buffer.language_settings(cx).tasks.prefer_lsp
16407            }) else {
16408                return;
16409            };
16410
16411            let rows = Self::runnable_rows(
16412                project,
16413                display_snapshot,
16414                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16415                new_rows,
16416                cx.clone(),
16417            )
16418            .await;
16419            editor
16420                .update(cx, |editor, _| {
16421                    editor.clear_tasks();
16422                    for (key, mut value) in rows {
16423                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16424                            value.templates.extend(lsp_tasks.templates);
16425                        }
16426
16427                        editor.insert_tasks(key, value);
16428                    }
16429                    for (key, value) in lsp_tasks_by_rows {
16430                        editor.insert_tasks(key, value);
16431                    }
16432                })
16433                .ok();
16434        })
16435    }
16436    fn fetch_runnable_ranges(
16437        snapshot: &DisplaySnapshot,
16438        range: Range<Anchor>,
16439    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16440        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16441    }
16442
16443    fn runnable_rows(
16444        project: Entity<Project>,
16445        snapshot: DisplaySnapshot,
16446        prefer_lsp: bool,
16447        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16448        cx: AsyncWindowContext,
16449    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16450        cx.spawn(async move |cx| {
16451            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16452            for (run_range, mut runnable) in runnable_ranges {
16453                let Some(tasks) = cx
16454                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16455                    .ok()
16456                else {
16457                    continue;
16458                };
16459                let mut tasks = tasks.await;
16460
16461                if prefer_lsp {
16462                    tasks.retain(|(task_kind, _)| {
16463                        !matches!(task_kind, TaskSourceKind::Language { .. })
16464                    });
16465                }
16466                if tasks.is_empty() {
16467                    continue;
16468                }
16469
16470                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16471                let Some(row) = snapshot
16472                    .buffer_snapshot()
16473                    .buffer_line_for_row(MultiBufferRow(point.row))
16474                    .map(|(_, range)| range.start.row)
16475                else {
16476                    continue;
16477                };
16478
16479                let context_range =
16480                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16481                runnable_rows.push((
16482                    (runnable.buffer_id, row),
16483                    RunnableTasks {
16484                        templates: tasks,
16485                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16486                        context_range,
16487                        column: point.column,
16488                        extra_variables: runnable.extra_captures,
16489                    },
16490                ));
16491            }
16492            runnable_rows
16493        })
16494    }
16495
16496    fn templates_with_tags(
16497        project: &Entity<Project>,
16498        runnable: &mut Runnable,
16499        cx: &mut App,
16500    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16501        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16502            let (worktree_id, file) = project
16503                .buffer_for_id(runnable.buffer, cx)
16504                .and_then(|buffer| buffer.read(cx).file())
16505                .map(|file| (file.worktree_id(cx), file.clone()))
16506                .unzip();
16507
16508            (
16509                project.task_store().read(cx).task_inventory().cloned(),
16510                worktree_id,
16511                file,
16512            )
16513        });
16514
16515        let tags = mem::take(&mut runnable.tags);
16516        let language = runnable.language.clone();
16517        cx.spawn(async move |cx| {
16518            let mut templates_with_tags = Vec::new();
16519            if let Some(inventory) = inventory {
16520                for RunnableTag(tag) in tags {
16521                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16522                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16523                    }) else {
16524                        return templates_with_tags;
16525                    };
16526                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16527                        move |(_, template)| {
16528                            template.tags.iter().any(|source_tag| source_tag == &tag)
16529                        },
16530                    ));
16531                }
16532            }
16533            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16534
16535            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16536                // Strongest source wins; if we have worktree tag binding, prefer that to
16537                // global and language bindings;
16538                // if we have a global binding, prefer that to language binding.
16539                let first_mismatch = templates_with_tags
16540                    .iter()
16541                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16542                if let Some(index) = first_mismatch {
16543                    templates_with_tags.truncate(index);
16544                }
16545            }
16546
16547            templates_with_tags
16548        })
16549    }
16550
16551    pub fn move_to_enclosing_bracket(
16552        &mut self,
16553        _: &MoveToEnclosingBracket,
16554        window: &mut Window,
16555        cx: &mut Context<Self>,
16556    ) {
16557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16558        self.change_selections(Default::default(), window, cx, |s| {
16559            s.move_offsets_with(|snapshot, selection| {
16560                let Some(enclosing_bracket_ranges) =
16561                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16562                else {
16563                    return;
16564                };
16565
16566                let mut best_length = usize::MAX;
16567                let mut best_inside = false;
16568                let mut best_in_bracket_range = false;
16569                let mut best_destination = None;
16570                for (open, close) in enclosing_bracket_ranges {
16571                    let close = close.to_inclusive();
16572                    let length = *close.end() - open.start;
16573                    let inside = selection.start >= open.end && selection.end <= *close.start();
16574                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16575                        || close.contains(&selection.head());
16576
16577                    // If best is next to a bracket and current isn't, skip
16578                    if !in_bracket_range && best_in_bracket_range {
16579                        continue;
16580                    }
16581
16582                    // Prefer smaller lengths unless best is inside and current isn't
16583                    if length > best_length && (best_inside || !inside) {
16584                        continue;
16585                    }
16586
16587                    best_length = length;
16588                    best_inside = inside;
16589                    best_in_bracket_range = in_bracket_range;
16590                    best_destination = Some(
16591                        if close.contains(&selection.start) && close.contains(&selection.end) {
16592                            if inside { open.end } else { open.start }
16593                        } else if inside {
16594                            *close.start()
16595                        } else {
16596                            *close.end()
16597                        },
16598                    );
16599                }
16600
16601                if let Some(destination) = best_destination {
16602                    selection.collapse_to(destination, SelectionGoal::None);
16603                }
16604            })
16605        });
16606    }
16607
16608    pub fn undo_selection(
16609        &mut self,
16610        _: &UndoSelection,
16611        window: &mut Window,
16612        cx: &mut Context<Self>,
16613    ) {
16614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16615        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16616            self.selection_history.mode = SelectionHistoryMode::Undoing;
16617            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16618                this.end_selection(window, cx);
16619                this.change_selections(
16620                    SelectionEffects::scroll(Autoscroll::newest()),
16621                    window,
16622                    cx,
16623                    |s| s.select_anchors(entry.selections.to_vec()),
16624                );
16625            });
16626            self.selection_history.mode = SelectionHistoryMode::Normal;
16627
16628            self.select_next_state = entry.select_next_state;
16629            self.select_prev_state = entry.select_prev_state;
16630            self.add_selections_state = entry.add_selections_state;
16631        }
16632    }
16633
16634    pub fn redo_selection(
16635        &mut self,
16636        _: &RedoSelection,
16637        window: &mut Window,
16638        cx: &mut Context<Self>,
16639    ) {
16640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16641        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16642            self.selection_history.mode = SelectionHistoryMode::Redoing;
16643            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16644                this.end_selection(window, cx);
16645                this.change_selections(
16646                    SelectionEffects::scroll(Autoscroll::newest()),
16647                    window,
16648                    cx,
16649                    |s| s.select_anchors(entry.selections.to_vec()),
16650                );
16651            });
16652            self.selection_history.mode = SelectionHistoryMode::Normal;
16653
16654            self.select_next_state = entry.select_next_state;
16655            self.select_prev_state = entry.select_prev_state;
16656            self.add_selections_state = entry.add_selections_state;
16657        }
16658    }
16659
16660    pub fn expand_excerpts(
16661        &mut self,
16662        action: &ExpandExcerpts,
16663        _: &mut Window,
16664        cx: &mut Context<Self>,
16665    ) {
16666        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16667    }
16668
16669    pub fn expand_excerpts_down(
16670        &mut self,
16671        action: &ExpandExcerptsDown,
16672        _: &mut Window,
16673        cx: &mut Context<Self>,
16674    ) {
16675        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16676    }
16677
16678    pub fn expand_excerpts_up(
16679        &mut self,
16680        action: &ExpandExcerptsUp,
16681        _: &mut Window,
16682        cx: &mut Context<Self>,
16683    ) {
16684        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16685    }
16686
16687    pub fn expand_excerpts_for_direction(
16688        &mut self,
16689        lines: u32,
16690        direction: ExpandExcerptDirection,
16691
16692        cx: &mut Context<Self>,
16693    ) {
16694        let selections = self.selections.disjoint_anchors_arc();
16695
16696        let lines = if lines == 0 {
16697            EditorSettings::get_global(cx).expand_excerpt_lines
16698        } else {
16699            lines
16700        };
16701
16702        self.buffer.update(cx, |buffer, cx| {
16703            let snapshot = buffer.snapshot(cx);
16704            let mut excerpt_ids = selections
16705                .iter()
16706                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16707                .collect::<Vec<_>>();
16708            excerpt_ids.sort();
16709            excerpt_ids.dedup();
16710            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16711        })
16712    }
16713
16714    pub fn expand_excerpt(
16715        &mut self,
16716        excerpt: ExcerptId,
16717        direction: ExpandExcerptDirection,
16718        window: &mut Window,
16719        cx: &mut Context<Self>,
16720    ) {
16721        let current_scroll_position = self.scroll_position(cx);
16722        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16723        let mut scroll = None;
16724
16725        if direction == ExpandExcerptDirection::Down {
16726            let multi_buffer = self.buffer.read(cx);
16727            let snapshot = multi_buffer.snapshot(cx);
16728            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16729                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16730                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16731            {
16732                let buffer_snapshot = buffer.read(cx).snapshot();
16733                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16734                let last_row = buffer_snapshot.max_point().row;
16735                let lines_below = last_row.saturating_sub(excerpt_end_row);
16736                if lines_below >= lines_to_expand {
16737                    scroll = Some(
16738                        current_scroll_position
16739                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16740                    );
16741                }
16742            }
16743        }
16744        if direction == ExpandExcerptDirection::Up
16745            && self
16746                .buffer
16747                .read(cx)
16748                .snapshot(cx)
16749                .excerpt_before(excerpt)
16750                .is_none()
16751        {
16752            scroll = Some(current_scroll_position);
16753        }
16754
16755        self.buffer.update(cx, |buffer, cx| {
16756            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16757        });
16758
16759        if let Some(new_scroll_position) = scroll {
16760            self.set_scroll_position(new_scroll_position, window, cx);
16761        }
16762    }
16763
16764    pub fn go_to_singleton_buffer_point(
16765        &mut self,
16766        point: Point,
16767        window: &mut Window,
16768        cx: &mut Context<Self>,
16769    ) {
16770        self.go_to_singleton_buffer_range(point..point, window, cx);
16771    }
16772
16773    pub fn go_to_singleton_buffer_range(
16774        &mut self,
16775        range: Range<Point>,
16776        window: &mut Window,
16777        cx: &mut Context<Self>,
16778    ) {
16779        let multibuffer = self.buffer().read(cx);
16780        let Some(buffer) = multibuffer.as_singleton() else {
16781            return;
16782        };
16783        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16784            return;
16785        };
16786        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16787            return;
16788        };
16789        self.change_selections(
16790            SelectionEffects::default().nav_history(true),
16791            window,
16792            cx,
16793            |s| s.select_anchor_ranges([start..end]),
16794        );
16795    }
16796
16797    pub fn go_to_diagnostic(
16798        &mut self,
16799        action: &GoToDiagnostic,
16800        window: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) {
16803        if !self.diagnostics_enabled() {
16804            return;
16805        }
16806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16807        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16808    }
16809
16810    pub fn go_to_prev_diagnostic(
16811        &mut self,
16812        action: &GoToPreviousDiagnostic,
16813        window: &mut Window,
16814        cx: &mut Context<Self>,
16815    ) {
16816        if !self.diagnostics_enabled() {
16817            return;
16818        }
16819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16820        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16821    }
16822
16823    pub fn go_to_diagnostic_impl(
16824        &mut self,
16825        direction: Direction,
16826        severity: GoToDiagnosticSeverityFilter,
16827        window: &mut Window,
16828        cx: &mut Context<Self>,
16829    ) {
16830        let buffer = self.buffer.read(cx).snapshot(cx);
16831        let selection = self
16832            .selections
16833            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16834
16835        let mut active_group_id = None;
16836        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16837            && active_group.active_range.start.to_offset(&buffer) == selection.start
16838        {
16839            active_group_id = Some(active_group.group_id);
16840        }
16841
16842        fn filtered<'a>(
16843            severity: GoToDiagnosticSeverityFilter,
16844            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16845        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16846            diagnostics
16847                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16848                .filter(|entry| entry.range.start != entry.range.end)
16849                .filter(|entry| !entry.diagnostic.is_unnecessary)
16850        }
16851
16852        let before = filtered(
16853            severity,
16854            buffer
16855                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16856                .filter(|entry| entry.range.start <= selection.start),
16857        );
16858        let after = filtered(
16859            severity,
16860            buffer
16861                .diagnostics_in_range(selection.start..buffer.len())
16862                .filter(|entry| entry.range.start >= selection.start),
16863        );
16864
16865        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16866        if direction == Direction::Prev {
16867            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16868            {
16869                for diagnostic in prev_diagnostics.into_iter().rev() {
16870                    if diagnostic.range.start != selection.start
16871                        || active_group_id
16872                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16873                    {
16874                        found = Some(diagnostic);
16875                        break 'outer;
16876                    }
16877                }
16878            }
16879        } else {
16880            for diagnostic in after.chain(before) {
16881                if diagnostic.range.start != selection.start
16882                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16883                {
16884                    found = Some(diagnostic);
16885                    break;
16886                }
16887            }
16888        }
16889        let Some(next_diagnostic) = found else {
16890            return;
16891        };
16892
16893        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16894        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16895            return;
16896        };
16897        let snapshot = self.snapshot(window, cx);
16898        if snapshot.intersects_fold(next_diagnostic.range.start) {
16899            self.unfold_ranges(
16900                std::slice::from_ref(&next_diagnostic.range),
16901                true,
16902                false,
16903                cx,
16904            );
16905        }
16906        self.change_selections(Default::default(), window, cx, |s| {
16907            s.select_ranges(vec![
16908                next_diagnostic.range.start..next_diagnostic.range.start,
16909            ])
16910        });
16911        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16912        self.refresh_edit_prediction(false, true, window, cx);
16913    }
16914
16915    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16916        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16917        let snapshot = self.snapshot(window, cx);
16918        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16919        self.go_to_hunk_before_or_after_position(
16920            &snapshot,
16921            selection.head(),
16922            Direction::Next,
16923            window,
16924            cx,
16925        );
16926    }
16927
16928    pub fn go_to_hunk_before_or_after_position(
16929        &mut self,
16930        snapshot: &EditorSnapshot,
16931        position: Point,
16932        direction: Direction,
16933        window: &mut Window,
16934        cx: &mut Context<Editor>,
16935    ) {
16936        let row = if direction == Direction::Next {
16937            self.hunk_after_position(snapshot, position)
16938                .map(|hunk| hunk.row_range.start)
16939        } else {
16940            self.hunk_before_position(snapshot, position)
16941        };
16942
16943        if let Some(row) = row {
16944            let destination = Point::new(row.0, 0);
16945            let autoscroll = Autoscroll::center();
16946
16947            self.unfold_ranges(&[destination..destination], false, false, cx);
16948            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16949                s.select_ranges([destination..destination]);
16950            });
16951        }
16952    }
16953
16954    fn hunk_after_position(
16955        &mut self,
16956        snapshot: &EditorSnapshot,
16957        position: Point,
16958    ) -> Option<MultiBufferDiffHunk> {
16959        snapshot
16960            .buffer_snapshot()
16961            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16962            .find(|hunk| hunk.row_range.start.0 > position.row)
16963            .or_else(|| {
16964                snapshot
16965                    .buffer_snapshot()
16966                    .diff_hunks_in_range(Point::zero()..position)
16967                    .find(|hunk| hunk.row_range.end.0 < position.row)
16968            })
16969    }
16970
16971    fn go_to_prev_hunk(
16972        &mut self,
16973        _: &GoToPreviousHunk,
16974        window: &mut Window,
16975        cx: &mut Context<Self>,
16976    ) {
16977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16978        let snapshot = self.snapshot(window, cx);
16979        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16980        self.go_to_hunk_before_or_after_position(
16981            &snapshot,
16982            selection.head(),
16983            Direction::Prev,
16984            window,
16985            cx,
16986        );
16987    }
16988
16989    fn hunk_before_position(
16990        &mut self,
16991        snapshot: &EditorSnapshot,
16992        position: Point,
16993    ) -> Option<MultiBufferRow> {
16994        snapshot
16995            .buffer_snapshot()
16996            .diff_hunk_before(position)
16997            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16998    }
16999
17000    fn go_to_next_change(
17001        &mut self,
17002        _: &GoToNextChange,
17003        window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        if let Some(selections) = self
17007            .change_list
17008            .next_change(1, Direction::Next)
17009            .map(|s| s.to_vec())
17010        {
17011            self.change_selections(Default::default(), window, cx, |s| {
17012                let map = s.display_snapshot();
17013                s.select_display_ranges(selections.iter().map(|a| {
17014                    let point = a.to_display_point(&map);
17015                    point..point
17016                }))
17017            })
17018        }
17019    }
17020
17021    fn go_to_previous_change(
17022        &mut self,
17023        _: &GoToPreviousChange,
17024        window: &mut Window,
17025        cx: &mut Context<Self>,
17026    ) {
17027        if let Some(selections) = self
17028            .change_list
17029            .next_change(1, Direction::Prev)
17030            .map(|s| s.to_vec())
17031        {
17032            self.change_selections(Default::default(), window, cx, |s| {
17033                let map = s.display_snapshot();
17034                s.select_display_ranges(selections.iter().map(|a| {
17035                    let point = a.to_display_point(&map);
17036                    point..point
17037                }))
17038            })
17039        }
17040    }
17041
17042    pub fn go_to_next_document_highlight(
17043        &mut self,
17044        _: &GoToNextDocumentHighlight,
17045        window: &mut Window,
17046        cx: &mut Context<Self>,
17047    ) {
17048        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17049    }
17050
17051    pub fn go_to_prev_document_highlight(
17052        &mut self,
17053        _: &GoToPreviousDocumentHighlight,
17054        window: &mut Window,
17055        cx: &mut Context<Self>,
17056    ) {
17057        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17058    }
17059
17060    pub fn go_to_document_highlight_before_or_after_position(
17061        &mut self,
17062        direction: Direction,
17063        window: &mut Window,
17064        cx: &mut Context<Editor>,
17065    ) {
17066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17067        let snapshot = self.snapshot(window, cx);
17068        let buffer = &snapshot.buffer_snapshot();
17069        let position = self
17070            .selections
17071            .newest::<Point>(&snapshot.display_snapshot)
17072            .head();
17073        let anchor_position = buffer.anchor_after(position);
17074
17075        // Get all document highlights (both read and write)
17076        let mut all_highlights = Vec::new();
17077
17078        if let Some((_, read_highlights)) = self
17079            .background_highlights
17080            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17081        {
17082            all_highlights.extend(read_highlights.iter());
17083        }
17084
17085        if let Some((_, write_highlights)) = self
17086            .background_highlights
17087            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17088        {
17089            all_highlights.extend(write_highlights.iter());
17090        }
17091
17092        if all_highlights.is_empty() {
17093            return;
17094        }
17095
17096        // Sort highlights by position
17097        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17098
17099        let target_highlight = match direction {
17100            Direction::Next => {
17101                // Find the first highlight after the current position
17102                all_highlights
17103                    .iter()
17104                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17105            }
17106            Direction::Prev => {
17107                // Find the last highlight before the current position
17108                all_highlights
17109                    .iter()
17110                    .rev()
17111                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17112            }
17113        };
17114
17115        if let Some(highlight) = target_highlight {
17116            let destination = highlight.start.to_point(buffer);
17117            let autoscroll = Autoscroll::center();
17118
17119            self.unfold_ranges(&[destination..destination], false, false, cx);
17120            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17121                s.select_ranges([destination..destination]);
17122            });
17123        }
17124    }
17125
17126    fn go_to_line<T: 'static>(
17127        &mut self,
17128        position: Anchor,
17129        highlight_color: Option<Hsla>,
17130        window: &mut Window,
17131        cx: &mut Context<Self>,
17132    ) {
17133        let snapshot = self.snapshot(window, cx).display_snapshot;
17134        let position = position.to_point(&snapshot.buffer_snapshot());
17135        let start = snapshot
17136            .buffer_snapshot()
17137            .clip_point(Point::new(position.row, 0), Bias::Left);
17138        let end = start + Point::new(1, 0);
17139        let start = snapshot.buffer_snapshot().anchor_before(start);
17140        let end = snapshot.buffer_snapshot().anchor_before(end);
17141
17142        self.highlight_rows::<T>(
17143            start..end,
17144            highlight_color
17145                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17146            Default::default(),
17147            cx,
17148        );
17149
17150        if self.buffer.read(cx).is_singleton() {
17151            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17152        }
17153    }
17154
17155    pub fn go_to_definition(
17156        &mut self,
17157        _: &GoToDefinition,
17158        window: &mut Window,
17159        cx: &mut Context<Self>,
17160    ) -> Task<Result<Navigated>> {
17161        let definition =
17162            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17163        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17164        cx.spawn_in(window, async move |editor, cx| {
17165            if definition.await? == Navigated::Yes {
17166                return Ok(Navigated::Yes);
17167            }
17168            match fallback_strategy {
17169                GoToDefinitionFallback::None => Ok(Navigated::No),
17170                GoToDefinitionFallback::FindAllReferences => {
17171                    match editor.update_in(cx, |editor, window, cx| {
17172                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17173                    })? {
17174                        Some(references) => references.await,
17175                        None => Ok(Navigated::No),
17176                    }
17177                }
17178            }
17179        })
17180    }
17181
17182    pub fn go_to_declaration(
17183        &mut self,
17184        _: &GoToDeclaration,
17185        window: &mut Window,
17186        cx: &mut Context<Self>,
17187    ) -> Task<Result<Navigated>> {
17188        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17189    }
17190
17191    pub fn go_to_declaration_split(
17192        &mut self,
17193        _: &GoToDeclaration,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) -> Task<Result<Navigated>> {
17197        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17198    }
17199
17200    pub fn go_to_implementation(
17201        &mut self,
17202        _: &GoToImplementation,
17203        window: &mut Window,
17204        cx: &mut Context<Self>,
17205    ) -> Task<Result<Navigated>> {
17206        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17207    }
17208
17209    pub fn go_to_implementation_split(
17210        &mut self,
17211        _: &GoToImplementationSplit,
17212        window: &mut Window,
17213        cx: &mut Context<Self>,
17214    ) -> Task<Result<Navigated>> {
17215        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17216    }
17217
17218    pub fn go_to_type_definition(
17219        &mut self,
17220        _: &GoToTypeDefinition,
17221        window: &mut Window,
17222        cx: &mut Context<Self>,
17223    ) -> Task<Result<Navigated>> {
17224        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17225    }
17226
17227    pub fn go_to_definition_split(
17228        &mut self,
17229        _: &GoToDefinitionSplit,
17230        window: &mut Window,
17231        cx: &mut Context<Self>,
17232    ) -> Task<Result<Navigated>> {
17233        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17234    }
17235
17236    pub fn go_to_type_definition_split(
17237        &mut self,
17238        _: &GoToTypeDefinitionSplit,
17239        window: &mut Window,
17240        cx: &mut Context<Self>,
17241    ) -> Task<Result<Navigated>> {
17242        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17243    }
17244
17245    fn go_to_definition_of_kind(
17246        &mut self,
17247        kind: GotoDefinitionKind,
17248        split: bool,
17249        window: &mut Window,
17250        cx: &mut Context<Self>,
17251    ) -> Task<Result<Navigated>> {
17252        let Some(provider) = self.semantics_provider.clone() else {
17253            return Task::ready(Ok(Navigated::No));
17254        };
17255        let head = self
17256            .selections
17257            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17258            .head();
17259        let buffer = self.buffer.read(cx);
17260        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17261            return Task::ready(Ok(Navigated::No));
17262        };
17263        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17264            return Task::ready(Ok(Navigated::No));
17265        };
17266
17267        cx.spawn_in(window, async move |editor, cx| {
17268            let Some(definitions) = definitions.await? else {
17269                return Ok(Navigated::No);
17270            };
17271            let navigated = editor
17272                .update_in(cx, |editor, window, cx| {
17273                    editor.navigate_to_hover_links(
17274                        Some(kind),
17275                        definitions
17276                            .into_iter()
17277                            .filter(|location| {
17278                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17279                            })
17280                            .map(HoverLink::Text)
17281                            .collect::<Vec<_>>(),
17282                        split,
17283                        window,
17284                        cx,
17285                    )
17286                })?
17287                .await?;
17288            anyhow::Ok(navigated)
17289        })
17290    }
17291
17292    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17293        let selection = self.selections.newest_anchor();
17294        let head = selection.head();
17295        let tail = selection.tail();
17296
17297        let Some((buffer, start_position)) =
17298            self.buffer.read(cx).text_anchor_for_position(head, cx)
17299        else {
17300            return;
17301        };
17302
17303        let end_position = if head != tail {
17304            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17305                return;
17306            };
17307            Some(pos)
17308        } else {
17309            None
17310        };
17311
17312        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17313            let url = if let Some(end_pos) = end_position {
17314                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17315            } else {
17316                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17317            };
17318
17319            if let Some(url) = url {
17320                cx.update(|window, cx| {
17321                    if parse_zed_link(&url, cx).is_some() {
17322                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17323                    } else {
17324                        cx.open_url(&url);
17325                    }
17326                })?;
17327            }
17328
17329            anyhow::Ok(())
17330        });
17331
17332        url_finder.detach();
17333    }
17334
17335    pub fn open_selected_filename(
17336        &mut self,
17337        _: &OpenSelectedFilename,
17338        window: &mut Window,
17339        cx: &mut Context<Self>,
17340    ) {
17341        let Some(workspace) = self.workspace() else {
17342            return;
17343        };
17344
17345        let position = self.selections.newest_anchor().head();
17346
17347        let Some((buffer, buffer_position)) =
17348            self.buffer.read(cx).text_anchor_for_position(position, cx)
17349        else {
17350            return;
17351        };
17352
17353        let project = self.project.clone();
17354
17355        cx.spawn_in(window, async move |_, cx| {
17356            let result = find_file(&buffer, project, buffer_position, cx).await;
17357
17358            if let Some((_, path)) = result {
17359                workspace
17360                    .update_in(cx, |workspace, window, cx| {
17361                        workspace.open_resolved_path(path, window, cx)
17362                    })?
17363                    .await?;
17364            }
17365            anyhow::Ok(())
17366        })
17367        .detach();
17368    }
17369
17370    pub(crate) fn navigate_to_hover_links(
17371        &mut self,
17372        kind: Option<GotoDefinitionKind>,
17373        definitions: Vec<HoverLink>,
17374        split: bool,
17375        window: &mut Window,
17376        cx: &mut Context<Editor>,
17377    ) -> Task<Result<Navigated>> {
17378        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17379        let mut first_url_or_file = None;
17380        let definitions: Vec<_> = definitions
17381            .into_iter()
17382            .filter_map(|def| match def {
17383                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17384                HoverLink::InlayHint(lsp_location, server_id) => {
17385                    let computation =
17386                        self.compute_target_location(lsp_location, server_id, window, cx);
17387                    Some(cx.background_spawn(computation))
17388                }
17389                HoverLink::Url(url) => {
17390                    first_url_or_file = Some(Either::Left(url));
17391                    None
17392                }
17393                HoverLink::File(path) => {
17394                    first_url_or_file = Some(Either::Right(path));
17395                    None
17396                }
17397            })
17398            .collect();
17399
17400        let workspace = self.workspace();
17401
17402        cx.spawn_in(window, async move |editor, cx| {
17403            let locations: Vec<Location> = future::join_all(definitions)
17404                .await
17405                .into_iter()
17406                .filter_map(|location| location.transpose())
17407                .collect::<Result<_>>()
17408                .context("location tasks")?;
17409            let mut locations = cx.update(|_, cx| {
17410                locations
17411                    .into_iter()
17412                    .map(|location| {
17413                        let buffer = location.buffer.read(cx);
17414                        (location.buffer, location.range.to_point(buffer))
17415                    })
17416                    .into_group_map()
17417            })?;
17418            let mut num_locations = 0;
17419            for ranges in locations.values_mut() {
17420                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17421                ranges.dedup();
17422                num_locations += ranges.len();
17423            }
17424
17425            if num_locations > 1 {
17426                let tab_kind = match kind {
17427                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17428                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17429                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17430                    Some(GotoDefinitionKind::Type) => "Types",
17431                };
17432                let title = editor
17433                    .update_in(cx, |_, _, cx| {
17434                        let target = locations
17435                            .iter()
17436                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17437                            .map(|(buffer, location)| {
17438                                buffer
17439                                    .read(cx)
17440                                    .text_for_range(location.clone())
17441                                    .collect::<String>()
17442                            })
17443                            .filter(|text| !text.contains('\n'))
17444                            .unique()
17445                            .take(3)
17446                            .join(", ");
17447                        if target.is_empty() {
17448                            tab_kind.to_owned()
17449                        } else {
17450                            format!("{tab_kind} for {target}")
17451                        }
17452                    })
17453                    .context("buffer title")?;
17454
17455                let Some(workspace) = workspace else {
17456                    return Ok(Navigated::No);
17457                };
17458
17459                let opened = workspace
17460                    .update_in(cx, |workspace, window, cx| {
17461                        let allow_preview = PreviewTabsSettings::get_global(cx)
17462                            .enable_preview_multibuffer_from_code_navigation;
17463                        Self::open_locations_in_multibuffer(
17464                            workspace,
17465                            locations,
17466                            title,
17467                            split,
17468                            allow_preview,
17469                            MultibufferSelectionMode::First,
17470                            window,
17471                            cx,
17472                        )
17473                    })
17474                    .is_ok();
17475
17476                anyhow::Ok(Navigated::from_bool(opened))
17477            } else if num_locations == 0 {
17478                // If there is one url or file, open it directly
17479                match first_url_or_file {
17480                    Some(Either::Left(url)) => {
17481                        cx.update(|window, cx| {
17482                            if parse_zed_link(&url, cx).is_some() {
17483                                window
17484                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17485                            } else {
17486                                cx.open_url(&url);
17487                            }
17488                        })?;
17489                        Ok(Navigated::Yes)
17490                    }
17491                    Some(Either::Right(path)) => {
17492                        // TODO(andrew): respect preview tab settings
17493                        //               `enable_keep_preview_on_code_navigation` and
17494                        //               `enable_preview_file_from_code_navigation`
17495                        let Some(workspace) = workspace else {
17496                            return Ok(Navigated::No);
17497                        };
17498                        workspace
17499                            .update_in(cx, |workspace, window, cx| {
17500                                workspace.open_resolved_path(path, window, cx)
17501                            })?
17502                            .await?;
17503                        Ok(Navigated::Yes)
17504                    }
17505                    None => Ok(Navigated::No),
17506                }
17507            } else {
17508                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17509                let target_range = target_ranges.first().unwrap().clone();
17510
17511                editor.update_in(cx, |editor, window, cx| {
17512                    let range = target_range.to_point(target_buffer.read(cx));
17513                    let range = editor.range_for_match(&range);
17514                    let range = collapse_multiline_range(range);
17515
17516                    if !split
17517                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17518                    {
17519                        editor.go_to_singleton_buffer_range(range, window, cx);
17520                    } else {
17521                        let Some(workspace) = workspace else {
17522                            return Navigated::No;
17523                        };
17524                        let pane = workspace.read(cx).active_pane().clone();
17525                        window.defer(cx, move |window, cx| {
17526                            let target_editor: Entity<Self> =
17527                                workspace.update(cx, |workspace, cx| {
17528                                    let pane = if split {
17529                                        workspace.adjacent_pane(window, cx)
17530                                    } else {
17531                                        workspace.active_pane().clone()
17532                                    };
17533
17534                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17535                                    let keep_old_preview = preview_tabs_settings
17536                                        .enable_keep_preview_on_code_navigation;
17537                                    let allow_new_preview = preview_tabs_settings
17538                                        .enable_preview_file_from_code_navigation;
17539
17540                                    workspace.open_project_item(
17541                                        pane,
17542                                        target_buffer.clone(),
17543                                        true,
17544                                        true,
17545                                        keep_old_preview,
17546                                        allow_new_preview,
17547                                        window,
17548                                        cx,
17549                                    )
17550                                });
17551                            target_editor.update(cx, |target_editor, cx| {
17552                                // When selecting a definition in a different buffer, disable the nav history
17553                                // to avoid creating a history entry at the previous cursor location.
17554                                pane.update(cx, |pane, _| pane.disable_history());
17555                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17556                                pane.update(cx, |pane, _| pane.enable_history());
17557                            });
17558                        });
17559                    }
17560                    Navigated::Yes
17561                })
17562            }
17563        })
17564    }
17565
17566    fn compute_target_location(
17567        &self,
17568        lsp_location: lsp::Location,
17569        server_id: LanguageServerId,
17570        window: &mut Window,
17571        cx: &mut Context<Self>,
17572    ) -> Task<anyhow::Result<Option<Location>>> {
17573        let Some(project) = self.project.clone() else {
17574            return Task::ready(Ok(None));
17575        };
17576
17577        cx.spawn_in(window, async move |editor, cx| {
17578            let location_task = editor.update(cx, |_, cx| {
17579                project.update(cx, |project, cx| {
17580                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17581                })
17582            })?;
17583            let location = Some({
17584                let target_buffer_handle = location_task.await.context("open local buffer")?;
17585                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17586                    let target_start = target_buffer
17587                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17588                    let target_end = target_buffer
17589                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17590                    target_buffer.anchor_after(target_start)
17591                        ..target_buffer.anchor_before(target_end)
17592                })?;
17593                Location {
17594                    buffer: target_buffer_handle,
17595                    range,
17596                }
17597            });
17598            Ok(location)
17599        })
17600    }
17601
17602    fn go_to_next_reference(
17603        &mut self,
17604        _: &GoToNextReference,
17605        window: &mut Window,
17606        cx: &mut Context<Self>,
17607    ) {
17608        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17609        if let Some(task) = task {
17610            task.detach();
17611        };
17612    }
17613
17614    fn go_to_prev_reference(
17615        &mut self,
17616        _: &GoToPreviousReference,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17621        if let Some(task) = task {
17622            task.detach();
17623        };
17624    }
17625
17626    pub fn go_to_reference_before_or_after_position(
17627        &mut self,
17628        direction: Direction,
17629        count: usize,
17630        window: &mut Window,
17631        cx: &mut Context<Self>,
17632    ) -> Option<Task<Result<()>>> {
17633        let selection = self.selections.newest_anchor();
17634        let head = selection.head();
17635
17636        let multi_buffer = self.buffer.read(cx);
17637
17638        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17639        let workspace = self.workspace()?;
17640        let project = workspace.read(cx).project().clone();
17641        let references =
17642            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17643        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17644            let Some(locations) = references.await? else {
17645                return Ok(());
17646            };
17647
17648            if locations.is_empty() {
17649                // totally normal - the cursor may be on something which is not
17650                // a symbol (e.g. a keyword)
17651                log::info!("no references found under cursor");
17652                return Ok(());
17653            }
17654
17655            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17656
17657            let (locations, current_location_index) =
17658                multi_buffer.update(cx, |multi_buffer, cx| {
17659                    let mut locations = locations
17660                        .into_iter()
17661                        .filter_map(|loc| {
17662                            let start = multi_buffer.buffer_anchor_to_anchor(
17663                                &loc.buffer,
17664                                loc.range.start,
17665                                cx,
17666                            )?;
17667                            let end = multi_buffer.buffer_anchor_to_anchor(
17668                                &loc.buffer,
17669                                loc.range.end,
17670                                cx,
17671                            )?;
17672                            Some(start..end)
17673                        })
17674                        .collect::<Vec<_>>();
17675
17676                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17677                    // There is an O(n) implementation, but given this list will be
17678                    // small (usually <100 items), the extra O(log(n)) factor isn't
17679                    // worth the (surprisingly large amount of) extra complexity.
17680                    locations
17681                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17682
17683                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17684
17685                    let current_location_index = locations.iter().position(|loc| {
17686                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17687                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17688                    });
17689
17690                    (locations, current_location_index)
17691                })?;
17692
17693            let Some(current_location_index) = current_location_index else {
17694                // This indicates something has gone wrong, because we already
17695                // handle the "no references" case above
17696                log::error!(
17697                    "failed to find current reference under cursor. Total references: {}",
17698                    locations.len()
17699                );
17700                return Ok(());
17701            };
17702
17703            let destination_location_index = match direction {
17704                Direction::Next => (current_location_index + count) % locations.len(),
17705                Direction::Prev => {
17706                    (current_location_index + locations.len() - count % locations.len())
17707                        % locations.len()
17708                }
17709            };
17710
17711            // TODO(cameron): is this needed?
17712            // the thinking is to avoid "jumping to the current location" (avoid
17713            // polluting "jumplist" in vim terms)
17714            if current_location_index == destination_location_index {
17715                return Ok(());
17716            }
17717
17718            let Range { start, end } = locations[destination_location_index];
17719
17720            editor.update_in(cx, |editor, window, cx| {
17721                let effects = SelectionEffects::default();
17722
17723                editor.unfold_ranges(&[start..end], false, false, cx);
17724                editor.change_selections(effects, window, cx, |s| {
17725                    s.select_ranges([start..start]);
17726                });
17727            })?;
17728
17729            Ok(())
17730        }))
17731    }
17732
17733    pub fn find_all_references(
17734        &mut self,
17735        action: &FindAllReferences,
17736        window: &mut Window,
17737        cx: &mut Context<Self>,
17738    ) -> Option<Task<Result<Navigated>>> {
17739        let always_open_multibuffer = action.always_open_multibuffer;
17740        let selection = self.selections.newest_anchor();
17741        let multi_buffer = self.buffer.read(cx);
17742        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17743        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17744        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17745        let head = selection_offset.head();
17746
17747        let head_anchor = multi_buffer_snapshot.anchor_at(
17748            head,
17749            if head < selection_offset.tail() {
17750                Bias::Right
17751            } else {
17752                Bias::Left
17753            },
17754        );
17755
17756        match self
17757            .find_all_references_task_sources
17758            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17759        {
17760            Ok(_) => {
17761                log::info!(
17762                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17763                );
17764                return None;
17765            }
17766            Err(i) => {
17767                self.find_all_references_task_sources.insert(i, head_anchor);
17768            }
17769        }
17770
17771        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17772        let workspace = self.workspace()?;
17773        let project = workspace.read(cx).project().clone();
17774        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17775        Some(cx.spawn_in(window, async move |editor, cx| {
17776            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17777                if let Ok(i) = editor
17778                    .find_all_references_task_sources
17779                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17780                {
17781                    editor.find_all_references_task_sources.remove(i);
17782                }
17783            });
17784
17785            let Some(locations) = references.await? else {
17786                return anyhow::Ok(Navigated::No);
17787            };
17788            let mut locations = cx.update(|_, cx| {
17789                locations
17790                    .into_iter()
17791                    .map(|location| {
17792                        let buffer = location.buffer.read(cx);
17793                        (location.buffer, location.range.to_point(buffer))
17794                    })
17795                    // if special-casing the single-match case, remove ranges
17796                    // that intersect current selection
17797                    .filter(|(location_buffer, location)| {
17798                        if always_open_multibuffer || &buffer != location_buffer {
17799                            return true;
17800                        }
17801
17802                        !location.contains_inclusive(&selection_point.range())
17803                    })
17804                    .into_group_map()
17805            })?;
17806            if locations.is_empty() {
17807                return anyhow::Ok(Navigated::No);
17808            }
17809            for ranges in locations.values_mut() {
17810                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17811                ranges.dedup();
17812            }
17813            let mut num_locations = 0;
17814            for ranges in locations.values_mut() {
17815                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17816                ranges.dedup();
17817                num_locations += ranges.len();
17818            }
17819
17820            if num_locations == 1 && !always_open_multibuffer {
17821                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17822                let target_range = target_ranges.first().unwrap().clone();
17823
17824                return editor.update_in(cx, |editor, window, cx| {
17825                    let range = target_range.to_point(target_buffer.read(cx));
17826                    let range = editor.range_for_match(&range);
17827                    let range = range.start..range.start;
17828
17829                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17830                        editor.go_to_singleton_buffer_range(range, window, cx);
17831                    } else {
17832                        let pane = workspace.read(cx).active_pane().clone();
17833                        window.defer(cx, move |window, cx| {
17834                            let target_editor: Entity<Self> =
17835                                workspace.update(cx, |workspace, cx| {
17836                                    let pane = workspace.active_pane().clone();
17837
17838                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17839                                    let keep_old_preview = preview_tabs_settings
17840                                        .enable_keep_preview_on_code_navigation;
17841                                    let allow_new_preview = preview_tabs_settings
17842                                        .enable_preview_file_from_code_navigation;
17843
17844                                    workspace.open_project_item(
17845                                        pane,
17846                                        target_buffer.clone(),
17847                                        true,
17848                                        true,
17849                                        keep_old_preview,
17850                                        allow_new_preview,
17851                                        window,
17852                                        cx,
17853                                    )
17854                                });
17855                            target_editor.update(cx, |target_editor, cx| {
17856                                // When selecting a definition in a different buffer, disable the nav history
17857                                // to avoid creating a history entry at the previous cursor location.
17858                                pane.update(cx, |pane, _| pane.disable_history());
17859                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17860                                pane.update(cx, |pane, _| pane.enable_history());
17861                            });
17862                        });
17863                    }
17864                    Navigated::No
17865                });
17866            }
17867
17868            workspace.update_in(cx, |workspace, window, cx| {
17869                let target = locations
17870                    .iter()
17871                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17872                    .map(|(buffer, location)| {
17873                        buffer
17874                            .read(cx)
17875                            .text_for_range(location.clone())
17876                            .collect::<String>()
17877                    })
17878                    .filter(|text| !text.contains('\n'))
17879                    .unique()
17880                    .take(3)
17881                    .join(", ");
17882                let title = if target.is_empty() {
17883                    "References".to_owned()
17884                } else {
17885                    format!("References to {target}")
17886                };
17887                let allow_preview = PreviewTabsSettings::get_global(cx)
17888                    .enable_preview_multibuffer_from_code_navigation;
17889                Self::open_locations_in_multibuffer(
17890                    workspace,
17891                    locations,
17892                    title,
17893                    false,
17894                    allow_preview,
17895                    MultibufferSelectionMode::First,
17896                    window,
17897                    cx,
17898                );
17899                Navigated::Yes
17900            })
17901        }))
17902    }
17903
17904    /// Opens a multibuffer with the given project locations in it.
17905    pub fn open_locations_in_multibuffer(
17906        workspace: &mut Workspace,
17907        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17908        title: String,
17909        split: bool,
17910        allow_preview: bool,
17911        multibuffer_selection_mode: MultibufferSelectionMode,
17912        window: &mut Window,
17913        cx: &mut Context<Workspace>,
17914    ) {
17915        if locations.is_empty() {
17916            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17917            return;
17918        }
17919
17920        let capability = workspace.project().read(cx).capability();
17921        let mut ranges = <Vec<Range<Anchor>>>::new();
17922
17923        // a key to find existing multibuffer editors with the same set of locations
17924        // to prevent us from opening more and more multibuffer tabs for searches and the like
17925        let mut key = (title.clone(), vec![]);
17926        let excerpt_buffer = cx.new(|cx| {
17927            let key = &mut key.1;
17928            let mut multibuffer = MultiBuffer::new(capability);
17929            for (buffer, mut ranges_for_buffer) in locations {
17930                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17931                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17932                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17933                    PathKey::for_buffer(&buffer, cx),
17934                    buffer.clone(),
17935                    ranges_for_buffer,
17936                    multibuffer_context_lines(cx),
17937                    cx,
17938                );
17939                ranges.extend(new_ranges)
17940            }
17941
17942            multibuffer.with_title(title)
17943        });
17944        let existing = workspace.active_pane().update(cx, |pane, cx| {
17945            pane.items()
17946                .filter_map(|item| item.downcast::<Editor>())
17947                .find(|editor| {
17948                    editor
17949                        .read(cx)
17950                        .lookup_key
17951                        .as_ref()
17952                        .and_then(|it| {
17953                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17954                        })
17955                        .is_some_and(|it| *it == key)
17956                })
17957        });
17958        let was_existing = existing.is_some();
17959        let editor = existing.unwrap_or_else(|| {
17960            cx.new(|cx| {
17961                let mut editor = Editor::for_multibuffer(
17962                    excerpt_buffer,
17963                    Some(workspace.project().clone()),
17964                    window,
17965                    cx,
17966                );
17967                editor.lookup_key = Some(Box::new(key));
17968                editor
17969            })
17970        });
17971        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17972            MultibufferSelectionMode::First => {
17973                if let Some(first_range) = ranges.first() {
17974                    editor.change_selections(
17975                        SelectionEffects::no_scroll(),
17976                        window,
17977                        cx,
17978                        |selections| {
17979                            selections.clear_disjoint();
17980                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17981                        },
17982                    );
17983                }
17984                editor.highlight_background::<Self>(
17985                    &ranges,
17986                    |_, theme| theme.colors().editor_highlighted_line_background,
17987                    cx,
17988                );
17989            }
17990            MultibufferSelectionMode::All => {
17991                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17992                    selections.clear_disjoint();
17993                    selections.select_anchor_ranges(ranges);
17994                });
17995            }
17996        });
17997
17998        let item = Box::new(editor);
17999
18000        let pane = if split {
18001            workspace.adjacent_pane(window, cx)
18002        } else {
18003            workspace.active_pane().clone()
18004        };
18005        let activate_pane = split;
18006
18007        let mut destination_index = None;
18008        pane.update(cx, |pane, cx| {
18009            if allow_preview && !was_existing {
18010                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18011            }
18012            if was_existing && !allow_preview {
18013                pane.unpreview_item_if_preview(item.item_id());
18014            }
18015            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18016        });
18017    }
18018
18019    pub fn rename(
18020        &mut self,
18021        _: &Rename,
18022        window: &mut Window,
18023        cx: &mut Context<Self>,
18024    ) -> Option<Task<Result<()>>> {
18025        use language::ToOffset as _;
18026
18027        let provider = self.semantics_provider.clone()?;
18028        let selection = self.selections.newest_anchor().clone();
18029        let (cursor_buffer, cursor_buffer_position) = self
18030            .buffer
18031            .read(cx)
18032            .text_anchor_for_position(selection.head(), cx)?;
18033        let (tail_buffer, cursor_buffer_position_end) = self
18034            .buffer
18035            .read(cx)
18036            .text_anchor_for_position(selection.tail(), cx)?;
18037        if tail_buffer != cursor_buffer {
18038            return None;
18039        }
18040
18041        let snapshot = cursor_buffer.read(cx).snapshot();
18042        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18043        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18044        let prepare_rename = provider
18045            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18046            .unwrap_or_else(|| Task::ready(Ok(None)));
18047        drop(snapshot);
18048
18049        Some(cx.spawn_in(window, async move |this, cx| {
18050            let rename_range = if let Some(range) = prepare_rename.await? {
18051                Some(range)
18052            } else {
18053                this.update(cx, |this, cx| {
18054                    let buffer = this.buffer.read(cx).snapshot(cx);
18055                    let mut buffer_highlights = this
18056                        .document_highlights_for_position(selection.head(), &buffer)
18057                        .filter(|highlight| {
18058                            highlight.start.excerpt_id == selection.head().excerpt_id
18059                                && highlight.end.excerpt_id == selection.head().excerpt_id
18060                        });
18061                    buffer_highlights
18062                        .next()
18063                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18064                })?
18065            };
18066            if let Some(rename_range) = rename_range {
18067                this.update_in(cx, |this, window, cx| {
18068                    let snapshot = cursor_buffer.read(cx).snapshot();
18069                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18070                    let cursor_offset_in_rename_range =
18071                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18072                    let cursor_offset_in_rename_range_end =
18073                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18074
18075                    this.take_rename(false, window, cx);
18076                    let buffer = this.buffer.read(cx).read(cx);
18077                    let cursor_offset = selection.head().to_offset(&buffer);
18078                    let rename_start =
18079                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18080                    let rename_end = rename_start + rename_buffer_range.len();
18081                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18082                    let mut old_highlight_id = None;
18083                    let old_name: Arc<str> = buffer
18084                        .chunks(rename_start..rename_end, true)
18085                        .map(|chunk| {
18086                            if old_highlight_id.is_none() {
18087                                old_highlight_id = chunk.syntax_highlight_id;
18088                            }
18089                            chunk.text
18090                        })
18091                        .collect::<String>()
18092                        .into();
18093
18094                    drop(buffer);
18095
18096                    // Position the selection in the rename editor so that it matches the current selection.
18097                    this.show_local_selections = false;
18098                    let rename_editor = cx.new(|cx| {
18099                        let mut editor = Editor::single_line(window, cx);
18100                        editor.buffer.update(cx, |buffer, cx| {
18101                            buffer.edit(
18102                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18103                                None,
18104                                cx,
18105                            )
18106                        });
18107                        let cursor_offset_in_rename_range =
18108                            MultiBufferOffset(cursor_offset_in_rename_range);
18109                        let cursor_offset_in_rename_range_end =
18110                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18111                        let rename_selection_range = match cursor_offset_in_rename_range
18112                            .cmp(&cursor_offset_in_rename_range_end)
18113                        {
18114                            Ordering::Equal => {
18115                                editor.select_all(&SelectAll, window, cx);
18116                                return editor;
18117                            }
18118                            Ordering::Less => {
18119                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18120                            }
18121                            Ordering::Greater => {
18122                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18123                            }
18124                        };
18125                        if rename_selection_range.end.0 > old_name.len() {
18126                            editor.select_all(&SelectAll, window, cx);
18127                        } else {
18128                            editor.change_selections(Default::default(), window, cx, |s| {
18129                                s.select_ranges([rename_selection_range]);
18130                            });
18131                        }
18132                        editor
18133                    });
18134                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18135                        if e == &EditorEvent::Focused {
18136                            cx.emit(EditorEvent::FocusedIn)
18137                        }
18138                    })
18139                    .detach();
18140
18141                    let write_highlights =
18142                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18143                    let read_highlights =
18144                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18145                    let ranges = write_highlights
18146                        .iter()
18147                        .flat_map(|(_, ranges)| ranges.iter())
18148                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18149                        .cloned()
18150                        .collect();
18151
18152                    this.highlight_text::<Rename>(
18153                        ranges,
18154                        HighlightStyle {
18155                            fade_out: Some(0.6),
18156                            ..Default::default()
18157                        },
18158                        cx,
18159                    );
18160                    let rename_focus_handle = rename_editor.focus_handle(cx);
18161                    window.focus(&rename_focus_handle);
18162                    let block_id = this.insert_blocks(
18163                        [BlockProperties {
18164                            style: BlockStyle::Flex,
18165                            placement: BlockPlacement::Below(range.start),
18166                            height: Some(1),
18167                            render: Arc::new({
18168                                let rename_editor = rename_editor.clone();
18169                                move |cx: &mut BlockContext| {
18170                                    let mut text_style = cx.editor_style.text.clone();
18171                                    if let Some(highlight_style) = old_highlight_id
18172                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18173                                    {
18174                                        text_style = text_style.highlight(highlight_style);
18175                                    }
18176                                    div()
18177                                        .block_mouse_except_scroll()
18178                                        .pl(cx.anchor_x)
18179                                        .child(EditorElement::new(
18180                                            &rename_editor,
18181                                            EditorStyle {
18182                                                background: cx.theme().system().transparent,
18183                                                local_player: cx.editor_style.local_player,
18184                                                text: text_style,
18185                                                scrollbar_width: cx.editor_style.scrollbar_width,
18186                                                syntax: cx.editor_style.syntax.clone(),
18187                                                status: cx.editor_style.status.clone(),
18188                                                inlay_hints_style: HighlightStyle {
18189                                                    font_weight: Some(FontWeight::BOLD),
18190                                                    ..make_inlay_hints_style(cx.app)
18191                                                },
18192                                                edit_prediction_styles: make_suggestion_styles(
18193                                                    cx.app,
18194                                                ),
18195                                                ..EditorStyle::default()
18196                                            },
18197                                        ))
18198                                        .into_any_element()
18199                                }
18200                            }),
18201                            priority: 0,
18202                        }],
18203                        Some(Autoscroll::fit()),
18204                        cx,
18205                    )[0];
18206                    this.pending_rename = Some(RenameState {
18207                        range,
18208                        old_name,
18209                        editor: rename_editor,
18210                        block_id,
18211                    });
18212                })?;
18213            }
18214
18215            Ok(())
18216        }))
18217    }
18218
18219    pub fn confirm_rename(
18220        &mut self,
18221        _: &ConfirmRename,
18222        window: &mut Window,
18223        cx: &mut Context<Self>,
18224    ) -> Option<Task<Result<()>>> {
18225        let rename = self.take_rename(false, window, cx)?;
18226        let workspace = self.workspace()?.downgrade();
18227        let (buffer, start) = self
18228            .buffer
18229            .read(cx)
18230            .text_anchor_for_position(rename.range.start, cx)?;
18231        let (end_buffer, _) = self
18232            .buffer
18233            .read(cx)
18234            .text_anchor_for_position(rename.range.end, cx)?;
18235        if buffer != end_buffer {
18236            return None;
18237        }
18238
18239        let old_name = rename.old_name;
18240        let new_name = rename.editor.read(cx).text(cx);
18241
18242        let rename = self.semantics_provider.as_ref()?.perform_rename(
18243            &buffer,
18244            start,
18245            new_name.clone(),
18246            cx,
18247        )?;
18248
18249        Some(cx.spawn_in(window, async move |editor, cx| {
18250            let project_transaction = rename.await?;
18251            Self::open_project_transaction(
18252                &editor,
18253                workspace,
18254                project_transaction,
18255                format!("Rename: {}{}", old_name, new_name),
18256                cx,
18257            )
18258            .await?;
18259
18260            editor.update(cx, |editor, cx| {
18261                editor.refresh_document_highlights(cx);
18262            })?;
18263            Ok(())
18264        }))
18265    }
18266
18267    fn take_rename(
18268        &mut self,
18269        moving_cursor: bool,
18270        window: &mut Window,
18271        cx: &mut Context<Self>,
18272    ) -> Option<RenameState> {
18273        let rename = self.pending_rename.take()?;
18274        if rename.editor.focus_handle(cx).is_focused(window) {
18275            window.focus(&self.focus_handle);
18276        }
18277
18278        self.remove_blocks(
18279            [rename.block_id].into_iter().collect(),
18280            Some(Autoscroll::fit()),
18281            cx,
18282        );
18283        self.clear_highlights::<Rename>(cx);
18284        self.show_local_selections = true;
18285
18286        if moving_cursor {
18287            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18288                editor
18289                    .selections
18290                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18291                    .head()
18292            });
18293
18294            // Update the selection to match the position of the selection inside
18295            // the rename editor.
18296            let snapshot = self.buffer.read(cx).read(cx);
18297            let rename_range = rename.range.to_offset(&snapshot);
18298            let cursor_in_editor = snapshot
18299                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18300                .min(rename_range.end);
18301            drop(snapshot);
18302
18303            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18304                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18305            });
18306        } else {
18307            self.refresh_document_highlights(cx);
18308        }
18309
18310        Some(rename)
18311    }
18312
18313    pub fn pending_rename(&self) -> Option<&RenameState> {
18314        self.pending_rename.as_ref()
18315    }
18316
18317    fn format(
18318        &mut self,
18319        _: &Format,
18320        window: &mut Window,
18321        cx: &mut Context<Self>,
18322    ) -> Option<Task<Result<()>>> {
18323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18324
18325        let project = match &self.project {
18326            Some(project) => project.clone(),
18327            None => return None,
18328        };
18329
18330        Some(self.perform_format(
18331            project,
18332            FormatTrigger::Manual,
18333            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18334            window,
18335            cx,
18336        ))
18337    }
18338
18339    fn format_selections(
18340        &mut self,
18341        _: &FormatSelections,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) -> Option<Task<Result<()>>> {
18345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18346
18347        let project = match &self.project {
18348            Some(project) => project.clone(),
18349            None => return None,
18350        };
18351
18352        let ranges = self
18353            .selections
18354            .all_adjusted(&self.display_snapshot(cx))
18355            .into_iter()
18356            .map(|selection| selection.range())
18357            .collect_vec();
18358
18359        Some(self.perform_format(
18360            project,
18361            FormatTrigger::Manual,
18362            FormatTarget::Ranges(ranges),
18363            window,
18364            cx,
18365        ))
18366    }
18367
18368    fn perform_format(
18369        &mut self,
18370        project: Entity<Project>,
18371        trigger: FormatTrigger,
18372        target: FormatTarget,
18373        window: &mut Window,
18374        cx: &mut Context<Self>,
18375    ) -> Task<Result<()>> {
18376        let buffer = self.buffer.clone();
18377        let (buffers, target) = match target {
18378            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18379            FormatTarget::Ranges(selection_ranges) => {
18380                let multi_buffer = buffer.read(cx);
18381                let snapshot = multi_buffer.read(cx);
18382                let mut buffers = HashSet::default();
18383                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18384                    BTreeMap::new();
18385                for selection_range in selection_ranges {
18386                    for (buffer, buffer_range, _) in
18387                        snapshot.range_to_buffer_ranges(selection_range)
18388                    {
18389                        let buffer_id = buffer.remote_id();
18390                        let start = buffer.anchor_before(buffer_range.start);
18391                        let end = buffer.anchor_after(buffer_range.end);
18392                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18393                        buffer_id_to_ranges
18394                            .entry(buffer_id)
18395                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18396                            .or_insert_with(|| vec![start..end]);
18397                    }
18398                }
18399                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18400            }
18401        };
18402
18403        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18404        let selections_prev = transaction_id_prev
18405            .and_then(|transaction_id_prev| {
18406                // default to selections as they were after the last edit, if we have them,
18407                // instead of how they are now.
18408                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18409                // will take you back to where you made the last edit, instead of staying where you scrolled
18410                self.selection_history
18411                    .transaction(transaction_id_prev)
18412                    .map(|t| t.0.clone())
18413            })
18414            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18415
18416        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18417        let format = project.update(cx, |project, cx| {
18418            project.format(buffers, target, true, trigger, cx)
18419        });
18420
18421        cx.spawn_in(window, async move |editor, cx| {
18422            let transaction = futures::select_biased! {
18423                transaction = format.log_err().fuse() => transaction,
18424                () = timeout => {
18425                    log::warn!("timed out waiting for formatting");
18426                    None
18427                }
18428            };
18429
18430            buffer
18431                .update(cx, |buffer, cx| {
18432                    if let Some(transaction) = transaction
18433                        && !buffer.is_singleton()
18434                    {
18435                        buffer.push_transaction(&transaction.0, cx);
18436                    }
18437                    cx.notify();
18438                })
18439                .ok();
18440
18441            if let Some(transaction_id_now) =
18442                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18443            {
18444                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18445                if has_new_transaction {
18446                    _ = editor.update(cx, |editor, _| {
18447                        editor
18448                            .selection_history
18449                            .insert_transaction(transaction_id_now, selections_prev);
18450                    });
18451                }
18452            }
18453
18454            Ok(())
18455        })
18456    }
18457
18458    fn organize_imports(
18459        &mut self,
18460        _: &OrganizeImports,
18461        window: &mut Window,
18462        cx: &mut Context<Self>,
18463    ) -> Option<Task<Result<()>>> {
18464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18465        let project = match &self.project {
18466            Some(project) => project.clone(),
18467            None => return None,
18468        };
18469        Some(self.perform_code_action_kind(
18470            project,
18471            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18472            window,
18473            cx,
18474        ))
18475    }
18476
18477    fn perform_code_action_kind(
18478        &mut self,
18479        project: Entity<Project>,
18480        kind: CodeActionKind,
18481        window: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) -> Task<Result<()>> {
18484        let buffer = self.buffer.clone();
18485        let buffers = buffer.read(cx).all_buffers();
18486        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18487        let apply_action = project.update(cx, |project, cx| {
18488            project.apply_code_action_kind(buffers, kind, true, cx)
18489        });
18490        cx.spawn_in(window, async move |_, cx| {
18491            let transaction = futures::select_biased! {
18492                () = timeout => {
18493                    log::warn!("timed out waiting for executing code action");
18494                    None
18495                }
18496                transaction = apply_action.log_err().fuse() => transaction,
18497            };
18498            buffer
18499                .update(cx, |buffer, cx| {
18500                    // check if we need this
18501                    if let Some(transaction) = transaction
18502                        && !buffer.is_singleton()
18503                    {
18504                        buffer.push_transaction(&transaction.0, cx);
18505                    }
18506                    cx.notify();
18507                })
18508                .ok();
18509            Ok(())
18510        })
18511    }
18512
18513    pub fn restart_language_server(
18514        &mut self,
18515        _: &RestartLanguageServer,
18516        _: &mut Window,
18517        cx: &mut Context<Self>,
18518    ) {
18519        if let Some(project) = self.project.clone() {
18520            self.buffer.update(cx, |multi_buffer, cx| {
18521                project.update(cx, |project, cx| {
18522                    project.restart_language_servers_for_buffers(
18523                        multi_buffer.all_buffers().into_iter().collect(),
18524                        HashSet::default(),
18525                        cx,
18526                    );
18527                });
18528            })
18529        }
18530    }
18531
18532    pub fn stop_language_server(
18533        &mut self,
18534        _: &StopLanguageServer,
18535        _: &mut Window,
18536        cx: &mut Context<Self>,
18537    ) {
18538        if let Some(project) = self.project.clone() {
18539            self.buffer.update(cx, |multi_buffer, cx| {
18540                project.update(cx, |project, cx| {
18541                    project.stop_language_servers_for_buffers(
18542                        multi_buffer.all_buffers().into_iter().collect(),
18543                        HashSet::default(),
18544                        cx,
18545                    );
18546                });
18547            });
18548            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18549        }
18550    }
18551
18552    fn cancel_language_server_work(
18553        workspace: &mut Workspace,
18554        _: &actions::CancelLanguageServerWork,
18555        _: &mut Window,
18556        cx: &mut Context<Workspace>,
18557    ) {
18558        let project = workspace.project();
18559        let buffers = workspace
18560            .active_item(cx)
18561            .and_then(|item| item.act_as::<Editor>(cx))
18562            .map_or(HashSet::default(), |editor| {
18563                editor.read(cx).buffer.read(cx).all_buffers()
18564            });
18565        project.update(cx, |project, cx| {
18566            project.cancel_language_server_work_for_buffers(buffers, cx);
18567        });
18568    }
18569
18570    fn show_character_palette(
18571        &mut self,
18572        _: &ShowCharacterPalette,
18573        window: &mut Window,
18574        _: &mut Context<Self>,
18575    ) {
18576        window.show_character_palette();
18577    }
18578
18579    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18580        if !self.diagnostics_enabled() {
18581            return;
18582        }
18583
18584        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18585            let buffer = self.buffer.read(cx).snapshot(cx);
18586            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18587            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18588            let is_valid = buffer
18589                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18590                .any(|entry| {
18591                    entry.diagnostic.is_primary
18592                        && !entry.range.is_empty()
18593                        && entry.range.start == primary_range_start
18594                        && entry.diagnostic.message == active_diagnostics.active_message
18595                });
18596
18597            if !is_valid {
18598                self.dismiss_diagnostics(cx);
18599            }
18600        }
18601    }
18602
18603    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18604        match &self.active_diagnostics {
18605            ActiveDiagnostic::Group(group) => Some(group),
18606            _ => None,
18607        }
18608    }
18609
18610    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18611        if !self.diagnostics_enabled() {
18612            return;
18613        }
18614        self.dismiss_diagnostics(cx);
18615        self.active_diagnostics = ActiveDiagnostic::All;
18616    }
18617
18618    fn activate_diagnostics(
18619        &mut self,
18620        buffer_id: BufferId,
18621        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18622        window: &mut Window,
18623        cx: &mut Context<Self>,
18624    ) {
18625        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18626            return;
18627        }
18628        self.dismiss_diagnostics(cx);
18629        let snapshot = self.snapshot(window, cx);
18630        let buffer = self.buffer.read(cx).snapshot(cx);
18631        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18632            return;
18633        };
18634
18635        let diagnostic_group = buffer
18636            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18637            .collect::<Vec<_>>();
18638
18639        let language_registry = self
18640            .project()
18641            .map(|project| project.read(cx).languages().clone());
18642
18643        let blocks = renderer.render_group(
18644            diagnostic_group,
18645            buffer_id,
18646            snapshot,
18647            cx.weak_entity(),
18648            language_registry,
18649            cx,
18650        );
18651
18652        let blocks = self.display_map.update(cx, |display_map, cx| {
18653            display_map.insert_blocks(blocks, cx).into_iter().collect()
18654        });
18655        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18656            active_range: buffer.anchor_before(diagnostic.range.start)
18657                ..buffer.anchor_after(diagnostic.range.end),
18658            active_message: diagnostic.diagnostic.message.clone(),
18659            group_id: diagnostic.diagnostic.group_id,
18660            blocks,
18661        });
18662        cx.notify();
18663    }
18664
18665    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18666        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18667            return;
18668        };
18669
18670        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18671        if let ActiveDiagnostic::Group(group) = prev {
18672            self.display_map.update(cx, |display_map, cx| {
18673                display_map.remove_blocks(group.blocks, cx);
18674            });
18675            cx.notify();
18676        }
18677    }
18678
18679    /// Disable inline diagnostics rendering for this editor.
18680    pub fn disable_inline_diagnostics(&mut self) {
18681        self.inline_diagnostics_enabled = false;
18682        self.inline_diagnostics_update = Task::ready(());
18683        self.inline_diagnostics.clear();
18684    }
18685
18686    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18687        self.diagnostics_enabled = false;
18688        self.dismiss_diagnostics(cx);
18689        self.inline_diagnostics_update = Task::ready(());
18690        self.inline_diagnostics.clear();
18691    }
18692
18693    pub fn disable_word_completions(&mut self) {
18694        self.word_completions_enabled = false;
18695    }
18696
18697    pub fn diagnostics_enabled(&self) -> bool {
18698        self.diagnostics_enabled && self.mode.is_full()
18699    }
18700
18701    pub fn inline_diagnostics_enabled(&self) -> bool {
18702        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18703    }
18704
18705    pub fn show_inline_diagnostics(&self) -> bool {
18706        self.show_inline_diagnostics
18707    }
18708
18709    pub fn toggle_inline_diagnostics(
18710        &mut self,
18711        _: &ToggleInlineDiagnostics,
18712        window: &mut Window,
18713        cx: &mut Context<Editor>,
18714    ) {
18715        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18716        self.refresh_inline_diagnostics(false, window, cx);
18717    }
18718
18719    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18720        self.diagnostics_max_severity = severity;
18721        self.display_map.update(cx, |display_map, _| {
18722            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18723        });
18724    }
18725
18726    pub fn toggle_diagnostics(
18727        &mut self,
18728        _: &ToggleDiagnostics,
18729        window: &mut Window,
18730        cx: &mut Context<Editor>,
18731    ) {
18732        if !self.diagnostics_enabled() {
18733            return;
18734        }
18735
18736        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18737            EditorSettings::get_global(cx)
18738                .diagnostics_max_severity
18739                .filter(|severity| severity != &DiagnosticSeverity::Off)
18740                .unwrap_or(DiagnosticSeverity::Hint)
18741        } else {
18742            DiagnosticSeverity::Off
18743        };
18744        self.set_max_diagnostics_severity(new_severity, cx);
18745        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18746            self.active_diagnostics = ActiveDiagnostic::None;
18747            self.inline_diagnostics_update = Task::ready(());
18748            self.inline_diagnostics.clear();
18749        } else {
18750            self.refresh_inline_diagnostics(false, window, cx);
18751        }
18752
18753        cx.notify();
18754    }
18755
18756    pub fn toggle_minimap(
18757        &mut self,
18758        _: &ToggleMinimap,
18759        window: &mut Window,
18760        cx: &mut Context<Editor>,
18761    ) {
18762        if self.supports_minimap(cx) {
18763            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18764        }
18765    }
18766
18767    fn refresh_inline_diagnostics(
18768        &mut self,
18769        debounce: bool,
18770        window: &mut Window,
18771        cx: &mut Context<Self>,
18772    ) {
18773        let max_severity = ProjectSettings::get_global(cx)
18774            .diagnostics
18775            .inline
18776            .max_severity
18777            .unwrap_or(self.diagnostics_max_severity);
18778
18779        if !self.inline_diagnostics_enabled()
18780            || !self.diagnostics_enabled()
18781            || !self.show_inline_diagnostics
18782            || max_severity == DiagnosticSeverity::Off
18783        {
18784            self.inline_diagnostics_update = Task::ready(());
18785            self.inline_diagnostics.clear();
18786            return;
18787        }
18788
18789        let debounce_ms = ProjectSettings::get_global(cx)
18790            .diagnostics
18791            .inline
18792            .update_debounce_ms;
18793        let debounce = if debounce && debounce_ms > 0 {
18794            Some(Duration::from_millis(debounce_ms))
18795        } else {
18796            None
18797        };
18798        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18799            if let Some(debounce) = debounce {
18800                cx.background_executor().timer(debounce).await;
18801            }
18802            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18803                editor
18804                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18805                    .ok()
18806            }) else {
18807                return;
18808            };
18809
18810            let new_inline_diagnostics = cx
18811                .background_spawn(async move {
18812                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18813                    for diagnostic_entry in
18814                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18815                    {
18816                        let message = diagnostic_entry
18817                            .diagnostic
18818                            .message
18819                            .split_once('\n')
18820                            .map(|(line, _)| line)
18821                            .map(SharedString::new)
18822                            .unwrap_or_else(|| {
18823                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18824                            });
18825                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18826                        let (Ok(i) | Err(i)) = inline_diagnostics
18827                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18828                        inline_diagnostics.insert(
18829                            i,
18830                            (
18831                                start_anchor,
18832                                InlineDiagnostic {
18833                                    message,
18834                                    group_id: diagnostic_entry.diagnostic.group_id,
18835                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18836                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18837                                    severity: diagnostic_entry.diagnostic.severity,
18838                                },
18839                            ),
18840                        );
18841                    }
18842                    inline_diagnostics
18843                })
18844                .await;
18845
18846            editor
18847                .update(cx, |editor, cx| {
18848                    editor.inline_diagnostics = new_inline_diagnostics;
18849                    cx.notify();
18850                })
18851                .ok();
18852        });
18853    }
18854
18855    fn pull_diagnostics(
18856        &mut self,
18857        buffer_id: Option<BufferId>,
18858        window: &Window,
18859        cx: &mut Context<Self>,
18860    ) -> Option<()> {
18861        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18862            return None;
18863        }
18864        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18865            .diagnostics
18866            .lsp_pull_diagnostics;
18867        if !pull_diagnostics_settings.enabled {
18868            return None;
18869        }
18870        let project = self.project()?.downgrade();
18871
18872        let mut edited_buffer_ids = HashSet::default();
18873        let mut edited_worktree_ids = HashSet::default();
18874        let edited_buffers = match buffer_id {
18875            Some(buffer_id) => {
18876                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18877                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18878                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18879                edited_worktree_ids.insert(worktree_id);
18880                vec![buffer]
18881            }
18882            None => self
18883                .buffer()
18884                .read(cx)
18885                .all_buffers()
18886                .into_iter()
18887                .filter(|buffer| {
18888                    let buffer = buffer.read(cx);
18889                    match buffer.file().map(|f| f.worktree_id(cx)) {
18890                        Some(worktree_id) => {
18891                            edited_buffer_ids.insert(buffer.remote_id());
18892                            edited_worktree_ids.insert(worktree_id);
18893                            true
18894                        }
18895                        None => false,
18896                    }
18897                })
18898                .collect::<Vec<_>>(),
18899        };
18900
18901        if edited_buffers.is_empty() {
18902            self.pull_diagnostics_task = Task::ready(());
18903            self.pull_diagnostics_background_task = Task::ready(());
18904            return None;
18905        }
18906
18907        let mut already_used_buffers = HashSet::default();
18908        let related_open_buffers = self
18909            .workspace
18910            .as_ref()
18911            .and_then(|(workspace, _)| workspace.upgrade())
18912            .into_iter()
18913            .flat_map(|workspace| workspace.read(cx).panes())
18914            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18915            .filter(|editor| editor != &cx.entity())
18916            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18917            .filter(|buffer| {
18918                let buffer = buffer.read(cx);
18919                let buffer_id = buffer.remote_id();
18920                if already_used_buffers.insert(buffer_id) {
18921                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18922                        return !edited_buffer_ids.contains(&buffer_id)
18923                            && !edited_worktree_ids.contains(&worktree_id);
18924                    }
18925                }
18926                false
18927            })
18928            .collect::<Vec<_>>();
18929
18930        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18931        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18932            if buffers.is_empty() {
18933                return Task::ready(());
18934            }
18935            let project_weak = project.clone();
18936            cx.spawn_in(window, async move |_, cx| {
18937                cx.background_executor().timer(delay).await;
18938
18939                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18940                    buffers
18941                        .into_iter()
18942                        .filter_map(|buffer| {
18943                            project_weak
18944                                .update(cx, |project, cx| {
18945                                    project.lsp_store().update(cx, |lsp_store, cx| {
18946                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18947                                    })
18948                                })
18949                                .ok()
18950                        })
18951                        .collect::<FuturesUnordered<_>>()
18952                }) else {
18953                    return;
18954                };
18955
18956                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18957                    if let Err(e) = pull_task {
18958                        log::error!("Failed to update project diagnostics: {e:#}");
18959                    }
18960                }
18961            })
18962        };
18963
18964        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18965        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18966
18967        Some(())
18968    }
18969
18970    pub fn set_selections_from_remote(
18971        &mut self,
18972        selections: Vec<Selection<Anchor>>,
18973        pending_selection: Option<Selection<Anchor>>,
18974        window: &mut Window,
18975        cx: &mut Context<Self>,
18976    ) {
18977        let old_cursor_position = self.selections.newest_anchor().head();
18978        self.selections
18979            .change_with(&self.display_snapshot(cx), |s| {
18980                s.select_anchors(selections);
18981                if let Some(pending_selection) = pending_selection {
18982                    s.set_pending(pending_selection, SelectMode::Character);
18983                } else {
18984                    s.clear_pending();
18985                }
18986            });
18987        self.selections_did_change(
18988            false,
18989            &old_cursor_position,
18990            SelectionEffects::default(),
18991            window,
18992            cx,
18993        );
18994    }
18995
18996    pub fn transact(
18997        &mut self,
18998        window: &mut Window,
18999        cx: &mut Context<Self>,
19000        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19001    ) -> Option<TransactionId> {
19002        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19003            this.start_transaction_at(Instant::now(), window, cx);
19004            update(this, window, cx);
19005            this.end_transaction_at(Instant::now(), cx)
19006        })
19007    }
19008
19009    pub fn start_transaction_at(
19010        &mut self,
19011        now: Instant,
19012        window: &mut Window,
19013        cx: &mut Context<Self>,
19014    ) -> Option<TransactionId> {
19015        self.end_selection(window, cx);
19016        if let Some(tx_id) = self
19017            .buffer
19018            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19019        {
19020            self.selection_history
19021                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19022            cx.emit(EditorEvent::TransactionBegun {
19023                transaction_id: tx_id,
19024            });
19025            Some(tx_id)
19026        } else {
19027            None
19028        }
19029    }
19030
19031    pub fn end_transaction_at(
19032        &mut self,
19033        now: Instant,
19034        cx: &mut Context<Self>,
19035    ) -> Option<TransactionId> {
19036        if let Some(transaction_id) = self
19037            .buffer
19038            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19039        {
19040            if let Some((_, end_selections)) =
19041                self.selection_history.transaction_mut(transaction_id)
19042            {
19043                *end_selections = Some(self.selections.disjoint_anchors_arc());
19044            } else {
19045                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19046            }
19047
19048            cx.emit(EditorEvent::Edited { transaction_id });
19049            Some(transaction_id)
19050        } else {
19051            None
19052        }
19053    }
19054
19055    pub fn modify_transaction_selection_history(
19056        &mut self,
19057        transaction_id: TransactionId,
19058        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19059    ) -> bool {
19060        self.selection_history
19061            .transaction_mut(transaction_id)
19062            .map(modify)
19063            .is_some()
19064    }
19065
19066    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19067        if self.selection_mark_mode {
19068            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19069                s.move_with(|_, sel| {
19070                    sel.collapse_to(sel.head(), SelectionGoal::None);
19071                });
19072            })
19073        }
19074        self.selection_mark_mode = true;
19075        cx.notify();
19076    }
19077
19078    pub fn swap_selection_ends(
19079        &mut self,
19080        _: &actions::SwapSelectionEnds,
19081        window: &mut Window,
19082        cx: &mut Context<Self>,
19083    ) {
19084        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19085            s.move_with(|_, sel| {
19086                if sel.start != sel.end {
19087                    sel.reversed = !sel.reversed
19088                }
19089            });
19090        });
19091        self.request_autoscroll(Autoscroll::newest(), cx);
19092        cx.notify();
19093    }
19094
19095    pub fn toggle_focus(
19096        workspace: &mut Workspace,
19097        _: &actions::ToggleFocus,
19098        window: &mut Window,
19099        cx: &mut Context<Workspace>,
19100    ) {
19101        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19102            return;
19103        };
19104        workspace.activate_item(&item, true, true, window, cx);
19105    }
19106
19107    pub fn toggle_fold(
19108        &mut self,
19109        _: &actions::ToggleFold,
19110        window: &mut Window,
19111        cx: &mut Context<Self>,
19112    ) {
19113        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19114            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19115            let selection = self.selections.newest::<Point>(&display_map);
19116
19117            let range = if selection.is_empty() {
19118                let point = selection.head().to_display_point(&display_map);
19119                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19120                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19121                    .to_point(&display_map);
19122                start..end
19123            } else {
19124                selection.range()
19125            };
19126            if display_map.folds_in_range(range).next().is_some() {
19127                self.unfold_lines(&Default::default(), window, cx)
19128            } else {
19129                self.fold(&Default::default(), window, cx)
19130            }
19131        } else {
19132            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19133            let buffer_ids: HashSet<_> = self
19134                .selections
19135                .disjoint_anchor_ranges()
19136                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19137                .collect();
19138
19139            let should_unfold = buffer_ids
19140                .iter()
19141                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19142
19143            for buffer_id in buffer_ids {
19144                if should_unfold {
19145                    self.unfold_buffer(buffer_id, cx);
19146                } else {
19147                    self.fold_buffer(buffer_id, cx);
19148                }
19149            }
19150        }
19151    }
19152
19153    pub fn toggle_fold_recursive(
19154        &mut self,
19155        _: &actions::ToggleFoldRecursive,
19156        window: &mut Window,
19157        cx: &mut Context<Self>,
19158    ) {
19159        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19160
19161        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19162        let range = if selection.is_empty() {
19163            let point = selection.head().to_display_point(&display_map);
19164            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19165            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19166                .to_point(&display_map);
19167            start..end
19168        } else {
19169            selection.range()
19170        };
19171        if display_map.folds_in_range(range).next().is_some() {
19172            self.unfold_recursive(&Default::default(), window, cx)
19173        } else {
19174            self.fold_recursive(&Default::default(), window, cx)
19175        }
19176    }
19177
19178    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19179        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19180            let mut to_fold = Vec::new();
19181            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19182            let selections = self.selections.all_adjusted(&display_map);
19183
19184            for selection in selections {
19185                let range = selection.range().sorted();
19186                let buffer_start_row = range.start.row;
19187
19188                if range.start.row != range.end.row {
19189                    let mut found = false;
19190                    let mut row = range.start.row;
19191                    while row <= range.end.row {
19192                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19193                        {
19194                            found = true;
19195                            row = crease.range().end.row + 1;
19196                            to_fold.push(crease);
19197                        } else {
19198                            row += 1
19199                        }
19200                    }
19201                    if found {
19202                        continue;
19203                    }
19204                }
19205
19206                for row in (0..=range.start.row).rev() {
19207                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19208                        && crease.range().end.row >= buffer_start_row
19209                    {
19210                        to_fold.push(crease);
19211                        if row <= range.start.row {
19212                            break;
19213                        }
19214                    }
19215                }
19216            }
19217
19218            self.fold_creases(to_fold, true, window, cx);
19219        } else {
19220            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19221            let buffer_ids = self
19222                .selections
19223                .disjoint_anchor_ranges()
19224                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19225                .collect::<HashSet<_>>();
19226            for buffer_id in buffer_ids {
19227                self.fold_buffer(buffer_id, cx);
19228            }
19229        }
19230    }
19231
19232    pub fn toggle_fold_all(
19233        &mut self,
19234        _: &actions::ToggleFoldAll,
19235        window: &mut Window,
19236        cx: &mut Context<Self>,
19237    ) {
19238        if self.buffer.read(cx).is_singleton() {
19239            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19240            let has_folds = display_map
19241                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19242                .next()
19243                .is_some();
19244
19245            if has_folds {
19246                self.unfold_all(&actions::UnfoldAll, window, cx);
19247            } else {
19248                self.fold_all(&actions::FoldAll, window, cx);
19249            }
19250        } else {
19251            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19252            let should_unfold = buffer_ids
19253                .iter()
19254                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19255
19256            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19257                editor
19258                    .update_in(cx, |editor, _, cx| {
19259                        for buffer_id in buffer_ids {
19260                            if should_unfold {
19261                                editor.unfold_buffer(buffer_id, cx);
19262                            } else {
19263                                editor.fold_buffer(buffer_id, cx);
19264                            }
19265                        }
19266                    })
19267                    .ok();
19268            });
19269        }
19270    }
19271
19272    fn fold_at_level(
19273        &mut self,
19274        fold_at: &FoldAtLevel,
19275        window: &mut Window,
19276        cx: &mut Context<Self>,
19277    ) {
19278        if !self.buffer.read(cx).is_singleton() {
19279            return;
19280        }
19281
19282        let fold_at_level = fold_at.0;
19283        let snapshot = self.buffer.read(cx).snapshot(cx);
19284        let mut to_fold = Vec::new();
19285        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19286
19287        let row_ranges_to_keep: Vec<Range<u32>> = self
19288            .selections
19289            .all::<Point>(&self.display_snapshot(cx))
19290            .into_iter()
19291            .map(|sel| sel.start.row..sel.end.row)
19292            .collect();
19293
19294        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19295            while start_row < end_row {
19296                match self
19297                    .snapshot(window, cx)
19298                    .crease_for_buffer_row(MultiBufferRow(start_row))
19299                {
19300                    Some(crease) => {
19301                        let nested_start_row = crease.range().start.row + 1;
19302                        let nested_end_row = crease.range().end.row;
19303
19304                        if current_level < fold_at_level {
19305                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19306                        } else if current_level == fold_at_level {
19307                            // Fold iff there is no selection completely contained within the fold region
19308                            if !row_ranges_to_keep.iter().any(|selection| {
19309                                selection.end >= nested_start_row
19310                                    && selection.start <= nested_end_row
19311                            }) {
19312                                to_fold.push(crease);
19313                            }
19314                        }
19315
19316                        start_row = nested_end_row + 1;
19317                    }
19318                    None => start_row += 1,
19319                }
19320            }
19321        }
19322
19323        self.fold_creases(to_fold, true, window, cx);
19324    }
19325
19326    pub fn fold_at_level_1(
19327        &mut self,
19328        _: &actions::FoldAtLevel1,
19329        window: &mut Window,
19330        cx: &mut Context<Self>,
19331    ) {
19332        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19333    }
19334
19335    pub fn fold_at_level_2(
19336        &mut self,
19337        _: &actions::FoldAtLevel2,
19338        window: &mut Window,
19339        cx: &mut Context<Self>,
19340    ) {
19341        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19342    }
19343
19344    pub fn fold_at_level_3(
19345        &mut self,
19346        _: &actions::FoldAtLevel3,
19347        window: &mut Window,
19348        cx: &mut Context<Self>,
19349    ) {
19350        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19351    }
19352
19353    pub fn fold_at_level_4(
19354        &mut self,
19355        _: &actions::FoldAtLevel4,
19356        window: &mut Window,
19357        cx: &mut Context<Self>,
19358    ) {
19359        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19360    }
19361
19362    pub fn fold_at_level_5(
19363        &mut self,
19364        _: &actions::FoldAtLevel5,
19365        window: &mut Window,
19366        cx: &mut Context<Self>,
19367    ) {
19368        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19369    }
19370
19371    pub fn fold_at_level_6(
19372        &mut self,
19373        _: &actions::FoldAtLevel6,
19374        window: &mut Window,
19375        cx: &mut Context<Self>,
19376    ) {
19377        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19378    }
19379
19380    pub fn fold_at_level_7(
19381        &mut self,
19382        _: &actions::FoldAtLevel7,
19383        window: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) {
19386        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19387    }
19388
19389    pub fn fold_at_level_8(
19390        &mut self,
19391        _: &actions::FoldAtLevel8,
19392        window: &mut Window,
19393        cx: &mut Context<Self>,
19394    ) {
19395        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19396    }
19397
19398    pub fn fold_at_level_9(
19399        &mut self,
19400        _: &actions::FoldAtLevel9,
19401        window: &mut Window,
19402        cx: &mut Context<Self>,
19403    ) {
19404        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19405    }
19406
19407    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19408        if self.buffer.read(cx).is_singleton() {
19409            let mut fold_ranges = Vec::new();
19410            let snapshot = self.buffer.read(cx).snapshot(cx);
19411
19412            for row in 0..snapshot.max_row().0 {
19413                if let Some(foldable_range) = self
19414                    .snapshot(window, cx)
19415                    .crease_for_buffer_row(MultiBufferRow(row))
19416                {
19417                    fold_ranges.push(foldable_range);
19418                }
19419            }
19420
19421            self.fold_creases(fold_ranges, true, window, cx);
19422        } else {
19423            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19424                editor
19425                    .update_in(cx, |editor, _, cx| {
19426                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19427                            editor.fold_buffer(buffer_id, cx);
19428                        }
19429                    })
19430                    .ok();
19431            });
19432        }
19433    }
19434
19435    pub fn fold_function_bodies(
19436        &mut self,
19437        _: &actions::FoldFunctionBodies,
19438        window: &mut Window,
19439        cx: &mut Context<Self>,
19440    ) {
19441        let snapshot = self.buffer.read(cx).snapshot(cx);
19442
19443        let ranges = snapshot
19444            .text_object_ranges(
19445                MultiBufferOffset(0)..snapshot.len(),
19446                TreeSitterOptions::default(),
19447            )
19448            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19449            .collect::<Vec<_>>();
19450
19451        let creases = ranges
19452            .into_iter()
19453            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19454            .collect();
19455
19456        self.fold_creases(creases, true, window, cx);
19457    }
19458
19459    pub fn fold_recursive(
19460        &mut self,
19461        _: &actions::FoldRecursive,
19462        window: &mut Window,
19463        cx: &mut Context<Self>,
19464    ) {
19465        let mut to_fold = Vec::new();
19466        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19467        let selections = self.selections.all_adjusted(&display_map);
19468
19469        for selection in selections {
19470            let range = selection.range().sorted();
19471            let buffer_start_row = range.start.row;
19472
19473            if range.start.row != range.end.row {
19474                let mut found = false;
19475                for row in range.start.row..=range.end.row {
19476                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19477                        found = true;
19478                        to_fold.push(crease);
19479                    }
19480                }
19481                if found {
19482                    continue;
19483                }
19484            }
19485
19486            for row in (0..=range.start.row).rev() {
19487                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19488                    if crease.range().end.row >= buffer_start_row {
19489                        to_fold.push(crease);
19490                    } else {
19491                        break;
19492                    }
19493                }
19494            }
19495        }
19496
19497        self.fold_creases(to_fold, true, window, cx);
19498    }
19499
19500    pub fn fold_at(
19501        &mut self,
19502        buffer_row: MultiBufferRow,
19503        window: &mut Window,
19504        cx: &mut Context<Self>,
19505    ) {
19506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19507
19508        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19509            let autoscroll = self
19510                .selections
19511                .all::<Point>(&display_map)
19512                .iter()
19513                .any(|selection| crease.range().overlaps(&selection.range()));
19514
19515            self.fold_creases(vec![crease], autoscroll, window, cx);
19516        }
19517    }
19518
19519    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19520        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19521            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19522            let buffer = display_map.buffer_snapshot();
19523            let selections = self.selections.all::<Point>(&display_map);
19524            let ranges = selections
19525                .iter()
19526                .map(|s| {
19527                    let range = s.display_range(&display_map).sorted();
19528                    let mut start = range.start.to_point(&display_map);
19529                    let mut end = range.end.to_point(&display_map);
19530                    start.column = 0;
19531                    end.column = buffer.line_len(MultiBufferRow(end.row));
19532                    start..end
19533                })
19534                .collect::<Vec<_>>();
19535
19536            self.unfold_ranges(&ranges, true, true, cx);
19537        } else {
19538            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19539            let buffer_ids = self
19540                .selections
19541                .disjoint_anchor_ranges()
19542                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19543                .collect::<HashSet<_>>();
19544            for buffer_id in buffer_ids {
19545                self.unfold_buffer(buffer_id, cx);
19546            }
19547        }
19548    }
19549
19550    pub fn unfold_recursive(
19551        &mut self,
19552        _: &UnfoldRecursive,
19553        _window: &mut Window,
19554        cx: &mut Context<Self>,
19555    ) {
19556        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19557        let selections = self.selections.all::<Point>(&display_map);
19558        let ranges = selections
19559            .iter()
19560            .map(|s| {
19561                let mut range = s.display_range(&display_map).sorted();
19562                *range.start.column_mut() = 0;
19563                *range.end.column_mut() = display_map.line_len(range.end.row());
19564                let start = range.start.to_point(&display_map);
19565                let end = range.end.to_point(&display_map);
19566                start..end
19567            })
19568            .collect::<Vec<_>>();
19569
19570        self.unfold_ranges(&ranges, true, true, cx);
19571    }
19572
19573    pub fn unfold_at(
19574        &mut self,
19575        buffer_row: MultiBufferRow,
19576        _window: &mut Window,
19577        cx: &mut Context<Self>,
19578    ) {
19579        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19580
19581        let intersection_range = Point::new(buffer_row.0, 0)
19582            ..Point::new(
19583                buffer_row.0,
19584                display_map.buffer_snapshot().line_len(buffer_row),
19585            );
19586
19587        let autoscroll = self
19588            .selections
19589            .all::<Point>(&display_map)
19590            .iter()
19591            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19592
19593        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19594    }
19595
19596    pub fn unfold_all(
19597        &mut self,
19598        _: &actions::UnfoldAll,
19599        _window: &mut Window,
19600        cx: &mut Context<Self>,
19601    ) {
19602        if self.buffer.read(cx).is_singleton() {
19603            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19604            self.unfold_ranges(
19605                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19606                true,
19607                true,
19608                cx,
19609            );
19610        } else {
19611            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19612                editor
19613                    .update(cx, |editor, cx| {
19614                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19615                            editor.unfold_buffer(buffer_id, cx);
19616                        }
19617                    })
19618                    .ok();
19619            });
19620        }
19621    }
19622
19623    pub fn fold_selected_ranges(
19624        &mut self,
19625        _: &FoldSelectedRanges,
19626        window: &mut Window,
19627        cx: &mut Context<Self>,
19628    ) {
19629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19630        let selections = self.selections.all_adjusted(&display_map);
19631        let ranges = selections
19632            .into_iter()
19633            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19634            .collect::<Vec<_>>();
19635        self.fold_creases(ranges, true, window, cx);
19636    }
19637
19638    pub fn fold_ranges<T: ToOffset + Clone>(
19639        &mut self,
19640        ranges: Vec<Range<T>>,
19641        auto_scroll: bool,
19642        window: &mut Window,
19643        cx: &mut Context<Self>,
19644    ) {
19645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19646        let ranges = ranges
19647            .into_iter()
19648            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19649            .collect::<Vec<_>>();
19650        self.fold_creases(ranges, auto_scroll, window, cx);
19651    }
19652
19653    pub fn fold_creases<T: ToOffset + Clone>(
19654        &mut self,
19655        creases: Vec<Crease<T>>,
19656        auto_scroll: bool,
19657        _window: &mut Window,
19658        cx: &mut Context<Self>,
19659    ) {
19660        if creases.is_empty() {
19661            return;
19662        }
19663
19664        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19665
19666        if auto_scroll {
19667            self.request_autoscroll(Autoscroll::fit(), cx);
19668        }
19669
19670        cx.notify();
19671
19672        self.scrollbar_marker_state.dirty = true;
19673        self.folds_did_change(cx);
19674    }
19675
19676    /// Removes any folds whose ranges intersect any of the given ranges.
19677    pub fn unfold_ranges<T: ToOffset + Clone>(
19678        &mut self,
19679        ranges: &[Range<T>],
19680        inclusive: bool,
19681        auto_scroll: bool,
19682        cx: &mut Context<Self>,
19683    ) {
19684        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19685            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19686        });
19687        self.folds_did_change(cx);
19688    }
19689
19690    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19691        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19692            return;
19693        }
19694
19695        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19696        self.display_map.update(cx, |display_map, cx| {
19697            display_map.fold_buffers([buffer_id], cx)
19698        });
19699
19700        let snapshot = self.display_snapshot(cx);
19701        self.selections.change_with(&snapshot, |selections| {
19702            selections.remove_selections_from_buffer(buffer_id);
19703        });
19704
19705        cx.emit(EditorEvent::BufferFoldToggled {
19706            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19707            folded: true,
19708        });
19709        cx.notify();
19710    }
19711
19712    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19713        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19714            return;
19715        }
19716        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19717        self.display_map.update(cx, |display_map, cx| {
19718            display_map.unfold_buffers([buffer_id], cx);
19719        });
19720        cx.emit(EditorEvent::BufferFoldToggled {
19721            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19722            folded: false,
19723        });
19724        cx.notify();
19725    }
19726
19727    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19728        self.display_map.read(cx).is_buffer_folded(buffer)
19729    }
19730
19731    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19732        self.display_map.read(cx).folded_buffers()
19733    }
19734
19735    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19736        self.display_map.update(cx, |display_map, cx| {
19737            display_map.disable_header_for_buffer(buffer_id, cx);
19738        });
19739        cx.notify();
19740    }
19741
19742    /// Removes any folds with the given ranges.
19743    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19744        &mut self,
19745        ranges: &[Range<T>],
19746        type_id: TypeId,
19747        auto_scroll: bool,
19748        cx: &mut Context<Self>,
19749    ) {
19750        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19751            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19752        });
19753        self.folds_did_change(cx);
19754    }
19755
19756    fn remove_folds_with<T: ToOffset + Clone>(
19757        &mut self,
19758        ranges: &[Range<T>],
19759        auto_scroll: bool,
19760        cx: &mut Context<Self>,
19761        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19762    ) {
19763        if ranges.is_empty() {
19764            return;
19765        }
19766
19767        let mut buffers_affected = HashSet::default();
19768        let multi_buffer = self.buffer().read(cx);
19769        for range in ranges {
19770            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19771                buffers_affected.insert(buffer.read(cx).remote_id());
19772            };
19773        }
19774
19775        self.display_map.update(cx, update);
19776
19777        if auto_scroll {
19778            self.request_autoscroll(Autoscroll::fit(), cx);
19779        }
19780
19781        cx.notify();
19782        self.scrollbar_marker_state.dirty = true;
19783        self.active_indent_guides_state.dirty = true;
19784    }
19785
19786    pub fn update_renderer_widths(
19787        &mut self,
19788        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19789        cx: &mut Context<Self>,
19790    ) -> bool {
19791        self.display_map
19792            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19793    }
19794
19795    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19796        self.display_map.read(cx).fold_placeholder.clone()
19797    }
19798
19799    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19800        self.use_base_text_line_numbers = show;
19801    }
19802
19803    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19804        self.buffer.update(cx, |buffer, cx| {
19805            buffer.set_all_diff_hunks_expanded(cx);
19806        });
19807    }
19808
19809    pub fn expand_all_diff_hunks(
19810        &mut self,
19811        _: &ExpandAllDiffHunks,
19812        _window: &mut Window,
19813        cx: &mut Context<Self>,
19814    ) {
19815        self.buffer.update(cx, |buffer, cx| {
19816            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19817        });
19818    }
19819
19820    pub fn collapse_all_diff_hunks(
19821        &mut self,
19822        _: &CollapseAllDiffHunks,
19823        _window: &mut Window,
19824        cx: &mut Context<Self>,
19825    ) {
19826        self.buffer.update(cx, |buffer, cx| {
19827            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19828        });
19829    }
19830
19831    pub fn toggle_selected_diff_hunks(
19832        &mut self,
19833        _: &ToggleSelectedDiffHunks,
19834        _window: &mut Window,
19835        cx: &mut Context<Self>,
19836    ) {
19837        let ranges: Vec<_> = self
19838            .selections
19839            .disjoint_anchors()
19840            .iter()
19841            .map(|s| s.range())
19842            .collect();
19843        self.toggle_diff_hunks_in_ranges(ranges, cx);
19844    }
19845
19846    pub fn diff_hunks_in_ranges<'a>(
19847        &'a self,
19848        ranges: &'a [Range<Anchor>],
19849        buffer: &'a MultiBufferSnapshot,
19850    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19851        ranges.iter().flat_map(move |range| {
19852            let end_excerpt_id = range.end.excerpt_id;
19853            let range = range.to_point(buffer);
19854            let mut peek_end = range.end;
19855            if range.end.row < buffer.max_row().0 {
19856                peek_end = Point::new(range.end.row + 1, 0);
19857            }
19858            buffer
19859                .diff_hunks_in_range(range.start..peek_end)
19860                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19861        })
19862    }
19863
19864    pub fn has_stageable_diff_hunks_in_ranges(
19865        &self,
19866        ranges: &[Range<Anchor>],
19867        snapshot: &MultiBufferSnapshot,
19868    ) -> bool {
19869        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19870        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19871    }
19872
19873    pub fn toggle_staged_selected_diff_hunks(
19874        &mut self,
19875        _: &::git::ToggleStaged,
19876        _: &mut Window,
19877        cx: &mut Context<Self>,
19878    ) {
19879        let snapshot = self.buffer.read(cx).snapshot(cx);
19880        let ranges: Vec<_> = self
19881            .selections
19882            .disjoint_anchors()
19883            .iter()
19884            .map(|s| s.range())
19885            .collect();
19886        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19887        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19888    }
19889
19890    pub fn set_render_diff_hunk_controls(
19891        &mut self,
19892        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19893        cx: &mut Context<Self>,
19894    ) {
19895        self.render_diff_hunk_controls = render_diff_hunk_controls;
19896        cx.notify();
19897    }
19898
19899    pub fn stage_and_next(
19900        &mut self,
19901        _: &::git::StageAndNext,
19902        window: &mut Window,
19903        cx: &mut Context<Self>,
19904    ) {
19905        self.do_stage_or_unstage_and_next(true, window, cx);
19906    }
19907
19908    pub fn unstage_and_next(
19909        &mut self,
19910        _: &::git::UnstageAndNext,
19911        window: &mut Window,
19912        cx: &mut Context<Self>,
19913    ) {
19914        self.do_stage_or_unstage_and_next(false, window, cx);
19915    }
19916
19917    pub fn stage_or_unstage_diff_hunks(
19918        &mut self,
19919        stage: bool,
19920        ranges: Vec<Range<Anchor>>,
19921        cx: &mut Context<Self>,
19922    ) {
19923        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19924        cx.spawn(async move |this, cx| {
19925            task.await?;
19926            this.update(cx, |this, cx| {
19927                let snapshot = this.buffer.read(cx).snapshot(cx);
19928                let chunk_by = this
19929                    .diff_hunks_in_ranges(&ranges, &snapshot)
19930                    .chunk_by(|hunk| hunk.buffer_id);
19931                for (buffer_id, hunks) in &chunk_by {
19932                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19933                }
19934            })
19935        })
19936        .detach_and_log_err(cx);
19937    }
19938
19939    fn save_buffers_for_ranges_if_needed(
19940        &mut self,
19941        ranges: &[Range<Anchor>],
19942        cx: &mut Context<Editor>,
19943    ) -> Task<Result<()>> {
19944        let multibuffer = self.buffer.read(cx);
19945        let snapshot = multibuffer.read(cx);
19946        let buffer_ids: HashSet<_> = ranges
19947            .iter()
19948            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19949            .collect();
19950        drop(snapshot);
19951
19952        let mut buffers = HashSet::default();
19953        for buffer_id in buffer_ids {
19954            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19955                let buffer = buffer_entity.read(cx);
19956                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19957                {
19958                    buffers.insert(buffer_entity);
19959                }
19960            }
19961        }
19962
19963        if let Some(project) = &self.project {
19964            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19965        } else {
19966            Task::ready(Ok(()))
19967        }
19968    }
19969
19970    fn do_stage_or_unstage_and_next(
19971        &mut self,
19972        stage: bool,
19973        window: &mut Window,
19974        cx: &mut Context<Self>,
19975    ) {
19976        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19977
19978        if ranges.iter().any(|range| range.start != range.end) {
19979            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19980            return;
19981        }
19982
19983        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19984        let snapshot = self.snapshot(window, cx);
19985        let position = self
19986            .selections
19987            .newest::<Point>(&snapshot.display_snapshot)
19988            .head();
19989        let mut row = snapshot
19990            .buffer_snapshot()
19991            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19992            .find(|hunk| hunk.row_range.start.0 > position.row)
19993            .map(|hunk| hunk.row_range.start);
19994
19995        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19996        // Outside of the project diff editor, wrap around to the beginning.
19997        if !all_diff_hunks_expanded {
19998            row = row.or_else(|| {
19999                snapshot
20000                    .buffer_snapshot()
20001                    .diff_hunks_in_range(Point::zero()..position)
20002                    .find(|hunk| hunk.row_range.end.0 < position.row)
20003                    .map(|hunk| hunk.row_range.start)
20004            });
20005        }
20006
20007        if let Some(row) = row {
20008            let destination = Point::new(row.0, 0);
20009            let autoscroll = Autoscroll::center();
20010
20011            self.unfold_ranges(&[destination..destination], false, false, cx);
20012            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20013                s.select_ranges([destination..destination]);
20014            });
20015        }
20016    }
20017
20018    fn do_stage_or_unstage(
20019        &self,
20020        stage: bool,
20021        buffer_id: BufferId,
20022        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20023        cx: &mut App,
20024    ) -> Option<()> {
20025        let project = self.project()?;
20026        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20027        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20028        let buffer_snapshot = buffer.read(cx).snapshot();
20029        let file_exists = buffer_snapshot
20030            .file()
20031            .is_some_and(|file| file.disk_state().exists());
20032        diff.update(cx, |diff, cx| {
20033            diff.stage_or_unstage_hunks(
20034                stage,
20035                &hunks
20036                    .map(|hunk| buffer_diff::DiffHunk {
20037                        buffer_range: hunk.buffer_range,
20038                        // We don't need to pass in word diffs here because they're only used for rendering and
20039                        // this function changes internal state
20040                        base_word_diffs: Vec::default(),
20041                        buffer_word_diffs: Vec::default(),
20042                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20043                            ..hunk.diff_base_byte_range.end.0,
20044                        secondary_status: hunk.secondary_status,
20045                        range: Point::zero()..Point::zero(), // unused
20046                    })
20047                    .collect::<Vec<_>>(),
20048                &buffer_snapshot,
20049                file_exists,
20050                cx,
20051            )
20052        });
20053        None
20054    }
20055
20056    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20057        let ranges: Vec<_> = self
20058            .selections
20059            .disjoint_anchors()
20060            .iter()
20061            .map(|s| s.range())
20062            .collect();
20063        self.buffer
20064            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20065    }
20066
20067    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20068        self.buffer.update(cx, |buffer, cx| {
20069            let ranges = vec![Anchor::min()..Anchor::max()];
20070            if !buffer.all_diff_hunks_expanded()
20071                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20072            {
20073                buffer.collapse_diff_hunks(ranges, cx);
20074                true
20075            } else {
20076                false
20077            }
20078        })
20079    }
20080
20081    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20082        if self.buffer.read(cx).all_diff_hunks_expanded() {
20083            return true;
20084        }
20085        let ranges = vec![Anchor::min()..Anchor::max()];
20086        self.buffer
20087            .read(cx)
20088            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20089    }
20090
20091    fn toggle_diff_hunks_in_ranges(
20092        &mut self,
20093        ranges: Vec<Range<Anchor>>,
20094        cx: &mut Context<Editor>,
20095    ) {
20096        self.buffer.update(cx, |buffer, cx| {
20097            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20098            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20099        })
20100    }
20101
20102    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20103        self.buffer.update(cx, |buffer, cx| {
20104            let snapshot = buffer.snapshot(cx);
20105            let excerpt_id = range.end.excerpt_id;
20106            let point_range = range.to_point(&snapshot);
20107            let expand = !buffer.single_hunk_is_expanded(range, cx);
20108            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20109        })
20110    }
20111
20112    pub(crate) fn apply_all_diff_hunks(
20113        &mut self,
20114        _: &ApplyAllDiffHunks,
20115        window: &mut Window,
20116        cx: &mut Context<Self>,
20117    ) {
20118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20119
20120        let buffers = self.buffer.read(cx).all_buffers();
20121        for branch_buffer in buffers {
20122            branch_buffer.update(cx, |branch_buffer, cx| {
20123                branch_buffer.merge_into_base(Vec::new(), cx);
20124            });
20125        }
20126
20127        if let Some(project) = self.project.clone() {
20128            self.save(
20129                SaveOptions {
20130                    format: true,
20131                    autosave: false,
20132                },
20133                project,
20134                window,
20135                cx,
20136            )
20137            .detach_and_log_err(cx);
20138        }
20139    }
20140
20141    pub(crate) fn apply_selected_diff_hunks(
20142        &mut self,
20143        _: &ApplyDiffHunk,
20144        window: &mut Window,
20145        cx: &mut Context<Self>,
20146    ) {
20147        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20148        let snapshot = self.snapshot(window, cx);
20149        let hunks = snapshot.hunks_for_ranges(
20150            self.selections
20151                .all(&snapshot.display_snapshot)
20152                .into_iter()
20153                .map(|selection| selection.range()),
20154        );
20155        let mut ranges_by_buffer = HashMap::default();
20156        self.transact(window, cx, |editor, _window, cx| {
20157            for hunk in hunks {
20158                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20159                    ranges_by_buffer
20160                        .entry(buffer.clone())
20161                        .or_insert_with(Vec::new)
20162                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20163                }
20164            }
20165
20166            for (buffer, ranges) in ranges_by_buffer {
20167                buffer.update(cx, |buffer, cx| {
20168                    buffer.merge_into_base(ranges, cx);
20169                });
20170            }
20171        });
20172
20173        if let Some(project) = self.project.clone() {
20174            self.save(
20175                SaveOptions {
20176                    format: true,
20177                    autosave: false,
20178                },
20179                project,
20180                window,
20181                cx,
20182            )
20183            .detach_and_log_err(cx);
20184        }
20185    }
20186
20187    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20188        if hovered != self.gutter_hovered {
20189            self.gutter_hovered = hovered;
20190            cx.notify();
20191        }
20192    }
20193
20194    pub fn insert_blocks(
20195        &mut self,
20196        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20197        autoscroll: Option<Autoscroll>,
20198        cx: &mut Context<Self>,
20199    ) -> Vec<CustomBlockId> {
20200        let blocks = self
20201            .display_map
20202            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20203        if let Some(autoscroll) = autoscroll {
20204            self.request_autoscroll(autoscroll, cx);
20205        }
20206        cx.notify();
20207        blocks
20208    }
20209
20210    pub fn resize_blocks(
20211        &mut self,
20212        heights: HashMap<CustomBlockId, u32>,
20213        autoscroll: Option<Autoscroll>,
20214        cx: &mut Context<Self>,
20215    ) {
20216        self.display_map
20217            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20218        if let Some(autoscroll) = autoscroll {
20219            self.request_autoscroll(autoscroll, cx);
20220        }
20221        cx.notify();
20222    }
20223
20224    pub fn replace_blocks(
20225        &mut self,
20226        renderers: HashMap<CustomBlockId, RenderBlock>,
20227        autoscroll: Option<Autoscroll>,
20228        cx: &mut Context<Self>,
20229    ) {
20230        self.display_map
20231            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20232        if let Some(autoscroll) = autoscroll {
20233            self.request_autoscroll(autoscroll, cx);
20234        }
20235        cx.notify();
20236    }
20237
20238    pub fn remove_blocks(
20239        &mut self,
20240        block_ids: HashSet<CustomBlockId>,
20241        autoscroll: Option<Autoscroll>,
20242        cx: &mut Context<Self>,
20243    ) {
20244        self.display_map.update(cx, |display_map, cx| {
20245            display_map.remove_blocks(block_ids, cx)
20246        });
20247        if let Some(autoscroll) = autoscroll {
20248            self.request_autoscroll(autoscroll, cx);
20249        }
20250        cx.notify();
20251    }
20252
20253    pub fn row_for_block(
20254        &self,
20255        block_id: CustomBlockId,
20256        cx: &mut Context<Self>,
20257    ) -> Option<DisplayRow> {
20258        self.display_map
20259            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20260    }
20261
20262    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20263        self.focused_block = Some(focused_block);
20264    }
20265
20266    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20267        self.focused_block.take()
20268    }
20269
20270    pub fn insert_creases(
20271        &mut self,
20272        creases: impl IntoIterator<Item = Crease<Anchor>>,
20273        cx: &mut Context<Self>,
20274    ) -> Vec<CreaseId> {
20275        self.display_map
20276            .update(cx, |map, cx| map.insert_creases(creases, cx))
20277    }
20278
20279    pub fn remove_creases(
20280        &mut self,
20281        ids: impl IntoIterator<Item = CreaseId>,
20282        cx: &mut Context<Self>,
20283    ) -> Vec<(CreaseId, Range<Anchor>)> {
20284        self.display_map
20285            .update(cx, |map, cx| map.remove_creases(ids, cx))
20286    }
20287
20288    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20289        self.display_map
20290            .update(cx, |map, cx| map.snapshot(cx))
20291            .longest_row()
20292    }
20293
20294    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20295        self.display_map
20296            .update(cx, |map, cx| map.snapshot(cx))
20297            .max_point()
20298    }
20299
20300    pub fn text(&self, cx: &App) -> String {
20301        self.buffer.read(cx).read(cx).text()
20302    }
20303
20304    pub fn is_empty(&self, cx: &App) -> bool {
20305        self.buffer.read(cx).read(cx).is_empty()
20306    }
20307
20308    pub fn text_option(&self, cx: &App) -> Option<String> {
20309        let text = self.text(cx);
20310        let text = text.trim();
20311
20312        if text.is_empty() {
20313            return None;
20314        }
20315
20316        Some(text.to_string())
20317    }
20318
20319    pub fn set_text(
20320        &mut self,
20321        text: impl Into<Arc<str>>,
20322        window: &mut Window,
20323        cx: &mut Context<Self>,
20324    ) {
20325        self.transact(window, cx, |this, _, cx| {
20326            this.buffer
20327                .read(cx)
20328                .as_singleton()
20329                .expect("you can only call set_text on editors for singleton buffers")
20330                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20331        });
20332    }
20333
20334    pub fn display_text(&self, cx: &mut App) -> String {
20335        self.display_map
20336            .update(cx, |map, cx| map.snapshot(cx))
20337            .text()
20338    }
20339
20340    fn create_minimap(
20341        &self,
20342        minimap_settings: MinimapSettings,
20343        window: &mut Window,
20344        cx: &mut Context<Self>,
20345    ) -> Option<Entity<Self>> {
20346        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20347            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20348    }
20349
20350    fn initialize_new_minimap(
20351        &self,
20352        minimap_settings: MinimapSettings,
20353        window: &mut Window,
20354        cx: &mut Context<Self>,
20355    ) -> Entity<Self> {
20356        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20357
20358        let mut minimap = Editor::new_internal(
20359            EditorMode::Minimap {
20360                parent: cx.weak_entity(),
20361            },
20362            self.buffer.clone(),
20363            None,
20364            Some(self.display_map.clone()),
20365            window,
20366            cx,
20367        );
20368        minimap.scroll_manager.clone_state(&self.scroll_manager);
20369        minimap.set_text_style_refinement(TextStyleRefinement {
20370            font_size: Some(MINIMAP_FONT_SIZE),
20371            font_weight: Some(MINIMAP_FONT_WEIGHT),
20372            ..Default::default()
20373        });
20374        minimap.update_minimap_configuration(minimap_settings, cx);
20375        cx.new(|_| minimap)
20376    }
20377
20378    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20379        let current_line_highlight = minimap_settings
20380            .current_line_highlight
20381            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20382        self.set_current_line_highlight(Some(current_line_highlight));
20383    }
20384
20385    pub fn minimap(&self) -> Option<&Entity<Self>> {
20386        self.minimap
20387            .as_ref()
20388            .filter(|_| self.minimap_visibility.visible())
20389    }
20390
20391    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20392        let mut wrap_guides = smallvec![];
20393
20394        if self.show_wrap_guides == Some(false) {
20395            return wrap_guides;
20396        }
20397
20398        let settings = self.buffer.read(cx).language_settings(cx);
20399        if settings.show_wrap_guides {
20400            match self.soft_wrap_mode(cx) {
20401                SoftWrap::Column(soft_wrap) => {
20402                    wrap_guides.push((soft_wrap as usize, true));
20403                }
20404                SoftWrap::Bounded(soft_wrap) => {
20405                    wrap_guides.push((soft_wrap as usize, true));
20406                }
20407                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20408            }
20409            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20410        }
20411
20412        wrap_guides
20413    }
20414
20415    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20416        let settings = self.buffer.read(cx).language_settings(cx);
20417        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20418        match mode {
20419            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20420                SoftWrap::None
20421            }
20422            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20423            language_settings::SoftWrap::PreferredLineLength => {
20424                SoftWrap::Column(settings.preferred_line_length)
20425            }
20426            language_settings::SoftWrap::Bounded => {
20427                SoftWrap::Bounded(settings.preferred_line_length)
20428            }
20429        }
20430    }
20431
20432    pub fn set_soft_wrap_mode(
20433        &mut self,
20434        mode: language_settings::SoftWrap,
20435
20436        cx: &mut Context<Self>,
20437    ) {
20438        self.soft_wrap_mode_override = Some(mode);
20439        cx.notify();
20440    }
20441
20442    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20443        self.hard_wrap = hard_wrap;
20444        cx.notify();
20445    }
20446
20447    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20448        self.text_style_refinement = Some(style);
20449    }
20450
20451    /// called by the Element so we know what style we were most recently rendered with.
20452    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20453        // We intentionally do not inform the display map about the minimap style
20454        // so that wrapping is not recalculated and stays consistent for the editor
20455        // and its linked minimap.
20456        if !self.mode.is_minimap() {
20457            let font = style.text.font();
20458            let font_size = style.text.font_size.to_pixels(window.rem_size());
20459            let display_map = self
20460                .placeholder_display_map
20461                .as_ref()
20462                .filter(|_| self.is_empty(cx))
20463                .unwrap_or(&self.display_map);
20464
20465            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20466        }
20467        self.style = Some(style);
20468    }
20469
20470    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20471        if self.style.is_none() {
20472            self.style = Some(self.create_style(cx));
20473        }
20474        self.style.as_ref().unwrap()
20475    }
20476
20477    // Called by the element. This method is not designed to be called outside of the editor
20478    // element's layout code because it does not notify when rewrapping is computed synchronously.
20479    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20480        if self.is_empty(cx) {
20481            self.placeholder_display_map
20482                .as_ref()
20483                .map_or(false, |display_map| {
20484                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20485                })
20486        } else {
20487            self.display_map
20488                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20489        }
20490    }
20491
20492    pub fn set_soft_wrap(&mut self) {
20493        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20494    }
20495
20496    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20497        if self.soft_wrap_mode_override.is_some() {
20498            self.soft_wrap_mode_override.take();
20499        } else {
20500            let soft_wrap = match self.soft_wrap_mode(cx) {
20501                SoftWrap::GitDiff => return,
20502                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20503                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20504                    language_settings::SoftWrap::None
20505                }
20506            };
20507            self.soft_wrap_mode_override = Some(soft_wrap);
20508        }
20509        cx.notify();
20510    }
20511
20512    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20513        let Some(workspace) = self.workspace() else {
20514            return;
20515        };
20516        let fs = workspace.read(cx).app_state().fs.clone();
20517        let current_show = TabBarSettings::get_global(cx).show;
20518        update_settings_file(fs, cx, move |setting, _| {
20519            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20520        });
20521    }
20522
20523    pub fn toggle_indent_guides(
20524        &mut self,
20525        _: &ToggleIndentGuides,
20526        _: &mut Window,
20527        cx: &mut Context<Self>,
20528    ) {
20529        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20530            self.buffer
20531                .read(cx)
20532                .language_settings(cx)
20533                .indent_guides
20534                .enabled
20535        });
20536        self.show_indent_guides = Some(!currently_enabled);
20537        cx.notify();
20538    }
20539
20540    fn should_show_indent_guides(&self) -> Option<bool> {
20541        self.show_indent_guides
20542    }
20543
20544    pub fn disable_indent_guides_for_buffer(
20545        &mut self,
20546        buffer_id: BufferId,
20547        cx: &mut Context<Self>,
20548    ) {
20549        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20550        cx.notify();
20551    }
20552
20553    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20554        self.buffers_with_disabled_indent_guides
20555            .contains(&buffer_id)
20556    }
20557
20558    pub fn toggle_line_numbers(
20559        &mut self,
20560        _: &ToggleLineNumbers,
20561        _: &mut Window,
20562        cx: &mut Context<Self>,
20563    ) {
20564        let mut editor_settings = EditorSettings::get_global(cx).clone();
20565        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20566        EditorSettings::override_global(editor_settings, cx);
20567    }
20568
20569    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20570        if let Some(show_line_numbers) = self.show_line_numbers {
20571            return show_line_numbers;
20572        }
20573        EditorSettings::get_global(cx).gutter.line_numbers
20574    }
20575
20576    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20577        match (
20578            self.use_relative_line_numbers,
20579            EditorSettings::get_global(cx).relative_line_numbers,
20580        ) {
20581            (None, setting) => setting,
20582            (Some(false), _) => RelativeLineNumbers::Disabled,
20583            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20584            (Some(true), _) => RelativeLineNumbers::Enabled,
20585        }
20586    }
20587
20588    pub fn toggle_relative_line_numbers(
20589        &mut self,
20590        _: &ToggleRelativeLineNumbers,
20591        _: &mut Window,
20592        cx: &mut Context<Self>,
20593    ) {
20594        let is_relative = self.relative_line_numbers(cx);
20595        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20596    }
20597
20598    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20599        self.use_relative_line_numbers = is_relative;
20600        cx.notify();
20601    }
20602
20603    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20604        self.show_gutter = show_gutter;
20605        cx.notify();
20606    }
20607
20608    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20609        self.show_scrollbars = ScrollbarAxes {
20610            horizontal: show,
20611            vertical: show,
20612        };
20613        cx.notify();
20614    }
20615
20616    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20617        self.show_scrollbars.vertical = show;
20618        cx.notify();
20619    }
20620
20621    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20622        self.show_scrollbars.horizontal = show;
20623        cx.notify();
20624    }
20625
20626    pub fn set_minimap_visibility(
20627        &mut self,
20628        minimap_visibility: MinimapVisibility,
20629        window: &mut Window,
20630        cx: &mut Context<Self>,
20631    ) {
20632        if self.minimap_visibility != minimap_visibility {
20633            if minimap_visibility.visible() && self.minimap.is_none() {
20634                let minimap_settings = EditorSettings::get_global(cx).minimap;
20635                self.minimap =
20636                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20637            }
20638            self.minimap_visibility = minimap_visibility;
20639            cx.notify();
20640        }
20641    }
20642
20643    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20644        self.set_show_scrollbars(false, cx);
20645        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20646    }
20647
20648    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20649        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20650    }
20651
20652    /// Normally the text in full mode and auto height editors is padded on the
20653    /// left side by roughly half a character width for improved hit testing.
20654    ///
20655    /// Use this method to disable this for cases where this is not wanted (e.g.
20656    /// if you want to align the editor text with some other text above or below)
20657    /// or if you want to add this padding to single-line editors.
20658    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20659        self.offset_content = offset_content;
20660        cx.notify();
20661    }
20662
20663    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20664        self.show_line_numbers = Some(show_line_numbers);
20665        cx.notify();
20666    }
20667
20668    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20669        self.disable_expand_excerpt_buttons = true;
20670        cx.notify();
20671    }
20672
20673    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20674        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20675        cx.notify();
20676    }
20677
20678    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20679        self.show_code_actions = Some(show_code_actions);
20680        cx.notify();
20681    }
20682
20683    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20684        self.show_runnables = Some(show_runnables);
20685        cx.notify();
20686    }
20687
20688    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20689        self.show_breakpoints = Some(show_breakpoints);
20690        cx.notify();
20691    }
20692
20693    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20694        if self.display_map.read(cx).masked != masked {
20695            self.display_map.update(cx, |map, _| map.masked = masked);
20696        }
20697        cx.notify()
20698    }
20699
20700    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20701        self.show_wrap_guides = Some(show_wrap_guides);
20702        cx.notify();
20703    }
20704
20705    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20706        self.show_indent_guides = Some(show_indent_guides);
20707        cx.notify();
20708    }
20709
20710    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20711        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20712            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20713                && let Some(dir) = file.abs_path(cx).parent()
20714            {
20715                return Some(dir.to_owned());
20716            }
20717        }
20718
20719        None
20720    }
20721
20722    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20723        self.active_excerpt(cx)?
20724            .1
20725            .read(cx)
20726            .file()
20727            .and_then(|f| f.as_local())
20728    }
20729
20730    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20731        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20732            let buffer = buffer.read(cx);
20733            if let Some(project_path) = buffer.project_path(cx) {
20734                let project = self.project()?.read(cx);
20735                project.absolute_path(&project_path, cx)
20736            } else {
20737                buffer
20738                    .file()
20739                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20740            }
20741        })
20742    }
20743
20744    pub fn reveal_in_finder(
20745        &mut self,
20746        _: &RevealInFileManager,
20747        _window: &mut Window,
20748        cx: &mut Context<Self>,
20749    ) {
20750        if let Some(target) = self.target_file(cx) {
20751            cx.reveal_path(&target.abs_path(cx));
20752        }
20753    }
20754
20755    pub fn copy_path(
20756        &mut self,
20757        _: &zed_actions::workspace::CopyPath,
20758        _window: &mut Window,
20759        cx: &mut Context<Self>,
20760    ) {
20761        if let Some(path) = self.target_file_abs_path(cx)
20762            && let Some(path) = path.to_str()
20763        {
20764            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20765        } else {
20766            cx.propagate();
20767        }
20768    }
20769
20770    pub fn copy_relative_path(
20771        &mut self,
20772        _: &zed_actions::workspace::CopyRelativePath,
20773        _window: &mut Window,
20774        cx: &mut Context<Self>,
20775    ) {
20776        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20777            let project = self.project()?.read(cx);
20778            let path = buffer.read(cx).file()?.path();
20779            let path = path.display(project.path_style(cx));
20780            Some(path)
20781        }) {
20782            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20783        } else {
20784            cx.propagate();
20785        }
20786    }
20787
20788    /// Returns the project path for the editor's buffer, if any buffer is
20789    /// opened in the editor.
20790    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20791        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20792            buffer.read(cx).project_path(cx)
20793        } else {
20794            None
20795        }
20796    }
20797
20798    // Returns true if the editor handled a go-to-line request
20799    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20800        maybe!({
20801            let breakpoint_store = self.breakpoint_store.as_ref()?;
20802
20803            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20804            else {
20805                self.clear_row_highlights::<ActiveDebugLine>();
20806                return None;
20807            };
20808
20809            let position = active_stack_frame.position;
20810            let buffer_id = position.buffer_id?;
20811            let snapshot = self
20812                .project
20813                .as_ref()?
20814                .read(cx)
20815                .buffer_for_id(buffer_id, cx)?
20816                .read(cx)
20817                .snapshot();
20818
20819            let mut handled = false;
20820            for (id, ExcerptRange { context, .. }) in
20821                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20822            {
20823                if context.start.cmp(&position, &snapshot).is_ge()
20824                    || context.end.cmp(&position, &snapshot).is_lt()
20825                {
20826                    continue;
20827                }
20828                let snapshot = self.buffer.read(cx).snapshot(cx);
20829                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20830
20831                handled = true;
20832                self.clear_row_highlights::<ActiveDebugLine>();
20833
20834                self.go_to_line::<ActiveDebugLine>(
20835                    multibuffer_anchor,
20836                    Some(cx.theme().colors().editor_debugger_active_line_background),
20837                    window,
20838                    cx,
20839                );
20840
20841                cx.notify();
20842            }
20843
20844            handled.then_some(())
20845        })
20846        .is_some()
20847    }
20848
20849    pub fn copy_file_name_without_extension(
20850        &mut self,
20851        _: &CopyFileNameWithoutExtension,
20852        _: &mut Window,
20853        cx: &mut Context<Self>,
20854    ) {
20855        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20856            let file = buffer.read(cx).file()?;
20857            file.path().file_stem()
20858        }) {
20859            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20860        }
20861    }
20862
20863    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20864        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20865            let file = buffer.read(cx).file()?;
20866            Some(file.file_name(cx))
20867        }) {
20868            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20869        }
20870    }
20871
20872    pub fn toggle_git_blame(
20873        &mut self,
20874        _: &::git::Blame,
20875        window: &mut Window,
20876        cx: &mut Context<Self>,
20877    ) {
20878        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20879
20880        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20881            self.start_git_blame(true, window, cx);
20882        }
20883
20884        cx.notify();
20885    }
20886
20887    pub fn toggle_git_blame_inline(
20888        &mut self,
20889        _: &ToggleGitBlameInline,
20890        window: &mut Window,
20891        cx: &mut Context<Self>,
20892    ) {
20893        self.toggle_git_blame_inline_internal(true, window, cx);
20894        cx.notify();
20895    }
20896
20897    pub fn open_git_blame_commit(
20898        &mut self,
20899        _: &OpenGitBlameCommit,
20900        window: &mut Window,
20901        cx: &mut Context<Self>,
20902    ) {
20903        self.open_git_blame_commit_internal(window, cx);
20904    }
20905
20906    fn open_git_blame_commit_internal(
20907        &mut self,
20908        window: &mut Window,
20909        cx: &mut Context<Self>,
20910    ) -> Option<()> {
20911        let blame = self.blame.as_ref()?;
20912        let snapshot = self.snapshot(window, cx);
20913        let cursor = self
20914            .selections
20915            .newest::<Point>(&snapshot.display_snapshot)
20916            .head();
20917        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20918        let (_, blame_entry) = blame
20919            .update(cx, |blame, cx| {
20920                blame
20921                    .blame_for_rows(
20922                        &[RowInfo {
20923                            buffer_id: Some(buffer.remote_id()),
20924                            buffer_row: Some(point.row),
20925                            ..Default::default()
20926                        }],
20927                        cx,
20928                    )
20929                    .next()
20930            })
20931            .flatten()?;
20932        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20933        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20934        let workspace = self.workspace()?.downgrade();
20935        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20936        None
20937    }
20938
20939    pub fn git_blame_inline_enabled(&self) -> bool {
20940        self.git_blame_inline_enabled
20941    }
20942
20943    pub fn toggle_selection_menu(
20944        &mut self,
20945        _: &ToggleSelectionMenu,
20946        _: &mut Window,
20947        cx: &mut Context<Self>,
20948    ) {
20949        self.show_selection_menu = self
20950            .show_selection_menu
20951            .map(|show_selections_menu| !show_selections_menu)
20952            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20953
20954        cx.notify();
20955    }
20956
20957    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20958        self.show_selection_menu
20959            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20960    }
20961
20962    fn start_git_blame(
20963        &mut self,
20964        user_triggered: bool,
20965        window: &mut Window,
20966        cx: &mut Context<Self>,
20967    ) {
20968        if let Some(project) = self.project() {
20969            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20970                && buffer.read(cx).file().is_none()
20971            {
20972                return;
20973            }
20974
20975            let focused = self.focus_handle(cx).contains_focused(window, cx);
20976
20977            let project = project.clone();
20978            let blame = cx
20979                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20980            self.blame_subscription =
20981                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20982            self.blame = Some(blame);
20983        }
20984    }
20985
20986    fn toggle_git_blame_inline_internal(
20987        &mut self,
20988        user_triggered: bool,
20989        window: &mut Window,
20990        cx: &mut Context<Self>,
20991    ) {
20992        if self.git_blame_inline_enabled {
20993            self.git_blame_inline_enabled = false;
20994            self.show_git_blame_inline = false;
20995            self.show_git_blame_inline_delay_task.take();
20996        } else {
20997            self.git_blame_inline_enabled = true;
20998            self.start_git_blame_inline(user_triggered, window, cx);
20999        }
21000
21001        cx.notify();
21002    }
21003
21004    fn start_git_blame_inline(
21005        &mut self,
21006        user_triggered: bool,
21007        window: &mut Window,
21008        cx: &mut Context<Self>,
21009    ) {
21010        self.start_git_blame(user_triggered, window, cx);
21011
21012        if ProjectSettings::get_global(cx)
21013            .git
21014            .inline_blame_delay()
21015            .is_some()
21016        {
21017            self.start_inline_blame_timer(window, cx);
21018        } else {
21019            self.show_git_blame_inline = true
21020        }
21021    }
21022
21023    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21024        self.blame.as_ref()
21025    }
21026
21027    pub fn show_git_blame_gutter(&self) -> bool {
21028        self.show_git_blame_gutter
21029    }
21030
21031    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21032        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21033    }
21034
21035    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21036        self.show_git_blame_inline
21037            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21038            && !self.newest_selection_head_on_empty_line(cx)
21039            && self.has_blame_entries(cx)
21040    }
21041
21042    fn has_blame_entries(&self, cx: &App) -> bool {
21043        self.blame()
21044            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21045    }
21046
21047    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21048        let cursor_anchor = self.selections.newest_anchor().head();
21049
21050        let snapshot = self.buffer.read(cx).snapshot(cx);
21051        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21052
21053        snapshot.line_len(buffer_row) == 0
21054    }
21055
21056    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21057        let buffer_and_selection = maybe!({
21058            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21059            let selection_range = selection.range();
21060
21061            let multi_buffer = self.buffer().read(cx);
21062            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21063            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21064
21065            let (buffer, range, _) = if selection.reversed {
21066                buffer_ranges.first()
21067            } else {
21068                buffer_ranges.last()
21069            }?;
21070
21071            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21072            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21073
21074            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21075                let selection = start_row_in_buffer..end_row_in_buffer;
21076
21077                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21078            };
21079
21080            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21081
21082            Some((
21083                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21084                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
21085                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
21086            ))
21087        });
21088
21089        let Some((buffer, selection)) = buffer_and_selection else {
21090            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21091        };
21092
21093        let Some(project) = self.project() else {
21094            return Task::ready(Err(anyhow!("editor does not have project")));
21095        };
21096
21097        project.update(cx, |project, cx| {
21098            project.get_permalink_to_line(&buffer, selection, cx)
21099        })
21100    }
21101
21102    pub fn copy_permalink_to_line(
21103        &mut self,
21104        _: &CopyPermalinkToLine,
21105        window: &mut Window,
21106        cx: &mut Context<Self>,
21107    ) {
21108        let permalink_task = self.get_permalink_to_line(cx);
21109        let workspace = self.workspace();
21110
21111        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21112            Ok(permalink) => {
21113                cx.update(|_, cx| {
21114                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21115                })
21116                .ok();
21117            }
21118            Err(err) => {
21119                let message = format!("Failed to copy permalink: {err}");
21120
21121                anyhow::Result::<()>::Err(err).log_err();
21122
21123                if let Some(workspace) = workspace {
21124                    workspace
21125                        .update_in(cx, |workspace, _, cx| {
21126                            struct CopyPermalinkToLine;
21127
21128                            workspace.show_toast(
21129                                Toast::new(
21130                                    NotificationId::unique::<CopyPermalinkToLine>(),
21131                                    message,
21132                                ),
21133                                cx,
21134                            )
21135                        })
21136                        .ok();
21137                }
21138            }
21139        })
21140        .detach();
21141    }
21142
21143    pub fn copy_file_location(
21144        &mut self,
21145        _: &CopyFileLocation,
21146        _: &mut Window,
21147        cx: &mut Context<Self>,
21148    ) {
21149        let selection = self
21150            .selections
21151            .newest::<Point>(&self.display_snapshot(cx))
21152            .start
21153            .row
21154            + 1;
21155        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21156            let project = self.project()?.read(cx);
21157            let file = buffer.read(cx).file()?;
21158            let path = file.path().display(project.path_style(cx));
21159
21160            Some(format!("{path}:{selection}"))
21161        }) {
21162            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21163        }
21164    }
21165
21166    pub fn open_permalink_to_line(
21167        &mut self,
21168        _: &OpenPermalinkToLine,
21169        window: &mut Window,
21170        cx: &mut Context<Self>,
21171    ) {
21172        let permalink_task = self.get_permalink_to_line(cx);
21173        let workspace = self.workspace();
21174
21175        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21176            Ok(permalink) => {
21177                cx.update(|_, cx| {
21178                    cx.open_url(permalink.as_ref());
21179                })
21180                .ok();
21181            }
21182            Err(err) => {
21183                let message = format!("Failed to open permalink: {err}");
21184
21185                anyhow::Result::<()>::Err(err).log_err();
21186
21187                if let Some(workspace) = workspace {
21188                    workspace
21189                        .update(cx, |workspace, cx| {
21190                            struct OpenPermalinkToLine;
21191
21192                            workspace.show_toast(
21193                                Toast::new(
21194                                    NotificationId::unique::<OpenPermalinkToLine>(),
21195                                    message,
21196                                ),
21197                                cx,
21198                            )
21199                        })
21200                        .ok();
21201                }
21202            }
21203        })
21204        .detach();
21205    }
21206
21207    pub fn insert_uuid_v4(
21208        &mut self,
21209        _: &InsertUuidV4,
21210        window: &mut Window,
21211        cx: &mut Context<Self>,
21212    ) {
21213        self.insert_uuid(UuidVersion::V4, window, cx);
21214    }
21215
21216    pub fn insert_uuid_v7(
21217        &mut self,
21218        _: &InsertUuidV7,
21219        window: &mut Window,
21220        cx: &mut Context<Self>,
21221    ) {
21222        self.insert_uuid(UuidVersion::V7, window, cx);
21223    }
21224
21225    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21227        self.transact(window, cx, |this, window, cx| {
21228            let edits = this
21229                .selections
21230                .all::<Point>(&this.display_snapshot(cx))
21231                .into_iter()
21232                .map(|selection| {
21233                    let uuid = match version {
21234                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21235                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21236                    };
21237
21238                    (selection.range(), uuid.to_string())
21239                });
21240            this.edit(edits, cx);
21241            this.refresh_edit_prediction(true, false, window, cx);
21242        });
21243    }
21244
21245    pub fn open_selections_in_multibuffer(
21246        &mut self,
21247        _: &OpenSelectionsInMultibuffer,
21248        window: &mut Window,
21249        cx: &mut Context<Self>,
21250    ) {
21251        let multibuffer = self.buffer.read(cx);
21252
21253        let Some(buffer) = multibuffer.as_singleton() else {
21254            return;
21255        };
21256
21257        let Some(workspace) = self.workspace() else {
21258            return;
21259        };
21260
21261        let title = multibuffer.title(cx).to_string();
21262
21263        let locations = self
21264            .selections
21265            .all_anchors(&self.display_snapshot(cx))
21266            .iter()
21267            .map(|selection| {
21268                (
21269                    buffer.clone(),
21270                    (selection.start.text_anchor..selection.end.text_anchor)
21271                        .to_point(buffer.read(cx)),
21272                )
21273            })
21274            .into_group_map();
21275
21276        cx.spawn_in(window, async move |_, cx| {
21277            workspace.update_in(cx, |workspace, window, cx| {
21278                Self::open_locations_in_multibuffer(
21279                    workspace,
21280                    locations,
21281                    format!("Selections for '{title}'"),
21282                    false,
21283                    false,
21284                    MultibufferSelectionMode::All,
21285                    window,
21286                    cx,
21287                );
21288            })
21289        })
21290        .detach();
21291    }
21292
21293    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21294    /// last highlight added will be used.
21295    ///
21296    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21297    pub fn highlight_rows<T: 'static>(
21298        &mut self,
21299        range: Range<Anchor>,
21300        color: Hsla,
21301        options: RowHighlightOptions,
21302        cx: &mut Context<Self>,
21303    ) {
21304        let snapshot = self.buffer().read(cx).snapshot(cx);
21305        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21306        let ix = row_highlights.binary_search_by(|highlight| {
21307            Ordering::Equal
21308                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21309                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21310        });
21311
21312        if let Err(mut ix) = ix {
21313            let index = post_inc(&mut self.highlight_order);
21314
21315            // If this range intersects with the preceding highlight, then merge it with
21316            // the preceding highlight. Otherwise insert a new highlight.
21317            let mut merged = false;
21318            if ix > 0 {
21319                let prev_highlight = &mut row_highlights[ix - 1];
21320                if prev_highlight
21321                    .range
21322                    .end
21323                    .cmp(&range.start, &snapshot)
21324                    .is_ge()
21325                {
21326                    ix -= 1;
21327                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21328                        prev_highlight.range.end = range.end;
21329                    }
21330                    merged = true;
21331                    prev_highlight.index = index;
21332                    prev_highlight.color = color;
21333                    prev_highlight.options = options;
21334                }
21335            }
21336
21337            if !merged {
21338                row_highlights.insert(
21339                    ix,
21340                    RowHighlight {
21341                        range,
21342                        index,
21343                        color,
21344                        options,
21345                        type_id: TypeId::of::<T>(),
21346                    },
21347                );
21348            }
21349
21350            // If any of the following highlights intersect with this one, merge them.
21351            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21352                let highlight = &row_highlights[ix];
21353                if next_highlight
21354                    .range
21355                    .start
21356                    .cmp(&highlight.range.end, &snapshot)
21357                    .is_le()
21358                {
21359                    if next_highlight
21360                        .range
21361                        .end
21362                        .cmp(&highlight.range.end, &snapshot)
21363                        .is_gt()
21364                    {
21365                        row_highlights[ix].range.end = next_highlight.range.end;
21366                    }
21367                    row_highlights.remove(ix + 1);
21368                } else {
21369                    break;
21370                }
21371            }
21372        }
21373    }
21374
21375    /// Remove any highlighted row ranges of the given type that intersect the
21376    /// given ranges.
21377    pub fn remove_highlighted_rows<T: 'static>(
21378        &mut self,
21379        ranges_to_remove: Vec<Range<Anchor>>,
21380        cx: &mut Context<Self>,
21381    ) {
21382        let snapshot = self.buffer().read(cx).snapshot(cx);
21383        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21384        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21385        row_highlights.retain(|highlight| {
21386            while let Some(range_to_remove) = ranges_to_remove.peek() {
21387                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21388                    Ordering::Less | Ordering::Equal => {
21389                        ranges_to_remove.next();
21390                    }
21391                    Ordering::Greater => {
21392                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21393                            Ordering::Less | Ordering::Equal => {
21394                                return false;
21395                            }
21396                            Ordering::Greater => break,
21397                        }
21398                    }
21399                }
21400            }
21401
21402            true
21403        })
21404    }
21405
21406    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21407    pub fn clear_row_highlights<T: 'static>(&mut self) {
21408        self.highlighted_rows.remove(&TypeId::of::<T>());
21409    }
21410
21411    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21412    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21413        self.highlighted_rows
21414            .get(&TypeId::of::<T>())
21415            .map_or(&[] as &[_], |vec| vec.as_slice())
21416            .iter()
21417            .map(|highlight| (highlight.range.clone(), highlight.color))
21418    }
21419
21420    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21421    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21422    /// Allows to ignore certain kinds of highlights.
21423    pub fn highlighted_display_rows(
21424        &self,
21425        window: &mut Window,
21426        cx: &mut App,
21427    ) -> BTreeMap<DisplayRow, LineHighlight> {
21428        let snapshot = self.snapshot(window, cx);
21429        let mut used_highlight_orders = HashMap::default();
21430        self.highlighted_rows
21431            .iter()
21432            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21433            .fold(
21434                BTreeMap::<DisplayRow, LineHighlight>::new(),
21435                |mut unique_rows, highlight| {
21436                    let start = highlight.range.start.to_display_point(&snapshot);
21437                    let end = highlight.range.end.to_display_point(&snapshot);
21438                    let start_row = start.row().0;
21439                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21440                    {
21441                        end.row().0.saturating_sub(1)
21442                    } else {
21443                        end.row().0
21444                    };
21445                    for row in start_row..=end_row {
21446                        let used_index =
21447                            used_highlight_orders.entry(row).or_insert(highlight.index);
21448                        if highlight.index >= *used_index {
21449                            *used_index = highlight.index;
21450                            unique_rows.insert(
21451                                DisplayRow(row),
21452                                LineHighlight {
21453                                    include_gutter: highlight.options.include_gutter,
21454                                    border: None,
21455                                    background: highlight.color.into(),
21456                                    type_id: Some(highlight.type_id),
21457                                },
21458                            );
21459                        }
21460                    }
21461                    unique_rows
21462                },
21463            )
21464    }
21465
21466    pub fn highlighted_display_row_for_autoscroll(
21467        &self,
21468        snapshot: &DisplaySnapshot,
21469    ) -> Option<DisplayRow> {
21470        self.highlighted_rows
21471            .values()
21472            .flat_map(|highlighted_rows| highlighted_rows.iter())
21473            .filter_map(|highlight| {
21474                if highlight.options.autoscroll {
21475                    Some(highlight.range.start.to_display_point(snapshot).row())
21476                } else {
21477                    None
21478                }
21479            })
21480            .min()
21481    }
21482
21483    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21484        self.highlight_background::<SearchWithinRange>(
21485            ranges,
21486            |_, colors| colors.colors().editor_document_highlight_read_background,
21487            cx,
21488        )
21489    }
21490
21491    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21492        self.breadcrumb_header = Some(new_header);
21493    }
21494
21495    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21496        self.clear_background_highlights::<SearchWithinRange>(cx);
21497    }
21498
21499    pub fn highlight_background<T: 'static>(
21500        &mut self,
21501        ranges: &[Range<Anchor>],
21502        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21503        cx: &mut Context<Self>,
21504    ) {
21505        self.background_highlights.insert(
21506            HighlightKey::Type(TypeId::of::<T>()),
21507            (Arc::new(color_fetcher), Arc::from(ranges)),
21508        );
21509        self.scrollbar_marker_state.dirty = true;
21510        cx.notify();
21511    }
21512
21513    pub fn highlight_background_key<T: 'static>(
21514        &mut self,
21515        key: usize,
21516        ranges: &[Range<Anchor>],
21517        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21518        cx: &mut Context<Self>,
21519    ) {
21520        self.background_highlights.insert(
21521            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21522            (Arc::new(color_fetcher), Arc::from(ranges)),
21523        );
21524        self.scrollbar_marker_state.dirty = true;
21525        cx.notify();
21526    }
21527
21528    pub fn clear_background_highlights<T: 'static>(
21529        &mut self,
21530        cx: &mut Context<Self>,
21531    ) -> Option<BackgroundHighlight> {
21532        let text_highlights = self
21533            .background_highlights
21534            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21535        if !text_highlights.1.is_empty() {
21536            self.scrollbar_marker_state.dirty = true;
21537            cx.notify();
21538        }
21539        Some(text_highlights)
21540    }
21541
21542    pub fn highlight_gutter<T: 'static>(
21543        &mut self,
21544        ranges: impl Into<Vec<Range<Anchor>>>,
21545        color_fetcher: fn(&App) -> Hsla,
21546        cx: &mut Context<Self>,
21547    ) {
21548        self.gutter_highlights
21549            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21550        cx.notify();
21551    }
21552
21553    pub fn clear_gutter_highlights<T: 'static>(
21554        &mut self,
21555        cx: &mut Context<Self>,
21556    ) -> Option<GutterHighlight> {
21557        cx.notify();
21558        self.gutter_highlights.remove(&TypeId::of::<T>())
21559    }
21560
21561    pub fn insert_gutter_highlight<T: 'static>(
21562        &mut self,
21563        range: Range<Anchor>,
21564        color_fetcher: fn(&App) -> Hsla,
21565        cx: &mut Context<Self>,
21566    ) {
21567        let snapshot = self.buffer().read(cx).snapshot(cx);
21568        let mut highlights = self
21569            .gutter_highlights
21570            .remove(&TypeId::of::<T>())
21571            .map(|(_, highlights)| highlights)
21572            .unwrap_or_default();
21573        let ix = highlights.binary_search_by(|highlight| {
21574            Ordering::Equal
21575                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21576                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21577        });
21578        if let Err(ix) = ix {
21579            highlights.insert(ix, range);
21580        }
21581        self.gutter_highlights
21582            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21583    }
21584
21585    pub fn remove_gutter_highlights<T: 'static>(
21586        &mut self,
21587        ranges_to_remove: Vec<Range<Anchor>>,
21588        cx: &mut Context<Self>,
21589    ) {
21590        let snapshot = self.buffer().read(cx).snapshot(cx);
21591        let Some((color_fetcher, mut gutter_highlights)) =
21592            self.gutter_highlights.remove(&TypeId::of::<T>())
21593        else {
21594            return;
21595        };
21596        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21597        gutter_highlights.retain(|highlight| {
21598            while let Some(range_to_remove) = ranges_to_remove.peek() {
21599                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21600                    Ordering::Less | Ordering::Equal => {
21601                        ranges_to_remove.next();
21602                    }
21603                    Ordering::Greater => {
21604                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21605                            Ordering::Less | Ordering::Equal => {
21606                                return false;
21607                            }
21608                            Ordering::Greater => break,
21609                        }
21610                    }
21611                }
21612            }
21613
21614            true
21615        });
21616        self.gutter_highlights
21617            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21618    }
21619
21620    #[cfg(feature = "test-support")]
21621    pub fn all_text_highlights(
21622        &self,
21623        window: &mut Window,
21624        cx: &mut Context<Self>,
21625    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21626        let snapshot = self.snapshot(window, cx);
21627        self.display_map.update(cx, |display_map, _| {
21628            display_map
21629                .all_text_highlights()
21630                .map(|highlight| {
21631                    let (style, ranges) = highlight.as_ref();
21632                    (
21633                        *style,
21634                        ranges
21635                            .iter()
21636                            .map(|range| range.clone().to_display_points(&snapshot))
21637                            .collect(),
21638                    )
21639                })
21640                .collect()
21641        })
21642    }
21643
21644    #[cfg(feature = "test-support")]
21645    pub fn all_text_background_highlights(
21646        &self,
21647        window: &mut Window,
21648        cx: &mut Context<Self>,
21649    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21650        let snapshot = self.snapshot(window, cx);
21651        let buffer = &snapshot.buffer_snapshot();
21652        let start = buffer.anchor_before(MultiBufferOffset(0));
21653        let end = buffer.anchor_after(buffer.len());
21654        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21655    }
21656
21657    #[cfg(any(test, feature = "test-support"))]
21658    pub fn sorted_background_highlights_in_range(
21659        &self,
21660        search_range: Range<Anchor>,
21661        display_snapshot: &DisplaySnapshot,
21662        theme: &Theme,
21663    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21664        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21665        res.sort_by(|a, b| {
21666            a.0.start
21667                .cmp(&b.0.start)
21668                .then_with(|| a.0.end.cmp(&b.0.end))
21669                .then_with(|| a.1.cmp(&b.1))
21670        });
21671        res
21672    }
21673
21674    #[cfg(feature = "test-support")]
21675    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21676        let snapshot = self.buffer().read(cx).snapshot(cx);
21677
21678        let highlights = self
21679            .background_highlights
21680            .get(&HighlightKey::Type(TypeId::of::<
21681                items::BufferSearchHighlights,
21682            >()));
21683
21684        if let Some((_color, ranges)) = highlights {
21685            ranges
21686                .iter()
21687                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21688                .collect_vec()
21689        } else {
21690            vec![]
21691        }
21692    }
21693
21694    fn document_highlights_for_position<'a>(
21695        &'a self,
21696        position: Anchor,
21697        buffer: &'a MultiBufferSnapshot,
21698    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21699        let read_highlights = self
21700            .background_highlights
21701            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21702            .map(|h| &h.1);
21703        let write_highlights = self
21704            .background_highlights
21705            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21706            .map(|h| &h.1);
21707        let left_position = position.bias_left(buffer);
21708        let right_position = position.bias_right(buffer);
21709        read_highlights
21710            .into_iter()
21711            .chain(write_highlights)
21712            .flat_map(move |ranges| {
21713                let start_ix = match ranges.binary_search_by(|probe| {
21714                    let cmp = probe.end.cmp(&left_position, buffer);
21715                    if cmp.is_ge() {
21716                        Ordering::Greater
21717                    } else {
21718                        Ordering::Less
21719                    }
21720                }) {
21721                    Ok(i) | Err(i) => i,
21722                };
21723
21724                ranges[start_ix..]
21725                    .iter()
21726                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21727            })
21728    }
21729
21730    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21731        self.background_highlights
21732            .get(&HighlightKey::Type(TypeId::of::<T>()))
21733            .is_some_and(|(_, highlights)| !highlights.is_empty())
21734    }
21735
21736    /// Returns all background highlights for a given range.
21737    ///
21738    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21739    pub fn background_highlights_in_range(
21740        &self,
21741        search_range: Range<Anchor>,
21742        display_snapshot: &DisplaySnapshot,
21743        theme: &Theme,
21744    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21745        let mut results = Vec::new();
21746        for (color_fetcher, ranges) in self.background_highlights.values() {
21747            let start_ix = match ranges.binary_search_by(|probe| {
21748                let cmp = probe
21749                    .end
21750                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21751                if cmp.is_gt() {
21752                    Ordering::Greater
21753                } else {
21754                    Ordering::Less
21755                }
21756            }) {
21757                Ok(i) | Err(i) => i,
21758            };
21759            for (index, range) in ranges[start_ix..].iter().enumerate() {
21760                if range
21761                    .start
21762                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21763                    .is_ge()
21764                {
21765                    break;
21766                }
21767
21768                let color = color_fetcher(&(start_ix + index), theme);
21769                let start = range.start.to_display_point(display_snapshot);
21770                let end = range.end.to_display_point(display_snapshot);
21771                results.push((start..end, color))
21772            }
21773        }
21774        results
21775    }
21776
21777    pub fn gutter_highlights_in_range(
21778        &self,
21779        search_range: Range<Anchor>,
21780        display_snapshot: &DisplaySnapshot,
21781        cx: &App,
21782    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21783        let mut results = Vec::new();
21784        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21785            let color = color_fetcher(cx);
21786            let start_ix = match ranges.binary_search_by(|probe| {
21787                let cmp = probe
21788                    .end
21789                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21790                if cmp.is_gt() {
21791                    Ordering::Greater
21792                } else {
21793                    Ordering::Less
21794                }
21795            }) {
21796                Ok(i) | Err(i) => i,
21797            };
21798            for range in &ranges[start_ix..] {
21799                if range
21800                    .start
21801                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21802                    .is_ge()
21803                {
21804                    break;
21805                }
21806
21807                let start = range.start.to_display_point(display_snapshot);
21808                let end = range.end.to_display_point(display_snapshot);
21809                results.push((start..end, color))
21810            }
21811        }
21812        results
21813    }
21814
21815    /// Get the text ranges corresponding to the redaction query
21816    pub fn redacted_ranges(
21817        &self,
21818        search_range: Range<Anchor>,
21819        display_snapshot: &DisplaySnapshot,
21820        cx: &App,
21821    ) -> Vec<Range<DisplayPoint>> {
21822        display_snapshot
21823            .buffer_snapshot()
21824            .redacted_ranges(search_range, |file| {
21825                if let Some(file) = file {
21826                    file.is_private()
21827                        && EditorSettings::get(
21828                            Some(SettingsLocation {
21829                                worktree_id: file.worktree_id(cx),
21830                                path: file.path().as_ref(),
21831                            }),
21832                            cx,
21833                        )
21834                        .redact_private_values
21835                } else {
21836                    false
21837                }
21838            })
21839            .map(|range| {
21840                range.start.to_display_point(display_snapshot)
21841                    ..range.end.to_display_point(display_snapshot)
21842            })
21843            .collect()
21844    }
21845
21846    pub fn highlight_text_key<T: 'static>(
21847        &mut self,
21848        key: usize,
21849        ranges: Vec<Range<Anchor>>,
21850        style: HighlightStyle,
21851        merge: bool,
21852        cx: &mut Context<Self>,
21853    ) {
21854        self.display_map.update(cx, |map, cx| {
21855            map.highlight_text(
21856                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21857                ranges,
21858                style,
21859                merge,
21860                cx,
21861            );
21862        });
21863        cx.notify();
21864    }
21865
21866    pub fn highlight_text<T: 'static>(
21867        &mut self,
21868        ranges: Vec<Range<Anchor>>,
21869        style: HighlightStyle,
21870        cx: &mut Context<Self>,
21871    ) {
21872        self.display_map.update(cx, |map, cx| {
21873            map.highlight_text(
21874                HighlightKey::Type(TypeId::of::<T>()),
21875                ranges,
21876                style,
21877                false,
21878                cx,
21879            )
21880        });
21881        cx.notify();
21882    }
21883
21884    pub fn text_highlights<'a, T: 'static>(
21885        &'a self,
21886        cx: &'a App,
21887    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21888        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21889    }
21890
21891    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21892        let cleared = self
21893            .display_map
21894            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21895        if cleared {
21896            cx.notify();
21897        }
21898    }
21899
21900    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21901        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21902            && self.focus_handle.is_focused(window)
21903    }
21904
21905    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21906        self.show_cursor_when_unfocused = is_enabled;
21907        cx.notify();
21908    }
21909
21910    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21911        cx.notify();
21912    }
21913
21914    fn on_debug_session_event(
21915        &mut self,
21916        _session: Entity<Session>,
21917        event: &SessionEvent,
21918        cx: &mut Context<Self>,
21919    ) {
21920        if let SessionEvent::InvalidateInlineValue = event {
21921            self.refresh_inline_values(cx);
21922        }
21923    }
21924
21925    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21926        let Some(project) = self.project.clone() else {
21927            return;
21928        };
21929
21930        if !self.inline_value_cache.enabled {
21931            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21932            self.splice_inlays(&inlays, Vec::new(), cx);
21933            return;
21934        }
21935
21936        let current_execution_position = self
21937            .highlighted_rows
21938            .get(&TypeId::of::<ActiveDebugLine>())
21939            .and_then(|lines| lines.last().map(|line| line.range.end));
21940
21941        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21942            let inline_values = editor
21943                .update(cx, |editor, cx| {
21944                    let Some(current_execution_position) = current_execution_position else {
21945                        return Some(Task::ready(Ok(Vec::new())));
21946                    };
21947
21948                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21949                        let snapshot = buffer.snapshot(cx);
21950
21951                        let excerpt = snapshot.excerpt_containing(
21952                            current_execution_position..current_execution_position,
21953                        )?;
21954
21955                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21956                    })?;
21957
21958                    let range =
21959                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21960
21961                    project.inline_values(buffer, range, cx)
21962                })
21963                .ok()
21964                .flatten()?
21965                .await
21966                .context("refreshing debugger inlays")
21967                .log_err()?;
21968
21969            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21970
21971            for (buffer_id, inline_value) in inline_values
21972                .into_iter()
21973                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21974            {
21975                buffer_inline_values
21976                    .entry(buffer_id)
21977                    .or_default()
21978                    .push(inline_value);
21979            }
21980
21981            editor
21982                .update(cx, |editor, cx| {
21983                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21984                    let mut new_inlays = Vec::default();
21985
21986                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21987                        let buffer_id = buffer_snapshot.remote_id();
21988                        buffer_inline_values
21989                            .get(&buffer_id)
21990                            .into_iter()
21991                            .flatten()
21992                            .for_each(|hint| {
21993                                let inlay = Inlay::debugger(
21994                                    post_inc(&mut editor.next_inlay_id),
21995                                    Anchor::in_buffer(excerpt_id, hint.position),
21996                                    hint.text(),
21997                                );
21998                                if !inlay.text().chars().contains(&'\n') {
21999                                    new_inlays.push(inlay);
22000                                }
22001                            });
22002                    }
22003
22004                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22005                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22006
22007                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22008                })
22009                .ok()?;
22010            Some(())
22011        });
22012    }
22013
22014    fn on_buffer_event(
22015        &mut self,
22016        multibuffer: &Entity<MultiBuffer>,
22017        event: &multi_buffer::Event,
22018        window: &mut Window,
22019        cx: &mut Context<Self>,
22020    ) {
22021        match event {
22022            multi_buffer::Event::Edited { edited_buffer } => {
22023                self.scrollbar_marker_state.dirty = true;
22024                self.active_indent_guides_state.dirty = true;
22025                self.refresh_active_diagnostics(cx);
22026                self.refresh_code_actions(window, cx);
22027                self.refresh_single_line_folds(window, cx);
22028                self.refresh_matching_bracket_highlights(window, cx);
22029                if self.has_active_edit_prediction() {
22030                    self.update_visible_edit_prediction(window, cx);
22031                }
22032
22033                if let Some(buffer) = edited_buffer {
22034                    if buffer.read(cx).file().is_none() {
22035                        cx.emit(EditorEvent::TitleChanged);
22036                    }
22037
22038                    if self.project.is_some() {
22039                        let buffer_id = buffer.read(cx).remote_id();
22040                        self.register_buffer(buffer_id, cx);
22041                        self.update_lsp_data(Some(buffer_id), window, cx);
22042                        self.refresh_inlay_hints(
22043                            InlayHintRefreshReason::BufferEdited(buffer_id),
22044                            cx,
22045                        );
22046                    }
22047                }
22048
22049                cx.emit(EditorEvent::BufferEdited);
22050                cx.emit(SearchEvent::MatchesInvalidated);
22051
22052                let Some(project) = &self.project else { return };
22053                let (telemetry, is_via_ssh) = {
22054                    let project = project.read(cx);
22055                    let telemetry = project.client().telemetry().clone();
22056                    let is_via_ssh = project.is_via_remote_server();
22057                    (telemetry, is_via_ssh)
22058                };
22059                telemetry.log_edit_event("editor", is_via_ssh);
22060            }
22061            multi_buffer::Event::ExcerptsAdded {
22062                buffer,
22063                predecessor,
22064                excerpts,
22065            } => {
22066                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22067                let buffer_id = buffer.read(cx).remote_id();
22068                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22069                    && let Some(project) = &self.project
22070                {
22071                    update_uncommitted_diff_for_buffer(
22072                        cx.entity(),
22073                        project,
22074                        [buffer.clone()],
22075                        self.buffer.clone(),
22076                        cx,
22077                    )
22078                    .detach();
22079                }
22080                self.update_lsp_data(Some(buffer_id), window, cx);
22081                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22082                self.colorize_brackets(false, cx);
22083                cx.emit(EditorEvent::ExcerptsAdded {
22084                    buffer: buffer.clone(),
22085                    predecessor: *predecessor,
22086                    excerpts: excerpts.clone(),
22087                });
22088            }
22089            multi_buffer::Event::ExcerptsRemoved {
22090                ids,
22091                removed_buffer_ids,
22092            } => {
22093                if let Some(inlay_hints) = &mut self.inlay_hints {
22094                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22095                }
22096                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22097                for buffer_id in removed_buffer_ids {
22098                    self.registered_buffers.remove(buffer_id);
22099                }
22100                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22101                cx.emit(EditorEvent::ExcerptsRemoved {
22102                    ids: ids.clone(),
22103                    removed_buffer_ids: removed_buffer_ids.clone(),
22104                });
22105            }
22106            multi_buffer::Event::ExcerptsEdited {
22107                excerpt_ids,
22108                buffer_ids,
22109            } => {
22110                self.display_map.update(cx, |map, cx| {
22111                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22112                });
22113                cx.emit(EditorEvent::ExcerptsEdited {
22114                    ids: excerpt_ids.clone(),
22115                });
22116            }
22117            multi_buffer::Event::ExcerptsExpanded { ids } => {
22118                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22119                self.refresh_document_highlights(cx);
22120                for id in ids {
22121                    self.fetched_tree_sitter_chunks.remove(id);
22122                }
22123                self.colorize_brackets(false, cx);
22124                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22125            }
22126            multi_buffer::Event::Reparsed(buffer_id) => {
22127                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22128                self.refresh_selected_text_highlights(true, window, cx);
22129                self.colorize_brackets(true, cx);
22130                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22131
22132                cx.emit(EditorEvent::Reparsed(*buffer_id));
22133            }
22134            multi_buffer::Event::DiffHunksToggled => {
22135                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22136            }
22137            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22138                if !is_fresh_language {
22139                    self.registered_buffers.remove(&buffer_id);
22140                }
22141                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22142                cx.emit(EditorEvent::Reparsed(*buffer_id));
22143                cx.notify();
22144            }
22145            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22146            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22147            multi_buffer::Event::FileHandleChanged
22148            | multi_buffer::Event::Reloaded
22149            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22150            multi_buffer::Event::DiagnosticsUpdated => {
22151                self.update_diagnostics_state(window, cx);
22152            }
22153            _ => {}
22154        };
22155    }
22156
22157    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22158        if !self.diagnostics_enabled() {
22159            return;
22160        }
22161        self.refresh_active_diagnostics(cx);
22162        self.refresh_inline_diagnostics(true, window, cx);
22163        self.scrollbar_marker_state.dirty = true;
22164        cx.notify();
22165    }
22166
22167    pub fn start_temporary_diff_override(&mut self) {
22168        self.load_diff_task.take();
22169        self.temporary_diff_override = true;
22170    }
22171
22172    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22173        self.temporary_diff_override = false;
22174        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22175        self.buffer.update(cx, |buffer, cx| {
22176            buffer.set_all_diff_hunks_collapsed(cx);
22177        });
22178
22179        if let Some(project) = self.project.clone() {
22180            self.load_diff_task = Some(
22181                update_uncommitted_diff_for_buffer(
22182                    cx.entity(),
22183                    &project,
22184                    self.buffer.read(cx).all_buffers(),
22185                    self.buffer.clone(),
22186                    cx,
22187                )
22188                .shared(),
22189            );
22190        }
22191    }
22192
22193    fn on_display_map_changed(
22194        &mut self,
22195        _: Entity<DisplayMap>,
22196        _: &mut Window,
22197        cx: &mut Context<Self>,
22198    ) {
22199        cx.notify();
22200    }
22201
22202    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22203        if !self.mode.is_full() {
22204            return None;
22205        }
22206
22207        let theme_settings = theme::ThemeSettings::get_global(cx);
22208        let theme = cx.theme();
22209        let accent_colors = theme.accents().clone();
22210
22211        let accent_overrides = theme_settings
22212            .theme_overrides
22213            .get(theme.name.as_ref())
22214            .map(|theme_style| &theme_style.accents)
22215            .into_iter()
22216            .flatten()
22217            .chain(
22218                theme_settings
22219                    .experimental_theme_overrides
22220                    .as_ref()
22221                    .map(|overrides| &overrides.accents)
22222                    .into_iter()
22223                    .flatten(),
22224            )
22225            .flat_map(|accent| accent.0.clone())
22226            .collect();
22227
22228        Some(AccentData {
22229            colors: accent_colors,
22230            overrides: accent_overrides,
22231        })
22232    }
22233
22234    fn fetch_applicable_language_settings(
22235        &self,
22236        cx: &App,
22237    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22238        if !self.mode.is_full() {
22239            return HashMap::default();
22240        }
22241
22242        self.buffer().read(cx).all_buffers().into_iter().fold(
22243            HashMap::default(),
22244            |mut acc, buffer| {
22245                let buffer = buffer.read(cx);
22246                let language = buffer.language().map(|language| language.name());
22247                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22248                    let file = buffer.file();
22249                    v.insert(language_settings(language, file, cx).into_owned());
22250                }
22251                acc
22252            },
22253        )
22254    }
22255
22256    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22257        let new_language_settings = self.fetch_applicable_language_settings(cx);
22258        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22259        self.applicable_language_settings = new_language_settings;
22260
22261        let new_accents = self.fetch_accent_data(cx);
22262        let accents_changed = new_accents != self.accent_data;
22263        self.accent_data = new_accents;
22264
22265        if self.diagnostics_enabled() {
22266            let new_severity = EditorSettings::get_global(cx)
22267                .diagnostics_max_severity
22268                .unwrap_or(DiagnosticSeverity::Hint);
22269            self.set_max_diagnostics_severity(new_severity, cx);
22270        }
22271        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22272        self.update_edit_prediction_settings(cx);
22273        self.refresh_edit_prediction(true, false, window, cx);
22274        self.refresh_inline_values(cx);
22275        self.refresh_inlay_hints(
22276            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22277                self.selections.newest_anchor().head(),
22278                &self.buffer.read(cx).snapshot(cx),
22279                cx,
22280            )),
22281            cx,
22282        );
22283
22284        let old_cursor_shape = self.cursor_shape;
22285        let old_show_breadcrumbs = self.show_breadcrumbs;
22286
22287        {
22288            let editor_settings = EditorSettings::get_global(cx);
22289            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22290            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22291            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22292            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22293        }
22294
22295        if old_cursor_shape != self.cursor_shape {
22296            cx.emit(EditorEvent::CursorShapeChanged);
22297        }
22298
22299        if old_show_breadcrumbs != self.show_breadcrumbs {
22300            cx.emit(EditorEvent::BreadcrumbsChanged);
22301        }
22302
22303        let project_settings = ProjectSettings::get_global(cx);
22304        self.buffer_serialization = self
22305            .should_serialize_buffer()
22306            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22307
22308        if self.mode.is_full() {
22309            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22310            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22311            if self.show_inline_diagnostics != show_inline_diagnostics {
22312                self.show_inline_diagnostics = show_inline_diagnostics;
22313                self.refresh_inline_diagnostics(false, window, cx);
22314            }
22315
22316            if self.git_blame_inline_enabled != inline_blame_enabled {
22317                self.toggle_git_blame_inline_internal(false, window, cx);
22318            }
22319
22320            let minimap_settings = EditorSettings::get_global(cx).minimap;
22321            if self.minimap_visibility != MinimapVisibility::Disabled {
22322                if self.minimap_visibility.settings_visibility()
22323                    != minimap_settings.minimap_enabled()
22324                {
22325                    self.set_minimap_visibility(
22326                        MinimapVisibility::for_mode(self.mode(), cx),
22327                        window,
22328                        cx,
22329                    );
22330                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22331                    minimap_entity.update(cx, |minimap_editor, cx| {
22332                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22333                    })
22334                }
22335            }
22336
22337            if language_settings_changed || accents_changed {
22338                self.colorize_brackets(true, cx);
22339            }
22340
22341            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22342                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22343            }) {
22344                if !inlay_splice.is_empty() {
22345                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22346                }
22347                self.refresh_colors_for_visible_range(None, window, cx);
22348            }
22349        }
22350
22351        cx.notify();
22352    }
22353
22354    pub fn set_searchable(&mut self, searchable: bool) {
22355        self.searchable = searchable;
22356    }
22357
22358    pub fn searchable(&self) -> bool {
22359        self.searchable
22360    }
22361
22362    pub fn open_excerpts_in_split(
22363        &mut self,
22364        _: &OpenExcerptsSplit,
22365        window: &mut Window,
22366        cx: &mut Context<Self>,
22367    ) {
22368        self.open_excerpts_common(None, true, window, cx)
22369    }
22370
22371    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22372        self.open_excerpts_common(None, false, window, cx)
22373    }
22374
22375    fn open_excerpts_common(
22376        &mut self,
22377        jump_data: Option<JumpData>,
22378        split: bool,
22379        window: &mut Window,
22380        cx: &mut Context<Self>,
22381    ) {
22382        let Some(workspace) = self.workspace() else {
22383            cx.propagate();
22384            return;
22385        };
22386
22387        if self.buffer.read(cx).is_singleton() {
22388            cx.propagate();
22389            return;
22390        }
22391
22392        let mut new_selections_by_buffer = HashMap::default();
22393        match &jump_data {
22394            Some(JumpData::MultiBufferPoint {
22395                excerpt_id,
22396                position,
22397                anchor,
22398                line_offset_from_top,
22399            }) => {
22400                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22401                if let Some(buffer) = multi_buffer_snapshot
22402                    .buffer_id_for_excerpt(*excerpt_id)
22403                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22404                {
22405                    let buffer_snapshot = buffer.read(cx).snapshot();
22406                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22407                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22408                    } else {
22409                        buffer_snapshot.clip_point(*position, Bias::Left)
22410                    };
22411                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22412                    new_selections_by_buffer.insert(
22413                        buffer,
22414                        (
22415                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22416                            Some(*line_offset_from_top),
22417                        ),
22418                    );
22419                }
22420            }
22421            Some(JumpData::MultiBufferRow {
22422                row,
22423                line_offset_from_top,
22424            }) => {
22425                let point = MultiBufferPoint::new(row.0, 0);
22426                if let Some((buffer, buffer_point, _)) =
22427                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22428                {
22429                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22430                    new_selections_by_buffer
22431                        .entry(buffer)
22432                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22433                        .0
22434                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22435                }
22436            }
22437            None => {
22438                let selections = self
22439                    .selections
22440                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22441                let multi_buffer = self.buffer.read(cx);
22442                for selection in selections {
22443                    for (snapshot, range, _, anchor) in multi_buffer
22444                        .snapshot(cx)
22445                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22446                    {
22447                        if let Some(anchor) = anchor {
22448                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22449                            else {
22450                                continue;
22451                            };
22452                            let offset = text::ToOffset::to_offset(
22453                                &anchor.text_anchor,
22454                                &buffer_handle.read(cx).snapshot(),
22455                            );
22456                            let range = BufferOffset(offset)..BufferOffset(offset);
22457                            new_selections_by_buffer
22458                                .entry(buffer_handle)
22459                                .or_insert((Vec::new(), None))
22460                                .0
22461                                .push(range)
22462                        } else {
22463                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22464                            else {
22465                                continue;
22466                            };
22467                            new_selections_by_buffer
22468                                .entry(buffer_handle)
22469                                .or_insert((Vec::new(), None))
22470                                .0
22471                                .push(range)
22472                        }
22473                    }
22474                }
22475            }
22476        }
22477
22478        new_selections_by_buffer
22479            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22480
22481        if new_selections_by_buffer.is_empty() {
22482            return;
22483        }
22484
22485        // We defer the pane interaction because we ourselves are a workspace item
22486        // and activating a new item causes the pane to call a method on us reentrantly,
22487        // which panics if we're on the stack.
22488        window.defer(cx, move |window, cx| {
22489            workspace.update(cx, |workspace, cx| {
22490                let pane = if split {
22491                    workspace.adjacent_pane(window, cx)
22492                } else {
22493                    workspace.active_pane().clone()
22494                };
22495
22496                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22497                    let buffer_read = buffer.read(cx);
22498                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22499                        (true, project::File::from_dyn(Some(file)).is_some())
22500                    } else {
22501                        (false, false)
22502                    };
22503
22504                    // If project file is none workspace.open_project_item will fail to open the excerpt
22505                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22506                    // so we check if there's a tab match in that case first
22507                    let editor = (!has_file || !is_project_file)
22508                        .then(|| {
22509                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22510                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22511                            // Instead, we try to activate the existing editor in the pane first.
22512                            let (editor, pane_item_index, pane_item_id) =
22513                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22514                                    let editor = item.downcast::<Editor>()?;
22515                                    let singleton_buffer =
22516                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22517                                    if singleton_buffer == buffer {
22518                                        Some((editor, i, item.item_id()))
22519                                    } else {
22520                                        None
22521                                    }
22522                                })?;
22523                            pane.update(cx, |pane, cx| {
22524                                pane.activate_item(pane_item_index, true, true, window, cx);
22525                                if !PreviewTabsSettings::get_global(cx)
22526                                    .enable_preview_from_multibuffer
22527                                {
22528                                    pane.unpreview_item_if_preview(pane_item_id);
22529                                }
22530                            });
22531                            Some(editor)
22532                        })
22533                        .flatten()
22534                        .unwrap_or_else(|| {
22535                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22536                                .enable_keep_preview_on_code_navigation;
22537                            let allow_new_preview =
22538                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22539                            workspace.open_project_item::<Self>(
22540                                pane.clone(),
22541                                buffer,
22542                                true,
22543                                true,
22544                                keep_old_preview,
22545                                allow_new_preview,
22546                                window,
22547                                cx,
22548                            )
22549                        });
22550
22551                    editor.update(cx, |editor, cx| {
22552                        if has_file && !is_project_file {
22553                            editor.set_read_only(true);
22554                        }
22555                        let autoscroll = match scroll_offset {
22556                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22557                            None => Autoscroll::newest(),
22558                        };
22559                        let nav_history = editor.nav_history.take();
22560                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22561                        let Some((&excerpt_id, _, buffer_snapshot)) =
22562                            multibuffer_snapshot.as_singleton()
22563                        else {
22564                            return;
22565                        };
22566                        editor.change_selections(
22567                            SelectionEffects::scroll(autoscroll),
22568                            window,
22569                            cx,
22570                            |s| {
22571                                s.select_ranges(ranges.into_iter().map(|range| {
22572                                    let range = buffer_snapshot.anchor_before(range.start)
22573                                        ..buffer_snapshot.anchor_after(range.end);
22574                                    multibuffer_snapshot
22575                                        .anchor_range_in_excerpt(excerpt_id, range)
22576                                        .unwrap()
22577                                }));
22578                            },
22579                        );
22580                        editor.nav_history = nav_history;
22581                    });
22582                }
22583            })
22584        });
22585    }
22586
22587    // Allow opening excerpts for buffers that either belong to the current project
22588    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22589    // are also supported so tests and other in-memory views keep working.
22590    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22591        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22592    }
22593
22594    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22595        let snapshot = self.buffer.read(cx).read(cx);
22596        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22597        Some(
22598            ranges
22599                .iter()
22600                .map(move |range| {
22601                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22602                })
22603                .collect(),
22604        )
22605    }
22606
22607    fn selection_replacement_ranges(
22608        &self,
22609        range: Range<MultiBufferOffsetUtf16>,
22610        cx: &mut App,
22611    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22612        let selections = self
22613            .selections
22614            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22615        let newest_selection = selections
22616            .iter()
22617            .max_by_key(|selection| selection.id)
22618            .unwrap();
22619        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22620        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22621        let snapshot = self.buffer.read(cx).read(cx);
22622        selections
22623            .into_iter()
22624            .map(|mut selection| {
22625                selection.start.0.0 =
22626                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22627                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22628                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22629                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22630            })
22631            .collect()
22632    }
22633
22634    fn report_editor_event(
22635        &self,
22636        reported_event: ReportEditorEvent,
22637        file_extension: Option<String>,
22638        cx: &App,
22639    ) {
22640        if cfg!(any(test, feature = "test-support")) {
22641            return;
22642        }
22643
22644        let Some(project) = &self.project else { return };
22645
22646        // If None, we are in a file without an extension
22647        let file = self
22648            .buffer
22649            .read(cx)
22650            .as_singleton()
22651            .and_then(|b| b.read(cx).file());
22652        let file_extension = file_extension.or(file
22653            .as_ref()
22654            .and_then(|file| Path::new(file.file_name(cx)).extension())
22655            .and_then(|e| e.to_str())
22656            .map(|a| a.to_string()));
22657
22658        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22659            .map(|vim_mode| vim_mode.0)
22660            .unwrap_or(false);
22661
22662        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22663        let copilot_enabled = edit_predictions_provider
22664            == language::language_settings::EditPredictionProvider::Copilot;
22665        let copilot_enabled_for_language = self
22666            .buffer
22667            .read(cx)
22668            .language_settings(cx)
22669            .show_edit_predictions;
22670
22671        let project = project.read(cx);
22672        let event_type = reported_event.event_type();
22673
22674        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22675            telemetry::event!(
22676                event_type,
22677                type = if auto_saved {"autosave"} else {"manual"},
22678                file_extension,
22679                vim_mode,
22680                copilot_enabled,
22681                copilot_enabled_for_language,
22682                edit_predictions_provider,
22683                is_via_ssh = project.is_via_remote_server(),
22684            );
22685        } else {
22686            telemetry::event!(
22687                event_type,
22688                file_extension,
22689                vim_mode,
22690                copilot_enabled,
22691                copilot_enabled_for_language,
22692                edit_predictions_provider,
22693                is_via_ssh = project.is_via_remote_server(),
22694            );
22695        };
22696    }
22697
22698    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22699    /// with each line being an array of {text, highlight} objects.
22700    fn copy_highlight_json(
22701        &mut self,
22702        _: &CopyHighlightJson,
22703        window: &mut Window,
22704        cx: &mut Context<Self>,
22705    ) {
22706        #[derive(Serialize)]
22707        struct Chunk<'a> {
22708            text: String,
22709            highlight: Option<&'a str>,
22710        }
22711
22712        let snapshot = self.buffer.read(cx).snapshot(cx);
22713        let range = self
22714            .selected_text_range(false, window, cx)
22715            .and_then(|selection| {
22716                if selection.range.is_empty() {
22717                    None
22718                } else {
22719                    Some(
22720                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22721                            selection.range.start,
22722                        )))
22723                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22724                                selection.range.end,
22725                            ))),
22726                    )
22727                }
22728            })
22729            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22730
22731        let chunks = snapshot.chunks(range, true);
22732        let mut lines = Vec::new();
22733        let mut line: VecDeque<Chunk> = VecDeque::new();
22734
22735        let Some(style) = self.style.as_ref() else {
22736            return;
22737        };
22738
22739        for chunk in chunks {
22740            let highlight = chunk
22741                .syntax_highlight_id
22742                .and_then(|id| id.name(&style.syntax));
22743            let mut chunk_lines = chunk.text.split('\n').peekable();
22744            while let Some(text) = chunk_lines.next() {
22745                let mut merged_with_last_token = false;
22746                if let Some(last_token) = line.back_mut()
22747                    && last_token.highlight == highlight
22748                {
22749                    last_token.text.push_str(text);
22750                    merged_with_last_token = true;
22751                }
22752
22753                if !merged_with_last_token {
22754                    line.push_back(Chunk {
22755                        text: text.into(),
22756                        highlight,
22757                    });
22758                }
22759
22760                if chunk_lines.peek().is_some() {
22761                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22762                        line.pop_front();
22763                    }
22764                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22765                        line.pop_back();
22766                    }
22767
22768                    lines.push(mem::take(&mut line));
22769                }
22770            }
22771        }
22772
22773        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22774            return;
22775        };
22776        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22777    }
22778
22779    pub fn open_context_menu(
22780        &mut self,
22781        _: &OpenContextMenu,
22782        window: &mut Window,
22783        cx: &mut Context<Self>,
22784    ) {
22785        self.request_autoscroll(Autoscroll::newest(), cx);
22786        let position = self
22787            .selections
22788            .newest_display(&self.display_snapshot(cx))
22789            .start;
22790        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22791    }
22792
22793    pub fn replay_insert_event(
22794        &mut self,
22795        text: &str,
22796        relative_utf16_range: Option<Range<isize>>,
22797        window: &mut Window,
22798        cx: &mut Context<Self>,
22799    ) {
22800        if !self.input_enabled {
22801            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22802            return;
22803        }
22804        if let Some(relative_utf16_range) = relative_utf16_range {
22805            let selections = self
22806                .selections
22807                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22808            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22809                let new_ranges = selections.into_iter().map(|range| {
22810                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22811                        range
22812                            .head()
22813                            .0
22814                            .0
22815                            .saturating_add_signed(relative_utf16_range.start),
22816                    ));
22817                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22818                        range
22819                            .head()
22820                            .0
22821                            .0
22822                            .saturating_add_signed(relative_utf16_range.end),
22823                    ));
22824                    start..end
22825                });
22826                s.select_ranges(new_ranges);
22827            });
22828        }
22829
22830        self.handle_input(text, window, cx);
22831    }
22832
22833    pub fn is_focused(&self, window: &Window) -> bool {
22834        self.focus_handle.is_focused(window)
22835    }
22836
22837    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22838        cx.emit(EditorEvent::Focused);
22839
22840        if let Some(descendant) = self
22841            .last_focused_descendant
22842            .take()
22843            .and_then(|descendant| descendant.upgrade())
22844        {
22845            window.focus(&descendant);
22846        } else {
22847            if let Some(blame) = self.blame.as_ref() {
22848                blame.update(cx, GitBlame::focus)
22849            }
22850
22851            self.blink_manager.update(cx, BlinkManager::enable);
22852            self.show_cursor_names(window, cx);
22853            self.buffer.update(cx, |buffer, cx| {
22854                buffer.finalize_last_transaction(cx);
22855                if self.leader_id.is_none() {
22856                    buffer.set_active_selections(
22857                        &self.selections.disjoint_anchors_arc(),
22858                        self.selections.line_mode(),
22859                        self.cursor_shape,
22860                        cx,
22861                    );
22862                }
22863            });
22864
22865            if let Some(position_map) = self.last_position_map.clone() {
22866                EditorElement::mouse_moved(
22867                    self,
22868                    &MouseMoveEvent {
22869                        position: window.mouse_position(),
22870                        pressed_button: None,
22871                        modifiers: window.modifiers(),
22872                    },
22873                    &position_map,
22874                    window,
22875                    cx,
22876                );
22877            }
22878        }
22879    }
22880
22881    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22882        cx.emit(EditorEvent::FocusedIn)
22883    }
22884
22885    fn handle_focus_out(
22886        &mut self,
22887        event: FocusOutEvent,
22888        _window: &mut Window,
22889        cx: &mut Context<Self>,
22890    ) {
22891        if event.blurred != self.focus_handle {
22892            self.last_focused_descendant = Some(event.blurred);
22893        }
22894        self.selection_drag_state = SelectionDragState::None;
22895        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22896    }
22897
22898    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22899        self.blink_manager.update(cx, BlinkManager::disable);
22900        self.buffer
22901            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22902
22903        if let Some(blame) = self.blame.as_ref() {
22904            blame.update(cx, GitBlame::blur)
22905        }
22906        if !self.hover_state.focused(window, cx) {
22907            hide_hover(self, cx);
22908        }
22909        if !self
22910            .context_menu
22911            .borrow()
22912            .as_ref()
22913            .is_some_and(|context_menu| context_menu.focused(window, cx))
22914        {
22915            self.hide_context_menu(window, cx);
22916        }
22917        self.take_active_edit_prediction(cx);
22918        cx.emit(EditorEvent::Blurred);
22919        cx.notify();
22920    }
22921
22922    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22923        let mut pending: String = window
22924            .pending_input_keystrokes()
22925            .into_iter()
22926            .flatten()
22927            .filter_map(|keystroke| keystroke.key_char.clone())
22928            .collect();
22929
22930        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22931            pending = "".to_string();
22932        }
22933
22934        let existing_pending = self
22935            .text_highlights::<PendingInput>(cx)
22936            .map(|(_, ranges)| ranges.to_vec());
22937        if existing_pending.is_none() && pending.is_empty() {
22938            return;
22939        }
22940        let transaction =
22941            self.transact(window, cx, |this, window, cx| {
22942                let selections = this
22943                    .selections
22944                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22945                let edits = selections
22946                    .iter()
22947                    .map(|selection| (selection.end..selection.end, pending.clone()));
22948                this.edit(edits, cx);
22949                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22950                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22951                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22952                    }));
22953                });
22954                if let Some(existing_ranges) = existing_pending {
22955                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22956                    this.edit(edits, cx);
22957                }
22958            });
22959
22960        let snapshot = self.snapshot(window, cx);
22961        let ranges = self
22962            .selections
22963            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22964            .into_iter()
22965            .map(|selection| {
22966                snapshot.buffer_snapshot().anchor_after(selection.end)
22967                    ..snapshot
22968                        .buffer_snapshot()
22969                        .anchor_before(selection.end + pending.len())
22970            })
22971            .collect();
22972
22973        if pending.is_empty() {
22974            self.clear_highlights::<PendingInput>(cx);
22975        } else {
22976            self.highlight_text::<PendingInput>(
22977                ranges,
22978                HighlightStyle {
22979                    underline: Some(UnderlineStyle {
22980                        thickness: px(1.),
22981                        color: None,
22982                        wavy: false,
22983                    }),
22984                    ..Default::default()
22985                },
22986                cx,
22987            );
22988        }
22989
22990        self.ime_transaction = self.ime_transaction.or(transaction);
22991        if let Some(transaction) = self.ime_transaction {
22992            self.buffer.update(cx, |buffer, cx| {
22993                buffer.group_until_transaction(transaction, cx);
22994            });
22995        }
22996
22997        if self.text_highlights::<PendingInput>(cx).is_none() {
22998            self.ime_transaction.take();
22999        }
23000    }
23001
23002    pub fn register_action_renderer(
23003        &mut self,
23004        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23005    ) -> Subscription {
23006        let id = self.next_editor_action_id.post_inc();
23007        self.editor_actions
23008            .borrow_mut()
23009            .insert(id, Box::new(listener));
23010
23011        let editor_actions = self.editor_actions.clone();
23012        Subscription::new(move || {
23013            editor_actions.borrow_mut().remove(&id);
23014        })
23015    }
23016
23017    pub fn register_action<A: Action>(
23018        &mut self,
23019        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23020    ) -> Subscription {
23021        let id = self.next_editor_action_id.post_inc();
23022        let listener = Arc::new(listener);
23023        self.editor_actions.borrow_mut().insert(
23024            id,
23025            Box::new(move |_, window, _| {
23026                let listener = listener.clone();
23027                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23028                    let action = action.downcast_ref().unwrap();
23029                    if phase == DispatchPhase::Bubble {
23030                        listener(action, window, cx)
23031                    }
23032                })
23033            }),
23034        );
23035
23036        let editor_actions = self.editor_actions.clone();
23037        Subscription::new(move || {
23038            editor_actions.borrow_mut().remove(&id);
23039        })
23040    }
23041
23042    pub fn file_header_size(&self) -> u32 {
23043        FILE_HEADER_HEIGHT
23044    }
23045
23046    pub fn restore(
23047        &mut self,
23048        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23049        window: &mut Window,
23050        cx: &mut Context<Self>,
23051    ) {
23052        self.buffer().update(cx, |multi_buffer, cx| {
23053            for (buffer_id, changes) in revert_changes {
23054                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23055                    buffer.update(cx, |buffer, cx| {
23056                        buffer.edit(
23057                            changes
23058                                .into_iter()
23059                                .map(|(range, text)| (range, text.to_string())),
23060                            None,
23061                            cx,
23062                        );
23063                    });
23064                }
23065            }
23066        });
23067        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23068            selections.refresh()
23069        });
23070    }
23071
23072    pub fn to_pixel_point(
23073        &mut self,
23074        source: multi_buffer::Anchor,
23075        editor_snapshot: &EditorSnapshot,
23076        window: &mut Window,
23077        cx: &App,
23078    ) -> Option<gpui::Point<Pixels>> {
23079        let source_point = source.to_display_point(editor_snapshot);
23080        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23081    }
23082
23083    pub fn display_to_pixel_point(
23084        &mut self,
23085        source: DisplayPoint,
23086        editor_snapshot: &EditorSnapshot,
23087        window: &mut Window,
23088        cx: &App,
23089    ) -> Option<gpui::Point<Pixels>> {
23090        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23091        let text_layout_details = self.text_layout_details(window);
23092        let scroll_top = text_layout_details
23093            .scroll_anchor
23094            .scroll_position(editor_snapshot)
23095            .y;
23096
23097        if source.row().as_f64() < scroll_top.floor() {
23098            return None;
23099        }
23100        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23101        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23102        Some(gpui::Point::new(source_x, source_y))
23103    }
23104
23105    pub fn has_visible_completions_menu(&self) -> bool {
23106        !self.edit_prediction_preview_is_active()
23107            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23108                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23109            })
23110    }
23111
23112    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23113        if self.mode.is_minimap() {
23114            return;
23115        }
23116        self.addons
23117            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23118    }
23119
23120    pub fn unregister_addon<T: Addon>(&mut self) {
23121        self.addons.remove(&std::any::TypeId::of::<T>());
23122    }
23123
23124    pub fn addon<T: Addon>(&self) -> Option<&T> {
23125        let type_id = std::any::TypeId::of::<T>();
23126        self.addons
23127            .get(&type_id)
23128            .and_then(|item| item.to_any().downcast_ref::<T>())
23129    }
23130
23131    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23132        let type_id = std::any::TypeId::of::<T>();
23133        self.addons
23134            .get_mut(&type_id)
23135            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23136    }
23137
23138    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23139        let text_layout_details = self.text_layout_details(window);
23140        let style = &text_layout_details.editor_style;
23141        let font_id = window.text_system().resolve_font(&style.text.font());
23142        let font_size = style.text.font_size.to_pixels(window.rem_size());
23143        let line_height = style.text.line_height_in_pixels(window.rem_size());
23144        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23145        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23146
23147        CharacterDimensions {
23148            em_width,
23149            em_advance,
23150            line_height,
23151        }
23152    }
23153
23154    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23155        self.load_diff_task.clone()
23156    }
23157
23158    fn read_metadata_from_db(
23159        &mut self,
23160        item_id: u64,
23161        workspace_id: WorkspaceId,
23162        window: &mut Window,
23163        cx: &mut Context<Editor>,
23164    ) {
23165        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23166            && !self.mode.is_minimap()
23167            && WorkspaceSettings::get(None, cx).restore_on_startup
23168                != RestoreOnStartupBehavior::EmptyTab
23169        {
23170            let buffer_snapshot = OnceCell::new();
23171
23172            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23173                && !folds.is_empty()
23174            {
23175                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23176                self.fold_ranges(
23177                    folds
23178                        .into_iter()
23179                        .map(|(start, end)| {
23180                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23181                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23182                        })
23183                        .collect(),
23184                    false,
23185                    window,
23186                    cx,
23187                );
23188            }
23189
23190            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23191                && !selections.is_empty()
23192            {
23193                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23194                // skip adding the initial selection to selection history
23195                self.selection_history.mode = SelectionHistoryMode::Skipping;
23196                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23197                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23198                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23199                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23200                    }));
23201                });
23202                self.selection_history.mode = SelectionHistoryMode::Normal;
23203            };
23204        }
23205
23206        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23207    }
23208
23209    fn update_lsp_data(
23210        &mut self,
23211        for_buffer: Option<BufferId>,
23212        window: &mut Window,
23213        cx: &mut Context<'_, Self>,
23214    ) {
23215        self.pull_diagnostics(for_buffer, window, cx);
23216        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23217    }
23218
23219    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23220        if self.ignore_lsp_data() {
23221            return;
23222        }
23223        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23224            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23225        }
23226    }
23227
23228    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23229        if self.ignore_lsp_data() {
23230            return;
23231        }
23232
23233        if !self.registered_buffers.contains_key(&buffer_id)
23234            && let Some(project) = self.project.as_ref()
23235        {
23236            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23237                project.update(cx, |project, cx| {
23238                    self.registered_buffers.insert(
23239                        buffer_id,
23240                        project.register_buffer_with_language_servers(&buffer, cx),
23241                    );
23242                });
23243            } else {
23244                self.registered_buffers.remove(&buffer_id);
23245            }
23246        }
23247    }
23248
23249    fn ignore_lsp_data(&self) -> bool {
23250        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23251        // skip any LSP updates for it.
23252        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23253    }
23254
23255    fn create_style(&self, cx: &App) -> EditorStyle {
23256        let settings = ThemeSettings::get_global(cx);
23257
23258        let mut text_style = match self.mode {
23259            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23260                color: cx.theme().colors().editor_foreground,
23261                font_family: settings.ui_font.family.clone(),
23262                font_features: settings.ui_font.features.clone(),
23263                font_fallbacks: settings.ui_font.fallbacks.clone(),
23264                font_size: rems(0.875).into(),
23265                font_weight: settings.ui_font.weight,
23266                line_height: relative(settings.buffer_line_height.value()),
23267                ..Default::default()
23268            },
23269            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23270                color: cx.theme().colors().editor_foreground,
23271                font_family: settings.buffer_font.family.clone(),
23272                font_features: settings.buffer_font.features.clone(),
23273                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23274                font_size: settings.buffer_font_size(cx).into(),
23275                font_weight: settings.buffer_font.weight,
23276                line_height: relative(settings.buffer_line_height.value()),
23277                ..Default::default()
23278            },
23279        };
23280        if let Some(text_style_refinement) = &self.text_style_refinement {
23281            text_style.refine(text_style_refinement)
23282        }
23283
23284        let background = match self.mode {
23285            EditorMode::SingleLine => cx.theme().system().transparent,
23286            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23287            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23288            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23289        };
23290
23291        EditorStyle {
23292            background,
23293            border: cx.theme().colors().border,
23294            local_player: cx.theme().players().local(),
23295            text: text_style,
23296            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23297            syntax: cx.theme().syntax().clone(),
23298            status: cx.theme().status().clone(),
23299            inlay_hints_style: make_inlay_hints_style(cx),
23300            edit_prediction_styles: make_suggestion_styles(cx),
23301            unnecessary_code_fade: settings.unnecessary_code_fade,
23302            show_underlines: self.diagnostics_enabled(),
23303        }
23304    }
23305}
23306
23307fn edit_for_markdown_paste<'a>(
23308    buffer: &MultiBufferSnapshot,
23309    range: Range<MultiBufferOffset>,
23310    to_insert: &'a str,
23311    url: Option<url::Url>,
23312) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23313    if url.is_none() {
23314        return (range, Cow::Borrowed(to_insert));
23315    };
23316
23317    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23318
23319    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23320        Cow::Borrowed(to_insert)
23321    } else {
23322        Cow::Owned(format!("[{old_text}]({to_insert})"))
23323    };
23324    (range, new_text)
23325}
23326
23327fn process_completion_for_edit(
23328    completion: &Completion,
23329    intent: CompletionIntent,
23330    buffer: &Entity<Buffer>,
23331    cursor_position: &text::Anchor,
23332    cx: &mut Context<Editor>,
23333) -> CompletionEdit {
23334    let buffer = buffer.read(cx);
23335    let buffer_snapshot = buffer.snapshot();
23336    let (snippet, new_text) = if completion.is_snippet() {
23337        let mut snippet_source = completion.new_text.clone();
23338        // Workaround for typescript language server issues so that methods don't expand within
23339        // strings and functions with type expressions. The previous point is used because the query
23340        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23341        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23342        let previous_point = if previous_point.column > 0 {
23343            cursor_position.to_previous_offset(&buffer_snapshot)
23344        } else {
23345            cursor_position.to_offset(&buffer_snapshot)
23346        };
23347        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23348            && scope.prefers_label_for_snippet_in_completion()
23349            && let Some(label) = completion.label()
23350            && matches!(
23351                completion.kind(),
23352                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23353            )
23354        {
23355            snippet_source = label;
23356        }
23357        match Snippet::parse(&snippet_source).log_err() {
23358            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23359            None => (None, completion.new_text.clone()),
23360        }
23361    } else {
23362        (None, completion.new_text.clone())
23363    };
23364
23365    let mut range_to_replace = {
23366        let replace_range = &completion.replace_range;
23367        if let CompletionSource::Lsp {
23368            insert_range: Some(insert_range),
23369            ..
23370        } = &completion.source
23371        {
23372            debug_assert_eq!(
23373                insert_range.start, replace_range.start,
23374                "insert_range and replace_range should start at the same position"
23375            );
23376            debug_assert!(
23377                insert_range
23378                    .start
23379                    .cmp(cursor_position, &buffer_snapshot)
23380                    .is_le(),
23381                "insert_range should start before or at cursor position"
23382            );
23383            debug_assert!(
23384                replace_range
23385                    .start
23386                    .cmp(cursor_position, &buffer_snapshot)
23387                    .is_le(),
23388                "replace_range should start before or at cursor position"
23389            );
23390
23391            let should_replace = match intent {
23392                CompletionIntent::CompleteWithInsert => false,
23393                CompletionIntent::CompleteWithReplace => true,
23394                CompletionIntent::Complete | CompletionIntent::Compose => {
23395                    let insert_mode =
23396                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23397                            .completions
23398                            .lsp_insert_mode;
23399                    match insert_mode {
23400                        LspInsertMode::Insert => false,
23401                        LspInsertMode::Replace => true,
23402                        LspInsertMode::ReplaceSubsequence => {
23403                            let mut text_to_replace = buffer.chars_for_range(
23404                                buffer.anchor_before(replace_range.start)
23405                                    ..buffer.anchor_after(replace_range.end),
23406                            );
23407                            let mut current_needle = text_to_replace.next();
23408                            for haystack_ch in completion.label.text.chars() {
23409                                if let Some(needle_ch) = current_needle
23410                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23411                                {
23412                                    current_needle = text_to_replace.next();
23413                                }
23414                            }
23415                            current_needle.is_none()
23416                        }
23417                        LspInsertMode::ReplaceSuffix => {
23418                            if replace_range
23419                                .end
23420                                .cmp(cursor_position, &buffer_snapshot)
23421                                .is_gt()
23422                            {
23423                                let range_after_cursor = *cursor_position..replace_range.end;
23424                                let text_after_cursor = buffer
23425                                    .text_for_range(
23426                                        buffer.anchor_before(range_after_cursor.start)
23427                                            ..buffer.anchor_after(range_after_cursor.end),
23428                                    )
23429                                    .collect::<String>()
23430                                    .to_ascii_lowercase();
23431                                completion
23432                                    .label
23433                                    .text
23434                                    .to_ascii_lowercase()
23435                                    .ends_with(&text_after_cursor)
23436                            } else {
23437                                true
23438                            }
23439                        }
23440                    }
23441                }
23442            };
23443
23444            if should_replace {
23445                replace_range.clone()
23446            } else {
23447                insert_range.clone()
23448            }
23449        } else {
23450            replace_range.clone()
23451        }
23452    };
23453
23454    if range_to_replace
23455        .end
23456        .cmp(cursor_position, &buffer_snapshot)
23457        .is_lt()
23458    {
23459        range_to_replace.end = *cursor_position;
23460    }
23461
23462    let replace_range = range_to_replace.to_offset(buffer);
23463    CompletionEdit {
23464        new_text,
23465        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23466        snippet,
23467    }
23468}
23469
23470struct CompletionEdit {
23471    new_text: String,
23472    replace_range: Range<BufferOffset>,
23473    snippet: Option<Snippet>,
23474}
23475
23476fn insert_extra_newline_brackets(
23477    buffer: &MultiBufferSnapshot,
23478    range: Range<MultiBufferOffset>,
23479    language: &language::LanguageScope,
23480) -> bool {
23481    let leading_whitespace_len = buffer
23482        .reversed_chars_at(range.start)
23483        .take_while(|c| c.is_whitespace() && *c != '\n')
23484        .map(|c| c.len_utf8())
23485        .sum::<usize>();
23486    let trailing_whitespace_len = buffer
23487        .chars_at(range.end)
23488        .take_while(|c| c.is_whitespace() && *c != '\n')
23489        .map(|c| c.len_utf8())
23490        .sum::<usize>();
23491    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23492
23493    language.brackets().any(|(pair, enabled)| {
23494        let pair_start = pair.start.trim_end();
23495        let pair_end = pair.end.trim_start();
23496
23497        enabled
23498            && pair.newline
23499            && buffer.contains_str_at(range.end, pair_end)
23500            && buffer.contains_str_at(
23501                range.start.saturating_sub_usize(pair_start.len()),
23502                pair_start,
23503            )
23504    })
23505}
23506
23507fn insert_extra_newline_tree_sitter(
23508    buffer: &MultiBufferSnapshot,
23509    range: Range<MultiBufferOffset>,
23510) -> bool {
23511    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23512        [(buffer, range, _)] => (*buffer, range.clone()),
23513        _ => return false,
23514    };
23515    let pair = {
23516        let mut result: Option<BracketMatch<usize>> = None;
23517
23518        for pair in buffer
23519            .all_bracket_ranges(range.start.0..range.end.0)
23520            .filter(move |pair| {
23521                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23522            })
23523        {
23524            let len = pair.close_range.end - pair.open_range.start;
23525
23526            if let Some(existing) = &result {
23527                let existing_len = existing.close_range.end - existing.open_range.start;
23528                if len > existing_len {
23529                    continue;
23530                }
23531            }
23532
23533            result = Some(pair);
23534        }
23535
23536        result
23537    };
23538    let Some(pair) = pair else {
23539        return false;
23540    };
23541    pair.newline_only
23542        && buffer
23543            .chars_for_range(pair.open_range.end..range.start.0)
23544            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23545            .all(|c| c.is_whitespace() && c != '\n')
23546}
23547
23548fn update_uncommitted_diff_for_buffer(
23549    editor: Entity<Editor>,
23550    project: &Entity<Project>,
23551    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23552    buffer: Entity<MultiBuffer>,
23553    cx: &mut App,
23554) -> Task<()> {
23555    let mut tasks = Vec::new();
23556    project.update(cx, |project, cx| {
23557        for buffer in buffers {
23558            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23559                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23560            }
23561        }
23562    });
23563    cx.spawn(async move |cx| {
23564        let diffs = future::join_all(tasks).await;
23565        if editor
23566            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23567            .unwrap_or(false)
23568        {
23569            return;
23570        }
23571
23572        buffer
23573            .update(cx, |buffer, cx| {
23574                for diff in diffs.into_iter().flatten() {
23575                    buffer.add_diff(diff, cx);
23576                }
23577            })
23578            .ok();
23579    })
23580}
23581
23582fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23583    let tab_size = tab_size.get() as usize;
23584    let mut width = offset;
23585
23586    for ch in text.chars() {
23587        width += if ch == '\t' {
23588            tab_size - (width % tab_size)
23589        } else {
23590            1
23591        };
23592    }
23593
23594    width - offset
23595}
23596
23597#[cfg(test)]
23598mod tests {
23599    use super::*;
23600
23601    #[test]
23602    fn test_string_size_with_expanded_tabs() {
23603        let nz = |val| NonZeroU32::new(val).unwrap();
23604        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23605        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23606        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23607        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23608        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23609        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23610        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23611        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23612    }
23613}
23614
23615/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23616struct WordBreakingTokenizer<'a> {
23617    input: &'a str,
23618}
23619
23620impl<'a> WordBreakingTokenizer<'a> {
23621    fn new(input: &'a str) -> Self {
23622        Self { input }
23623    }
23624}
23625
23626fn is_char_ideographic(ch: char) -> bool {
23627    use unicode_script::Script::*;
23628    use unicode_script::UnicodeScript;
23629    matches!(ch.script(), Han | Tangut | Yi)
23630}
23631
23632fn is_grapheme_ideographic(text: &str) -> bool {
23633    text.chars().any(is_char_ideographic)
23634}
23635
23636fn is_grapheme_whitespace(text: &str) -> bool {
23637    text.chars().any(|x| x.is_whitespace())
23638}
23639
23640fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23641    text.chars()
23642        .next()
23643        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23644}
23645
23646#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23647enum WordBreakToken<'a> {
23648    Word { token: &'a str, grapheme_len: usize },
23649    InlineWhitespace { token: &'a str, grapheme_len: usize },
23650    Newline,
23651}
23652
23653impl<'a> Iterator for WordBreakingTokenizer<'a> {
23654    /// Yields a span, the count of graphemes in the token, and whether it was
23655    /// whitespace. Note that it also breaks at word boundaries.
23656    type Item = WordBreakToken<'a>;
23657
23658    fn next(&mut self) -> Option<Self::Item> {
23659        use unicode_segmentation::UnicodeSegmentation;
23660        if self.input.is_empty() {
23661            return None;
23662        }
23663
23664        let mut iter = self.input.graphemes(true).peekable();
23665        let mut offset = 0;
23666        let mut grapheme_len = 0;
23667        if let Some(first_grapheme) = iter.next() {
23668            let is_newline = first_grapheme == "\n";
23669            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23670            offset += first_grapheme.len();
23671            grapheme_len += 1;
23672            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23673                if let Some(grapheme) = iter.peek().copied()
23674                    && should_stay_with_preceding_ideograph(grapheme)
23675                {
23676                    offset += grapheme.len();
23677                    grapheme_len += 1;
23678                }
23679            } else {
23680                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23681                let mut next_word_bound = words.peek().copied();
23682                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23683                    next_word_bound = words.next();
23684                }
23685                while let Some(grapheme) = iter.peek().copied() {
23686                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23687                        break;
23688                    };
23689                    if is_grapheme_whitespace(grapheme) != is_whitespace
23690                        || (grapheme == "\n") != is_newline
23691                    {
23692                        break;
23693                    };
23694                    offset += grapheme.len();
23695                    grapheme_len += 1;
23696                    iter.next();
23697                }
23698            }
23699            let token = &self.input[..offset];
23700            self.input = &self.input[offset..];
23701            if token == "\n" {
23702                Some(WordBreakToken::Newline)
23703            } else if is_whitespace {
23704                Some(WordBreakToken::InlineWhitespace {
23705                    token,
23706                    grapheme_len,
23707                })
23708            } else {
23709                Some(WordBreakToken::Word {
23710                    token,
23711                    grapheme_len,
23712                })
23713            }
23714        } else {
23715            None
23716        }
23717    }
23718}
23719
23720#[test]
23721fn test_word_breaking_tokenizer() {
23722    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23723        ("", &[]),
23724        ("  ", &[whitespace("  ", 2)]),
23725        ("Ʒ", &[word("Ʒ", 1)]),
23726        ("Ǽ", &[word("Ǽ", 1)]),
23727        ("", &[word("", 1)]),
23728        ("⋑⋑", &[word("⋑⋑", 2)]),
23729        (
23730            "原理,进而",
23731            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23732        ),
23733        (
23734            "hello world",
23735            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23736        ),
23737        (
23738            "hello, world",
23739            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23740        ),
23741        (
23742            "  hello world",
23743            &[
23744                whitespace("  ", 2),
23745                word("hello", 5),
23746                whitespace(" ", 1),
23747                word("world", 5),
23748            ],
23749        ),
23750        (
23751            "这是什么 \n 钢笔",
23752            &[
23753                word("", 1),
23754                word("", 1),
23755                word("", 1),
23756                word("", 1),
23757                whitespace(" ", 1),
23758                newline(),
23759                whitespace(" ", 1),
23760                word("", 1),
23761                word("", 1),
23762            ],
23763        ),
23764        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23765    ];
23766
23767    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23768        WordBreakToken::Word {
23769            token,
23770            grapheme_len,
23771        }
23772    }
23773
23774    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23775        WordBreakToken::InlineWhitespace {
23776            token,
23777            grapheme_len,
23778        }
23779    }
23780
23781    fn newline() -> WordBreakToken<'static> {
23782        WordBreakToken::Newline
23783    }
23784
23785    for (input, result) in tests {
23786        assert_eq!(
23787            WordBreakingTokenizer::new(input)
23788                .collect::<Vec<_>>()
23789                .as_slice(),
23790            *result,
23791        );
23792    }
23793}
23794
23795fn wrap_with_prefix(
23796    first_line_prefix: String,
23797    subsequent_lines_prefix: String,
23798    unwrapped_text: String,
23799    wrap_column: usize,
23800    tab_size: NonZeroU32,
23801    preserve_existing_whitespace: bool,
23802) -> String {
23803    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23804    let subsequent_lines_prefix_len =
23805        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23806    let mut wrapped_text = String::new();
23807    let mut current_line = first_line_prefix;
23808    let mut is_first_line = true;
23809
23810    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23811    let mut current_line_len = first_line_prefix_len;
23812    let mut in_whitespace = false;
23813    for token in tokenizer {
23814        let have_preceding_whitespace = in_whitespace;
23815        match token {
23816            WordBreakToken::Word {
23817                token,
23818                grapheme_len,
23819            } => {
23820                in_whitespace = false;
23821                let current_prefix_len = if is_first_line {
23822                    first_line_prefix_len
23823                } else {
23824                    subsequent_lines_prefix_len
23825                };
23826                if current_line_len + grapheme_len > wrap_column
23827                    && current_line_len != current_prefix_len
23828                {
23829                    wrapped_text.push_str(current_line.trim_end());
23830                    wrapped_text.push('\n');
23831                    is_first_line = false;
23832                    current_line = subsequent_lines_prefix.clone();
23833                    current_line_len = subsequent_lines_prefix_len;
23834                }
23835                current_line.push_str(token);
23836                current_line_len += grapheme_len;
23837            }
23838            WordBreakToken::InlineWhitespace {
23839                mut token,
23840                mut grapheme_len,
23841            } => {
23842                in_whitespace = true;
23843                if have_preceding_whitespace && !preserve_existing_whitespace {
23844                    continue;
23845                }
23846                if !preserve_existing_whitespace {
23847                    // Keep a single whitespace grapheme as-is
23848                    if let Some(first) =
23849                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23850                    {
23851                        token = first;
23852                    } else {
23853                        token = " ";
23854                    }
23855                    grapheme_len = 1;
23856                }
23857                let current_prefix_len = if is_first_line {
23858                    first_line_prefix_len
23859                } else {
23860                    subsequent_lines_prefix_len
23861                };
23862                if current_line_len + grapheme_len > wrap_column {
23863                    wrapped_text.push_str(current_line.trim_end());
23864                    wrapped_text.push('\n');
23865                    is_first_line = false;
23866                    current_line = subsequent_lines_prefix.clone();
23867                    current_line_len = subsequent_lines_prefix_len;
23868                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23869                    current_line.push_str(token);
23870                    current_line_len += grapheme_len;
23871                }
23872            }
23873            WordBreakToken::Newline => {
23874                in_whitespace = true;
23875                let current_prefix_len = if is_first_line {
23876                    first_line_prefix_len
23877                } else {
23878                    subsequent_lines_prefix_len
23879                };
23880                if preserve_existing_whitespace {
23881                    wrapped_text.push_str(current_line.trim_end());
23882                    wrapped_text.push('\n');
23883                    is_first_line = false;
23884                    current_line = subsequent_lines_prefix.clone();
23885                    current_line_len = subsequent_lines_prefix_len;
23886                } else if have_preceding_whitespace {
23887                    continue;
23888                } else if current_line_len + 1 > wrap_column
23889                    && current_line_len != current_prefix_len
23890                {
23891                    wrapped_text.push_str(current_line.trim_end());
23892                    wrapped_text.push('\n');
23893                    is_first_line = false;
23894                    current_line = subsequent_lines_prefix.clone();
23895                    current_line_len = subsequent_lines_prefix_len;
23896                } else if current_line_len != current_prefix_len {
23897                    current_line.push(' ');
23898                    current_line_len += 1;
23899                }
23900            }
23901        }
23902    }
23903
23904    if !current_line.is_empty() {
23905        wrapped_text.push_str(&current_line);
23906    }
23907    wrapped_text
23908}
23909
23910#[test]
23911fn test_wrap_with_prefix() {
23912    assert_eq!(
23913        wrap_with_prefix(
23914            "# ".to_string(),
23915            "# ".to_string(),
23916            "abcdefg".to_string(),
23917            4,
23918            NonZeroU32::new(4).unwrap(),
23919            false,
23920        ),
23921        "# abcdefg"
23922    );
23923    assert_eq!(
23924        wrap_with_prefix(
23925            "".to_string(),
23926            "".to_string(),
23927            "\thello world".to_string(),
23928            8,
23929            NonZeroU32::new(4).unwrap(),
23930            false,
23931        ),
23932        "hello\nworld"
23933    );
23934    assert_eq!(
23935        wrap_with_prefix(
23936            "// ".to_string(),
23937            "// ".to_string(),
23938            "xx \nyy zz aa bb cc".to_string(),
23939            12,
23940            NonZeroU32::new(4).unwrap(),
23941            false,
23942        ),
23943        "// xx yy zz\n// aa bb cc"
23944    );
23945    assert_eq!(
23946        wrap_with_prefix(
23947            String::new(),
23948            String::new(),
23949            "这是什么 \n 钢笔".to_string(),
23950            3,
23951            NonZeroU32::new(4).unwrap(),
23952            false,
23953        ),
23954        "这是什\n么 钢\n"
23955    );
23956    assert_eq!(
23957        wrap_with_prefix(
23958            String::new(),
23959            String::new(),
23960            format!("foo{}bar", '\u{2009}'), // thin space
23961            80,
23962            NonZeroU32::new(4).unwrap(),
23963            false,
23964        ),
23965        format!("foo{}bar", '\u{2009}')
23966    );
23967}
23968
23969pub trait CollaborationHub {
23970    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23971    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23972    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23973}
23974
23975impl CollaborationHub for Entity<Project> {
23976    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23977        self.read(cx).collaborators()
23978    }
23979
23980    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23981        self.read(cx).user_store().read(cx).participant_indices()
23982    }
23983
23984    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23985        let this = self.read(cx);
23986        let user_ids = this.collaborators().values().map(|c| c.user_id);
23987        this.user_store().read(cx).participant_names(user_ids, cx)
23988    }
23989}
23990
23991pub trait SemanticsProvider {
23992    fn hover(
23993        &self,
23994        buffer: &Entity<Buffer>,
23995        position: text::Anchor,
23996        cx: &mut App,
23997    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23998
23999    fn inline_values(
24000        &self,
24001        buffer_handle: Entity<Buffer>,
24002        range: Range<text::Anchor>,
24003        cx: &mut App,
24004    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24005
24006    fn applicable_inlay_chunks(
24007        &self,
24008        buffer: &Entity<Buffer>,
24009        ranges: &[Range<text::Anchor>],
24010        cx: &mut App,
24011    ) -> Vec<Range<BufferRow>>;
24012
24013    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24014
24015    fn inlay_hints(
24016        &self,
24017        invalidate: InvalidationStrategy,
24018        buffer: Entity<Buffer>,
24019        ranges: Vec<Range<text::Anchor>>,
24020        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24021        cx: &mut App,
24022    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24023
24024    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24025
24026    fn document_highlights(
24027        &self,
24028        buffer: &Entity<Buffer>,
24029        position: text::Anchor,
24030        cx: &mut App,
24031    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24032
24033    fn definitions(
24034        &self,
24035        buffer: &Entity<Buffer>,
24036        position: text::Anchor,
24037        kind: GotoDefinitionKind,
24038        cx: &mut App,
24039    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24040
24041    fn range_for_rename(
24042        &self,
24043        buffer: &Entity<Buffer>,
24044        position: text::Anchor,
24045        cx: &mut App,
24046    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24047
24048    fn perform_rename(
24049        &self,
24050        buffer: &Entity<Buffer>,
24051        position: text::Anchor,
24052        new_name: String,
24053        cx: &mut App,
24054    ) -> Option<Task<Result<ProjectTransaction>>>;
24055}
24056
24057pub trait CompletionProvider {
24058    fn completions(
24059        &self,
24060        excerpt_id: ExcerptId,
24061        buffer: &Entity<Buffer>,
24062        buffer_position: text::Anchor,
24063        trigger: CompletionContext,
24064        window: &mut Window,
24065        cx: &mut Context<Editor>,
24066    ) -> Task<Result<Vec<CompletionResponse>>>;
24067
24068    fn resolve_completions(
24069        &self,
24070        _buffer: Entity<Buffer>,
24071        _completion_indices: Vec<usize>,
24072        _completions: Rc<RefCell<Box<[Completion]>>>,
24073        _cx: &mut Context<Editor>,
24074    ) -> Task<Result<bool>> {
24075        Task::ready(Ok(false))
24076    }
24077
24078    fn apply_additional_edits_for_completion(
24079        &self,
24080        _buffer: Entity<Buffer>,
24081        _completions: Rc<RefCell<Box<[Completion]>>>,
24082        _completion_index: usize,
24083        _push_to_history: bool,
24084        _cx: &mut Context<Editor>,
24085    ) -> Task<Result<Option<language::Transaction>>> {
24086        Task::ready(Ok(None))
24087    }
24088
24089    fn is_completion_trigger(
24090        &self,
24091        buffer: &Entity<Buffer>,
24092        position: language::Anchor,
24093        text: &str,
24094        trigger_in_words: bool,
24095        cx: &mut Context<Editor>,
24096    ) -> bool;
24097
24098    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24099
24100    fn sort_completions(&self) -> bool {
24101        true
24102    }
24103
24104    fn filter_completions(&self) -> bool {
24105        true
24106    }
24107
24108    fn show_snippets(&self) -> bool {
24109        false
24110    }
24111}
24112
24113pub trait CodeActionProvider {
24114    fn id(&self) -> Arc<str>;
24115
24116    fn code_actions(
24117        &self,
24118        buffer: &Entity<Buffer>,
24119        range: Range<text::Anchor>,
24120        window: &mut Window,
24121        cx: &mut App,
24122    ) -> Task<Result<Vec<CodeAction>>>;
24123
24124    fn apply_code_action(
24125        &self,
24126        buffer_handle: Entity<Buffer>,
24127        action: CodeAction,
24128        excerpt_id: ExcerptId,
24129        push_to_history: bool,
24130        window: &mut Window,
24131        cx: &mut App,
24132    ) -> Task<Result<ProjectTransaction>>;
24133}
24134
24135impl CodeActionProvider for Entity<Project> {
24136    fn id(&self) -> Arc<str> {
24137        "project".into()
24138    }
24139
24140    fn code_actions(
24141        &self,
24142        buffer: &Entity<Buffer>,
24143        range: Range<text::Anchor>,
24144        _window: &mut Window,
24145        cx: &mut App,
24146    ) -> Task<Result<Vec<CodeAction>>> {
24147        self.update(cx, |project, cx| {
24148            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24149            let code_actions = project.code_actions(buffer, range, None, cx);
24150            cx.background_spawn(async move {
24151                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24152                Ok(code_lens_actions
24153                    .context("code lens fetch")?
24154                    .into_iter()
24155                    .flatten()
24156                    .chain(
24157                        code_actions
24158                            .context("code action fetch")?
24159                            .into_iter()
24160                            .flatten(),
24161                    )
24162                    .collect())
24163            })
24164        })
24165    }
24166
24167    fn apply_code_action(
24168        &self,
24169        buffer_handle: Entity<Buffer>,
24170        action: CodeAction,
24171        _excerpt_id: ExcerptId,
24172        push_to_history: bool,
24173        _window: &mut Window,
24174        cx: &mut App,
24175    ) -> Task<Result<ProjectTransaction>> {
24176        self.update(cx, |project, cx| {
24177            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24178        })
24179    }
24180}
24181
24182fn snippet_completions(
24183    project: &Project,
24184    buffer: &Entity<Buffer>,
24185    buffer_anchor: text::Anchor,
24186    classifier: CharClassifier,
24187    cx: &mut App,
24188) -> Task<Result<CompletionResponse>> {
24189    let languages = buffer.read(cx).languages_at(buffer_anchor);
24190    let snippet_store = project.snippets().read(cx);
24191
24192    let scopes: Vec<_> = languages
24193        .iter()
24194        .filter_map(|language| {
24195            let language_name = language.lsp_id();
24196            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24197
24198            if snippets.is_empty() {
24199                None
24200            } else {
24201                Some((language.default_scope(), snippets))
24202            }
24203        })
24204        .collect();
24205
24206    if scopes.is_empty() {
24207        return Task::ready(Ok(CompletionResponse {
24208            completions: vec![],
24209            display_options: CompletionDisplayOptions::default(),
24210            is_incomplete: false,
24211        }));
24212    }
24213
24214    let snapshot = buffer.read(cx).text_snapshot();
24215    let executor = cx.background_executor().clone();
24216
24217    cx.background_spawn(async move {
24218        let is_word_char = |c| classifier.is_word(c);
24219
24220        let mut is_incomplete = false;
24221        let mut completions: Vec<Completion> = Vec::new();
24222
24223        const MAX_PREFIX_LEN: usize = 128;
24224        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24225        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24226        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24227
24228        let max_buffer_window: String = snapshot
24229            .text_for_range(window_start..buffer_offset)
24230            .collect();
24231
24232        if max_buffer_window.is_empty() {
24233            return Ok(CompletionResponse {
24234                completions: vec![],
24235                display_options: CompletionDisplayOptions::default(),
24236                is_incomplete: true,
24237            });
24238        }
24239
24240        for (_scope, snippets) in scopes.into_iter() {
24241            // Sort snippets by word count to match longer snippet prefixes first.
24242            let mut sorted_snippet_candidates = snippets
24243                .iter()
24244                .enumerate()
24245                .flat_map(|(snippet_ix, snippet)| {
24246                    snippet
24247                        .prefix
24248                        .iter()
24249                        .enumerate()
24250                        .map(move |(prefix_ix, prefix)| {
24251                            let word_count =
24252                                snippet_candidate_suffixes(prefix, is_word_char).count();
24253                            ((snippet_ix, prefix_ix), prefix, word_count)
24254                        })
24255                })
24256                .collect_vec();
24257            sorted_snippet_candidates
24258                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24259
24260            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24261
24262            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24263                .take(
24264                    sorted_snippet_candidates
24265                        .first()
24266                        .map(|(_, _, word_count)| *word_count)
24267                        .unwrap_or_default(),
24268                )
24269                .collect_vec();
24270
24271            const MAX_RESULTS: usize = 100;
24272            // Each match also remembers how many characters from the buffer it consumed
24273            let mut matches: Vec<(StringMatch, usize)> = vec![];
24274
24275            let mut snippet_list_cutoff_index = 0;
24276            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24277                let word_count = buffer_index + 1;
24278                // Increase `snippet_list_cutoff_index` until we have all of the
24279                // snippets with sufficiently many words.
24280                while sorted_snippet_candidates
24281                    .get(snippet_list_cutoff_index)
24282                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24283                        *snippet_word_count >= word_count
24284                    })
24285                {
24286                    snippet_list_cutoff_index += 1;
24287                }
24288
24289                // Take only the candidates with at least `word_count` many words
24290                let snippet_candidates_at_word_len =
24291                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24292
24293                let candidates = snippet_candidates_at_word_len
24294                    .iter()
24295                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24296                    .enumerate() // index in `sorted_snippet_candidates`
24297                    // First char must match
24298                    .filter(|(_ix, prefix)| {
24299                        itertools::equal(
24300                            prefix
24301                                .chars()
24302                                .next()
24303                                .into_iter()
24304                                .flat_map(|c| c.to_lowercase()),
24305                            buffer_window
24306                                .chars()
24307                                .next()
24308                                .into_iter()
24309                                .flat_map(|c| c.to_lowercase()),
24310                        )
24311                    })
24312                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24313                    .collect::<Vec<StringMatchCandidate>>();
24314
24315                matches.extend(
24316                    fuzzy::match_strings(
24317                        &candidates,
24318                        &buffer_window,
24319                        buffer_window.chars().any(|c| c.is_uppercase()),
24320                        true,
24321                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24322                        &Default::default(),
24323                        executor.clone(),
24324                    )
24325                    .await
24326                    .into_iter()
24327                    .map(|string_match| (string_match, buffer_window.len())),
24328                );
24329
24330                if matches.len() >= MAX_RESULTS {
24331                    break;
24332                }
24333            }
24334
24335            let to_lsp = |point: &text::Anchor| {
24336                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24337                point_to_lsp(end)
24338            };
24339            let lsp_end = to_lsp(&buffer_anchor);
24340
24341            if matches.len() >= MAX_RESULTS {
24342                is_incomplete = true;
24343            }
24344
24345            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24346                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24347                    sorted_snippet_candidates[string_match.candidate_id];
24348                let snippet = &snippets[snippet_index];
24349                let start = buffer_offset - buffer_window_len;
24350                let start = snapshot.anchor_before(start);
24351                let range = start..buffer_anchor;
24352                let lsp_start = to_lsp(&start);
24353                let lsp_range = lsp::Range {
24354                    start: lsp_start,
24355                    end: lsp_end,
24356                };
24357                Completion {
24358                    replace_range: range,
24359                    new_text: snippet.body.clone(),
24360                    source: CompletionSource::Lsp {
24361                        insert_range: None,
24362                        server_id: LanguageServerId(usize::MAX),
24363                        resolved: true,
24364                        lsp_completion: Box::new(lsp::CompletionItem {
24365                            label: snippet.prefix.first().unwrap().clone(),
24366                            kind: Some(CompletionItemKind::SNIPPET),
24367                            label_details: snippet.description.as_ref().map(|description| {
24368                                lsp::CompletionItemLabelDetails {
24369                                    detail: Some(description.clone()),
24370                                    description: None,
24371                                }
24372                            }),
24373                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24374                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24375                                lsp::InsertReplaceEdit {
24376                                    new_text: snippet.body.clone(),
24377                                    insert: lsp_range,
24378                                    replace: lsp_range,
24379                                },
24380                            )),
24381                            filter_text: Some(snippet.body.clone()),
24382                            sort_text: Some(char::MAX.to_string()),
24383                            ..lsp::CompletionItem::default()
24384                        }),
24385                        lsp_defaults: None,
24386                    },
24387                    label: CodeLabel {
24388                        text: matching_prefix.clone(),
24389                        runs: Vec::new(),
24390                        filter_range: 0..matching_prefix.len(),
24391                    },
24392                    icon_path: None,
24393                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24394                        single_line: snippet.name.clone().into(),
24395                        plain_text: snippet
24396                            .description
24397                            .clone()
24398                            .map(|description| description.into()),
24399                    }),
24400                    insert_text_mode: None,
24401                    confirm: None,
24402                    match_start: Some(start),
24403                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24404                }
24405            }));
24406        }
24407
24408        Ok(CompletionResponse {
24409            completions,
24410            display_options: CompletionDisplayOptions::default(),
24411            is_incomplete,
24412        })
24413    })
24414}
24415
24416impl CompletionProvider for Entity<Project> {
24417    fn completions(
24418        &self,
24419        _excerpt_id: ExcerptId,
24420        buffer: &Entity<Buffer>,
24421        buffer_position: text::Anchor,
24422        options: CompletionContext,
24423        _window: &mut Window,
24424        cx: &mut Context<Editor>,
24425    ) -> Task<Result<Vec<CompletionResponse>>> {
24426        self.update(cx, |project, cx| {
24427            let task = project.completions(buffer, buffer_position, options, cx);
24428            cx.background_spawn(task)
24429        })
24430    }
24431
24432    fn resolve_completions(
24433        &self,
24434        buffer: Entity<Buffer>,
24435        completion_indices: Vec<usize>,
24436        completions: Rc<RefCell<Box<[Completion]>>>,
24437        cx: &mut Context<Editor>,
24438    ) -> Task<Result<bool>> {
24439        self.update(cx, |project, cx| {
24440            project.lsp_store().update(cx, |lsp_store, cx| {
24441                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24442            })
24443        })
24444    }
24445
24446    fn apply_additional_edits_for_completion(
24447        &self,
24448        buffer: Entity<Buffer>,
24449        completions: Rc<RefCell<Box<[Completion]>>>,
24450        completion_index: usize,
24451        push_to_history: bool,
24452        cx: &mut Context<Editor>,
24453    ) -> Task<Result<Option<language::Transaction>>> {
24454        self.update(cx, |project, cx| {
24455            project.lsp_store().update(cx, |lsp_store, cx| {
24456                lsp_store.apply_additional_edits_for_completion(
24457                    buffer,
24458                    completions,
24459                    completion_index,
24460                    push_to_history,
24461                    cx,
24462                )
24463            })
24464        })
24465    }
24466
24467    fn is_completion_trigger(
24468        &self,
24469        buffer: &Entity<Buffer>,
24470        position: language::Anchor,
24471        text: &str,
24472        trigger_in_words: bool,
24473        cx: &mut Context<Editor>,
24474    ) -> bool {
24475        let mut chars = text.chars();
24476        let char = if let Some(char) = chars.next() {
24477            char
24478        } else {
24479            return false;
24480        };
24481        if chars.next().is_some() {
24482            return false;
24483        }
24484
24485        let buffer = buffer.read(cx);
24486        let snapshot = buffer.snapshot();
24487        let classifier = snapshot
24488            .char_classifier_at(position)
24489            .scope_context(Some(CharScopeContext::Completion));
24490        if trigger_in_words && classifier.is_word(char) {
24491            return true;
24492        }
24493
24494        buffer.completion_triggers().contains(text)
24495    }
24496
24497    fn show_snippets(&self) -> bool {
24498        true
24499    }
24500}
24501
24502impl SemanticsProvider for Entity<Project> {
24503    fn hover(
24504        &self,
24505        buffer: &Entity<Buffer>,
24506        position: text::Anchor,
24507        cx: &mut App,
24508    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24509        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24510    }
24511
24512    fn document_highlights(
24513        &self,
24514        buffer: &Entity<Buffer>,
24515        position: text::Anchor,
24516        cx: &mut App,
24517    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24518        Some(self.update(cx, |project, cx| {
24519            project.document_highlights(buffer, position, cx)
24520        }))
24521    }
24522
24523    fn definitions(
24524        &self,
24525        buffer: &Entity<Buffer>,
24526        position: text::Anchor,
24527        kind: GotoDefinitionKind,
24528        cx: &mut App,
24529    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24530        Some(self.update(cx, |project, cx| match kind {
24531            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24532            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24533            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24534            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24535        }))
24536    }
24537
24538    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24539        self.update(cx, |project, cx| {
24540            if project
24541                .active_debug_session(cx)
24542                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24543            {
24544                return true;
24545            }
24546
24547            buffer.update(cx, |buffer, cx| {
24548                project.any_language_server_supports_inlay_hints(buffer, cx)
24549            })
24550        })
24551    }
24552
24553    fn inline_values(
24554        &self,
24555        buffer_handle: Entity<Buffer>,
24556        range: Range<text::Anchor>,
24557        cx: &mut App,
24558    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24559        self.update(cx, |project, cx| {
24560            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24561
24562            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24563        })
24564    }
24565
24566    fn applicable_inlay_chunks(
24567        &self,
24568        buffer: &Entity<Buffer>,
24569        ranges: &[Range<text::Anchor>],
24570        cx: &mut App,
24571    ) -> Vec<Range<BufferRow>> {
24572        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24573            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24574        })
24575    }
24576
24577    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24578        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24579            lsp_store.invalidate_inlay_hints(for_buffers)
24580        });
24581    }
24582
24583    fn inlay_hints(
24584        &self,
24585        invalidate: InvalidationStrategy,
24586        buffer: Entity<Buffer>,
24587        ranges: Vec<Range<text::Anchor>>,
24588        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24589        cx: &mut App,
24590    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24591        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24592            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24593        }))
24594    }
24595
24596    fn range_for_rename(
24597        &self,
24598        buffer: &Entity<Buffer>,
24599        position: text::Anchor,
24600        cx: &mut App,
24601    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24602        Some(self.update(cx, |project, cx| {
24603            let buffer = buffer.clone();
24604            let task = project.prepare_rename(buffer.clone(), position, cx);
24605            cx.spawn(async move |_, cx| {
24606                Ok(match task.await? {
24607                    PrepareRenameResponse::Success(range) => Some(range),
24608                    PrepareRenameResponse::InvalidPosition => None,
24609                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24610                        // Fallback on using TreeSitter info to determine identifier range
24611                        buffer.read_with(cx, |buffer, _| {
24612                            let snapshot = buffer.snapshot();
24613                            let (range, kind) = snapshot.surrounding_word(position, None);
24614                            if kind != Some(CharKind::Word) {
24615                                return None;
24616                            }
24617                            Some(
24618                                snapshot.anchor_before(range.start)
24619                                    ..snapshot.anchor_after(range.end),
24620                            )
24621                        })?
24622                    }
24623                })
24624            })
24625        }))
24626    }
24627
24628    fn perform_rename(
24629        &self,
24630        buffer: &Entity<Buffer>,
24631        position: text::Anchor,
24632        new_name: String,
24633        cx: &mut App,
24634    ) -> Option<Task<Result<ProjectTransaction>>> {
24635        Some(self.update(cx, |project, cx| {
24636            project.perform_rename(buffer.clone(), position, new_name, cx)
24637        }))
24638    }
24639}
24640
24641fn consume_contiguous_rows(
24642    contiguous_row_selections: &mut Vec<Selection<Point>>,
24643    selection: &Selection<Point>,
24644    display_map: &DisplaySnapshot,
24645    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24646) -> (MultiBufferRow, MultiBufferRow) {
24647    contiguous_row_selections.push(selection.clone());
24648    let start_row = starting_row(selection, display_map);
24649    let mut end_row = ending_row(selection, display_map);
24650
24651    while let Some(next_selection) = selections.peek() {
24652        if next_selection.start.row <= end_row.0 {
24653            end_row = ending_row(next_selection, display_map);
24654            contiguous_row_selections.push(selections.next().unwrap().clone());
24655        } else {
24656            break;
24657        }
24658    }
24659    (start_row, end_row)
24660}
24661
24662fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24663    if selection.start.column > 0 {
24664        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24665    } else {
24666        MultiBufferRow(selection.start.row)
24667    }
24668}
24669
24670fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24671    if next_selection.end.column > 0 || next_selection.is_empty() {
24672        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24673    } else {
24674        MultiBufferRow(next_selection.end.row)
24675    }
24676}
24677
24678impl EditorSnapshot {
24679    pub fn remote_selections_in_range<'a>(
24680        &'a self,
24681        range: &'a Range<Anchor>,
24682        collaboration_hub: &dyn CollaborationHub,
24683        cx: &'a App,
24684    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24685        let participant_names = collaboration_hub.user_names(cx);
24686        let participant_indices = collaboration_hub.user_participant_indices(cx);
24687        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24688        let collaborators_by_replica_id = collaborators_by_peer_id
24689            .values()
24690            .map(|collaborator| (collaborator.replica_id, collaborator))
24691            .collect::<HashMap<_, _>>();
24692        self.buffer_snapshot()
24693            .selections_in_range(range, false)
24694            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24695                if replica_id == ReplicaId::AGENT {
24696                    Some(RemoteSelection {
24697                        replica_id,
24698                        selection,
24699                        cursor_shape,
24700                        line_mode,
24701                        collaborator_id: CollaboratorId::Agent,
24702                        user_name: Some("Agent".into()),
24703                        color: cx.theme().players().agent(),
24704                    })
24705                } else {
24706                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24707                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24708                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24709                    Some(RemoteSelection {
24710                        replica_id,
24711                        selection,
24712                        cursor_shape,
24713                        line_mode,
24714                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24715                        user_name,
24716                        color: if let Some(index) = participant_index {
24717                            cx.theme().players().color_for_participant(index.0)
24718                        } else {
24719                            cx.theme().players().absent()
24720                        },
24721                    })
24722                }
24723            })
24724    }
24725
24726    pub fn hunks_for_ranges(
24727        &self,
24728        ranges: impl IntoIterator<Item = Range<Point>>,
24729    ) -> Vec<MultiBufferDiffHunk> {
24730        let mut hunks = Vec::new();
24731        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24732            HashMap::default();
24733        for query_range in ranges {
24734            let query_rows =
24735                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24736            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24737                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24738            ) {
24739                // Include deleted hunks that are adjacent to the query range, because
24740                // otherwise they would be missed.
24741                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24742                if hunk.status().is_deleted() {
24743                    intersects_range |= hunk.row_range.start == query_rows.end;
24744                    intersects_range |= hunk.row_range.end == query_rows.start;
24745                }
24746                if intersects_range {
24747                    if !processed_buffer_rows
24748                        .entry(hunk.buffer_id)
24749                        .or_default()
24750                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24751                    {
24752                        continue;
24753                    }
24754                    hunks.push(hunk);
24755                }
24756            }
24757        }
24758
24759        hunks
24760    }
24761
24762    fn display_diff_hunks_for_rows<'a>(
24763        &'a self,
24764        display_rows: Range<DisplayRow>,
24765        folded_buffers: &'a HashSet<BufferId>,
24766    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24767        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24768        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24769
24770        self.buffer_snapshot()
24771            .diff_hunks_in_range(buffer_start..buffer_end)
24772            .filter_map(|hunk| {
24773                if folded_buffers.contains(&hunk.buffer_id) {
24774                    return None;
24775                }
24776
24777                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24778                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24779
24780                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24781                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24782
24783                let display_hunk = if hunk_display_start.column() != 0 {
24784                    DisplayDiffHunk::Folded {
24785                        display_row: hunk_display_start.row(),
24786                    }
24787                } else {
24788                    let mut end_row = hunk_display_end.row();
24789                    if hunk_display_end.column() > 0 {
24790                        end_row.0 += 1;
24791                    }
24792                    let is_created_file = hunk.is_created_file();
24793
24794                    DisplayDiffHunk::Unfolded {
24795                        status: hunk.status(),
24796                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24797                            ..hunk.diff_base_byte_range.end.0,
24798                        word_diffs: hunk.word_diffs,
24799                        display_row_range: hunk_display_start.row()..end_row,
24800                        multi_buffer_range: Anchor::range_in_buffer(
24801                            hunk.excerpt_id,
24802                            hunk.buffer_range,
24803                        ),
24804                        is_created_file,
24805                    }
24806                };
24807
24808                Some(display_hunk)
24809            })
24810    }
24811
24812    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24813        self.display_snapshot
24814            .buffer_snapshot()
24815            .language_at(position)
24816    }
24817
24818    pub fn is_focused(&self) -> bool {
24819        self.is_focused
24820    }
24821
24822    pub fn placeholder_text(&self) -> Option<String> {
24823        self.placeholder_display_snapshot
24824            .as_ref()
24825            .map(|display_map| display_map.text())
24826    }
24827
24828    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24829        self.scroll_anchor.scroll_position(&self.display_snapshot)
24830    }
24831
24832    pub fn gutter_dimensions(
24833        &self,
24834        font_id: FontId,
24835        font_size: Pixels,
24836        style: &EditorStyle,
24837        window: &mut Window,
24838        cx: &App,
24839    ) -> GutterDimensions {
24840        if self.show_gutter
24841            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24842            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24843        {
24844            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24845                matches!(
24846                    ProjectSettings::get_global(cx).git.git_gutter,
24847                    GitGutterSetting::TrackedFiles
24848                )
24849            });
24850            let gutter_settings = EditorSettings::get_global(cx).gutter;
24851            let show_line_numbers = self
24852                .show_line_numbers
24853                .unwrap_or(gutter_settings.line_numbers);
24854            let line_gutter_width = if show_line_numbers {
24855                // Avoid flicker-like gutter resizes when the line number gains another digit by
24856                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24857                let min_width_for_number_on_gutter =
24858                    ch_advance * gutter_settings.min_line_number_digits as f32;
24859                self.max_line_number_width(style, window)
24860                    .max(min_width_for_number_on_gutter)
24861            } else {
24862                0.0.into()
24863            };
24864
24865            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24866            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24867
24868            let git_blame_entries_width =
24869                self.git_blame_gutter_max_author_length
24870                    .map(|max_author_length| {
24871                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24872                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24873
24874                        /// The number of characters to dedicate to gaps and margins.
24875                        const SPACING_WIDTH: usize = 4;
24876
24877                        let max_char_count = max_author_length.min(renderer.max_author_length())
24878                            + ::git::SHORT_SHA_LENGTH
24879                            + MAX_RELATIVE_TIMESTAMP.len()
24880                            + SPACING_WIDTH;
24881
24882                        ch_advance * max_char_count
24883                    });
24884
24885            let is_singleton = self.buffer_snapshot().is_singleton();
24886
24887            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24888            left_padding += if !is_singleton {
24889                ch_width * 4.0
24890            } else if show_runnables || show_breakpoints {
24891                ch_width * 3.0
24892            } else if show_git_gutter && show_line_numbers {
24893                ch_width * 2.0
24894            } else if show_git_gutter || show_line_numbers {
24895                ch_width
24896            } else {
24897                px(0.)
24898            };
24899
24900            let shows_folds = is_singleton && gutter_settings.folds;
24901
24902            let right_padding = if shows_folds && show_line_numbers {
24903                ch_width * 4.0
24904            } else if shows_folds || (!is_singleton && show_line_numbers) {
24905                ch_width * 3.0
24906            } else if show_line_numbers {
24907                ch_width
24908            } else {
24909                px(0.)
24910            };
24911
24912            GutterDimensions {
24913                left_padding,
24914                right_padding,
24915                width: line_gutter_width + left_padding + right_padding,
24916                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24917                git_blame_entries_width,
24918            }
24919        } else if self.offset_content {
24920            GutterDimensions::default_with_margin(font_id, font_size, cx)
24921        } else {
24922            GutterDimensions::default()
24923        }
24924    }
24925
24926    pub fn render_crease_toggle(
24927        &self,
24928        buffer_row: MultiBufferRow,
24929        row_contains_cursor: bool,
24930        editor: Entity<Editor>,
24931        window: &mut Window,
24932        cx: &mut App,
24933    ) -> Option<AnyElement> {
24934        let folded = self.is_line_folded(buffer_row);
24935        let mut is_foldable = false;
24936
24937        if let Some(crease) = self
24938            .crease_snapshot
24939            .query_row(buffer_row, self.buffer_snapshot())
24940        {
24941            is_foldable = true;
24942            match crease {
24943                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24944                    if let Some(render_toggle) = render_toggle {
24945                        let toggle_callback =
24946                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24947                                if folded {
24948                                    editor.update(cx, |editor, cx| {
24949                                        editor.fold_at(buffer_row, window, cx)
24950                                    });
24951                                } else {
24952                                    editor.update(cx, |editor, cx| {
24953                                        editor.unfold_at(buffer_row, window, cx)
24954                                    });
24955                                }
24956                            });
24957                        return Some((render_toggle)(
24958                            buffer_row,
24959                            folded,
24960                            toggle_callback,
24961                            window,
24962                            cx,
24963                        ));
24964                    }
24965                }
24966            }
24967        }
24968
24969        is_foldable |= self.starts_indent(buffer_row);
24970
24971        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24972            Some(
24973                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24974                    .toggle_state(folded)
24975                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24976                        if folded {
24977                            this.unfold_at(buffer_row, window, cx);
24978                        } else {
24979                            this.fold_at(buffer_row, window, cx);
24980                        }
24981                    }))
24982                    .into_any_element(),
24983            )
24984        } else {
24985            None
24986        }
24987    }
24988
24989    pub fn render_crease_trailer(
24990        &self,
24991        buffer_row: MultiBufferRow,
24992        window: &mut Window,
24993        cx: &mut App,
24994    ) -> Option<AnyElement> {
24995        let folded = self.is_line_folded(buffer_row);
24996        if let Crease::Inline { render_trailer, .. } = self
24997            .crease_snapshot
24998            .query_row(buffer_row, self.buffer_snapshot())?
24999        {
25000            let render_trailer = render_trailer.as_ref()?;
25001            Some(render_trailer(buffer_row, folded, window, cx))
25002        } else {
25003            None
25004        }
25005    }
25006
25007    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25008        let digit_count = self.widest_line_number().ilog10() + 1;
25009        column_pixels(style, digit_count as usize, window)
25010    }
25011}
25012
25013pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25014    let font_size = style.text.font_size.to_pixels(window.rem_size());
25015    let layout = window.text_system().shape_line(
25016        SharedString::from(" ".repeat(column)),
25017        font_size,
25018        &[TextRun {
25019            len: column,
25020            font: style.text.font(),
25021            color: Hsla::default(),
25022            ..Default::default()
25023        }],
25024        None,
25025    );
25026
25027    layout.width
25028}
25029
25030impl Deref for EditorSnapshot {
25031    type Target = DisplaySnapshot;
25032
25033    fn deref(&self) -> &Self::Target {
25034        &self.display_snapshot
25035    }
25036}
25037
25038#[derive(Clone, Debug, PartialEq, Eq)]
25039pub enum EditorEvent {
25040    InputIgnored {
25041        text: Arc<str>,
25042    },
25043    InputHandled {
25044        utf16_range_to_replace: Option<Range<isize>>,
25045        text: Arc<str>,
25046    },
25047    ExcerptsAdded {
25048        buffer: Entity<Buffer>,
25049        predecessor: ExcerptId,
25050        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25051    },
25052    ExcerptsRemoved {
25053        ids: Vec<ExcerptId>,
25054        removed_buffer_ids: Vec<BufferId>,
25055    },
25056    BufferFoldToggled {
25057        ids: Vec<ExcerptId>,
25058        folded: bool,
25059    },
25060    ExcerptsEdited {
25061        ids: Vec<ExcerptId>,
25062    },
25063    ExcerptsExpanded {
25064        ids: Vec<ExcerptId>,
25065    },
25066    BufferEdited,
25067    Edited {
25068        transaction_id: clock::Lamport,
25069    },
25070    Reparsed(BufferId),
25071    Focused,
25072    FocusedIn,
25073    Blurred,
25074    DirtyChanged,
25075    Saved,
25076    TitleChanged,
25077    SelectionsChanged {
25078        local: bool,
25079    },
25080    ScrollPositionChanged {
25081        local: bool,
25082        autoscroll: bool,
25083    },
25084    TransactionUndone {
25085        transaction_id: clock::Lamport,
25086    },
25087    TransactionBegun {
25088        transaction_id: clock::Lamport,
25089    },
25090    CursorShapeChanged,
25091    BreadcrumbsChanged,
25092    PushedToNavHistory {
25093        anchor: Anchor,
25094        is_deactivate: bool,
25095    },
25096}
25097
25098impl EventEmitter<EditorEvent> for Editor {}
25099
25100impl Focusable for Editor {
25101    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25102        self.focus_handle.clone()
25103    }
25104}
25105
25106impl Render for Editor {
25107    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25108        EditorElement::new(&cx.entity(), self.create_style(cx))
25109    }
25110}
25111
25112impl EntityInputHandler for Editor {
25113    fn text_for_range(
25114        &mut self,
25115        range_utf16: Range<usize>,
25116        adjusted_range: &mut Option<Range<usize>>,
25117        _: &mut Window,
25118        cx: &mut Context<Self>,
25119    ) -> Option<String> {
25120        let snapshot = self.buffer.read(cx).read(cx);
25121        let start = snapshot.clip_offset_utf16(
25122            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25123            Bias::Left,
25124        );
25125        let end = snapshot.clip_offset_utf16(
25126            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25127            Bias::Right,
25128        );
25129        if (start.0.0..end.0.0) != range_utf16 {
25130            adjusted_range.replace(start.0.0..end.0.0);
25131        }
25132        Some(snapshot.text_for_range(start..end).collect())
25133    }
25134
25135    fn selected_text_range(
25136        &mut self,
25137        ignore_disabled_input: bool,
25138        _: &mut Window,
25139        cx: &mut Context<Self>,
25140    ) -> Option<UTF16Selection> {
25141        // Prevent the IME menu from appearing when holding down an alphabetic key
25142        // while input is disabled.
25143        if !ignore_disabled_input && !self.input_enabled {
25144            return None;
25145        }
25146
25147        let selection = self
25148            .selections
25149            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25150        let range = selection.range();
25151
25152        Some(UTF16Selection {
25153            range: range.start.0.0..range.end.0.0,
25154            reversed: selection.reversed,
25155        })
25156    }
25157
25158    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25159        let snapshot = self.buffer.read(cx).read(cx);
25160        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25161        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25162    }
25163
25164    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25165        self.clear_highlights::<InputComposition>(cx);
25166        self.ime_transaction.take();
25167    }
25168
25169    fn replace_text_in_range(
25170        &mut self,
25171        range_utf16: Option<Range<usize>>,
25172        text: &str,
25173        window: &mut Window,
25174        cx: &mut Context<Self>,
25175    ) {
25176        if !self.input_enabled {
25177            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25178            return;
25179        }
25180
25181        self.transact(window, cx, |this, window, cx| {
25182            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25183                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25184                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25185                Some(this.selection_replacement_ranges(range_utf16, cx))
25186            } else {
25187                this.marked_text_ranges(cx)
25188            };
25189
25190            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25191                let newest_selection_id = this.selections.newest_anchor().id;
25192                this.selections
25193                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25194                    .iter()
25195                    .zip(ranges_to_replace.iter())
25196                    .find_map(|(selection, range)| {
25197                        if selection.id == newest_selection_id {
25198                            Some(
25199                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25200                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25201                            )
25202                        } else {
25203                            None
25204                        }
25205                    })
25206            });
25207
25208            cx.emit(EditorEvent::InputHandled {
25209                utf16_range_to_replace: range_to_replace,
25210                text: text.into(),
25211            });
25212
25213            if let Some(new_selected_ranges) = new_selected_ranges {
25214                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25215                    selections.select_ranges(new_selected_ranges)
25216                });
25217                this.backspace(&Default::default(), window, cx);
25218            }
25219
25220            this.handle_input(text, window, cx);
25221        });
25222
25223        if let Some(transaction) = self.ime_transaction {
25224            self.buffer.update(cx, |buffer, cx| {
25225                buffer.group_until_transaction(transaction, cx);
25226            });
25227        }
25228
25229        self.unmark_text(window, cx);
25230    }
25231
25232    fn replace_and_mark_text_in_range(
25233        &mut self,
25234        range_utf16: Option<Range<usize>>,
25235        text: &str,
25236        new_selected_range_utf16: Option<Range<usize>>,
25237        window: &mut Window,
25238        cx: &mut Context<Self>,
25239    ) {
25240        if !self.input_enabled {
25241            return;
25242        }
25243
25244        let transaction = self.transact(window, cx, |this, window, cx| {
25245            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25246                let snapshot = this.buffer.read(cx).read(cx);
25247                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25248                    for marked_range in &mut marked_ranges {
25249                        marked_range.end = marked_range.start + relative_range_utf16.end;
25250                        marked_range.start += relative_range_utf16.start;
25251                        marked_range.start =
25252                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25253                        marked_range.end =
25254                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25255                    }
25256                }
25257                Some(marked_ranges)
25258            } else if let Some(range_utf16) = range_utf16 {
25259                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25260                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25261                Some(this.selection_replacement_ranges(range_utf16, cx))
25262            } else {
25263                None
25264            };
25265
25266            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25267                let newest_selection_id = this.selections.newest_anchor().id;
25268                this.selections
25269                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25270                    .iter()
25271                    .zip(ranges_to_replace.iter())
25272                    .find_map(|(selection, range)| {
25273                        if selection.id == newest_selection_id {
25274                            Some(
25275                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25276                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25277                            )
25278                        } else {
25279                            None
25280                        }
25281                    })
25282            });
25283
25284            cx.emit(EditorEvent::InputHandled {
25285                utf16_range_to_replace: range_to_replace,
25286                text: text.into(),
25287            });
25288
25289            if let Some(ranges) = ranges_to_replace {
25290                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25291                    s.select_ranges(ranges)
25292                });
25293            }
25294
25295            let marked_ranges = {
25296                let snapshot = this.buffer.read(cx).read(cx);
25297                this.selections
25298                    .disjoint_anchors_arc()
25299                    .iter()
25300                    .map(|selection| {
25301                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25302                    })
25303                    .collect::<Vec<_>>()
25304            };
25305
25306            if text.is_empty() {
25307                this.unmark_text(window, cx);
25308            } else {
25309                this.highlight_text::<InputComposition>(
25310                    marked_ranges.clone(),
25311                    HighlightStyle {
25312                        underline: Some(UnderlineStyle {
25313                            thickness: px(1.),
25314                            color: None,
25315                            wavy: false,
25316                        }),
25317                        ..Default::default()
25318                    },
25319                    cx,
25320                );
25321            }
25322
25323            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25324            let use_autoclose = this.use_autoclose;
25325            let use_auto_surround = this.use_auto_surround;
25326            this.set_use_autoclose(false);
25327            this.set_use_auto_surround(false);
25328            this.handle_input(text, window, cx);
25329            this.set_use_autoclose(use_autoclose);
25330            this.set_use_auto_surround(use_auto_surround);
25331
25332            if let Some(new_selected_range) = new_selected_range_utf16 {
25333                let snapshot = this.buffer.read(cx).read(cx);
25334                let new_selected_ranges = marked_ranges
25335                    .into_iter()
25336                    .map(|marked_range| {
25337                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25338                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25339                            insertion_start.0 + new_selected_range.start,
25340                        ));
25341                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25342                            insertion_start.0 + new_selected_range.end,
25343                        ));
25344                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25345                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25346                    })
25347                    .collect::<Vec<_>>();
25348
25349                drop(snapshot);
25350                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25351                    selections.select_ranges(new_selected_ranges)
25352                });
25353            }
25354        });
25355
25356        self.ime_transaction = self.ime_transaction.or(transaction);
25357        if let Some(transaction) = self.ime_transaction {
25358            self.buffer.update(cx, |buffer, cx| {
25359                buffer.group_until_transaction(transaction, cx);
25360            });
25361        }
25362
25363        if self.text_highlights::<InputComposition>(cx).is_none() {
25364            self.ime_transaction.take();
25365        }
25366    }
25367
25368    fn bounds_for_range(
25369        &mut self,
25370        range_utf16: Range<usize>,
25371        element_bounds: gpui::Bounds<Pixels>,
25372        window: &mut Window,
25373        cx: &mut Context<Self>,
25374    ) -> Option<gpui::Bounds<Pixels>> {
25375        let text_layout_details = self.text_layout_details(window);
25376        let CharacterDimensions {
25377            em_width,
25378            em_advance,
25379            line_height,
25380        } = self.character_dimensions(window);
25381
25382        let snapshot = self.snapshot(window, cx);
25383        let scroll_position = snapshot.scroll_position();
25384        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25385
25386        let start =
25387            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25388        let x = Pixels::from(
25389            ScrollOffset::from(
25390                snapshot.x_for_display_point(start, &text_layout_details)
25391                    + self.gutter_dimensions.full_width(),
25392            ) - scroll_left,
25393        );
25394        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25395
25396        Some(Bounds {
25397            origin: element_bounds.origin + point(x, y),
25398            size: size(em_width, line_height),
25399        })
25400    }
25401
25402    fn character_index_for_point(
25403        &mut self,
25404        point: gpui::Point<Pixels>,
25405        _window: &mut Window,
25406        _cx: &mut Context<Self>,
25407    ) -> Option<usize> {
25408        let position_map = self.last_position_map.as_ref()?;
25409        if !position_map.text_hitbox.contains(&point) {
25410            return None;
25411        }
25412        let display_point = position_map.point_for_position(point).previous_valid;
25413        let anchor = position_map
25414            .snapshot
25415            .display_point_to_anchor(display_point, Bias::Left);
25416        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25417        Some(utf16_offset.0.0)
25418    }
25419
25420    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25421        self.input_enabled
25422    }
25423}
25424
25425trait SelectionExt {
25426    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25427    fn spanned_rows(
25428        &self,
25429        include_end_if_at_line_start: bool,
25430        map: &DisplaySnapshot,
25431    ) -> Range<MultiBufferRow>;
25432}
25433
25434impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25435    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25436        let start = self
25437            .start
25438            .to_point(map.buffer_snapshot())
25439            .to_display_point(map);
25440        let end = self
25441            .end
25442            .to_point(map.buffer_snapshot())
25443            .to_display_point(map);
25444        if self.reversed {
25445            end..start
25446        } else {
25447            start..end
25448        }
25449    }
25450
25451    fn spanned_rows(
25452        &self,
25453        include_end_if_at_line_start: bool,
25454        map: &DisplaySnapshot,
25455    ) -> Range<MultiBufferRow> {
25456        let start = self.start.to_point(map.buffer_snapshot());
25457        let mut end = self.end.to_point(map.buffer_snapshot());
25458        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25459            end.row -= 1;
25460        }
25461
25462        let buffer_start = map.prev_line_boundary(start).0;
25463        let buffer_end = map.next_line_boundary(end).0;
25464        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25465    }
25466}
25467
25468impl<T: InvalidationRegion> InvalidationStack<T> {
25469    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25470    where
25471        S: Clone + ToOffset,
25472    {
25473        while let Some(region) = self.last() {
25474            let all_selections_inside_invalidation_ranges =
25475                if selections.len() == region.ranges().len() {
25476                    selections
25477                        .iter()
25478                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25479                        .all(|(selection, invalidation_range)| {
25480                            let head = selection.head().to_offset(buffer);
25481                            invalidation_range.start <= head && invalidation_range.end >= head
25482                        })
25483                } else {
25484                    false
25485                };
25486
25487            if all_selections_inside_invalidation_ranges {
25488                break;
25489            } else {
25490                self.pop();
25491            }
25492        }
25493    }
25494}
25495
25496impl<T> Default for InvalidationStack<T> {
25497    fn default() -> Self {
25498        Self(Default::default())
25499    }
25500}
25501
25502impl<T> Deref for InvalidationStack<T> {
25503    type Target = Vec<T>;
25504
25505    fn deref(&self) -> &Self::Target {
25506        &self.0
25507    }
25508}
25509
25510impl<T> DerefMut for InvalidationStack<T> {
25511    fn deref_mut(&mut self) -> &mut Self::Target {
25512        &mut self.0
25513    }
25514}
25515
25516impl InvalidationRegion for SnippetState {
25517    fn ranges(&self) -> &[Range<Anchor>] {
25518        &self.ranges[self.active_index]
25519    }
25520}
25521
25522fn edit_prediction_edit_text(
25523    current_snapshot: &BufferSnapshot,
25524    edits: &[(Range<Anchor>, impl AsRef<str>)],
25525    edit_preview: &EditPreview,
25526    include_deletions: bool,
25527    cx: &App,
25528) -> HighlightedText {
25529    let edits = edits
25530        .iter()
25531        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25532        .collect::<Vec<_>>();
25533
25534    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25535}
25536
25537fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25538    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25539    // Just show the raw edit text with basic styling
25540    let mut text = String::new();
25541    let mut highlights = Vec::new();
25542
25543    let insertion_highlight_style = HighlightStyle {
25544        color: Some(cx.theme().colors().text),
25545        ..Default::default()
25546    };
25547
25548    for (_, edit_text) in edits {
25549        let start_offset = text.len();
25550        text.push_str(edit_text);
25551        let end_offset = text.len();
25552
25553        if start_offset < end_offset {
25554            highlights.push((start_offset..end_offset, insertion_highlight_style));
25555        }
25556    }
25557
25558    HighlightedText {
25559        text: text.into(),
25560        highlights,
25561    }
25562}
25563
25564pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25565    match severity {
25566        lsp::DiagnosticSeverity::ERROR => colors.error,
25567        lsp::DiagnosticSeverity::WARNING => colors.warning,
25568        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25569        lsp::DiagnosticSeverity::HINT => colors.info,
25570        _ => colors.ignored,
25571    }
25572}
25573
25574pub fn styled_runs_for_code_label<'a>(
25575    label: &'a CodeLabel,
25576    syntax_theme: &'a theme::SyntaxTheme,
25577    local_player: &'a theme::PlayerColor,
25578) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25579    let fade_out = HighlightStyle {
25580        fade_out: Some(0.35),
25581        ..Default::default()
25582    };
25583
25584    let mut prev_end = label.filter_range.end;
25585    label
25586        .runs
25587        .iter()
25588        .enumerate()
25589        .flat_map(move |(ix, (range, highlight_id))| {
25590            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25591                HighlightStyle {
25592                    color: Some(local_player.cursor),
25593                    ..Default::default()
25594                }
25595            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25596                HighlightStyle {
25597                    background_color: Some(local_player.selection),
25598                    ..Default::default()
25599                }
25600            } else if let Some(style) = highlight_id.style(syntax_theme) {
25601                style
25602            } else {
25603                return Default::default();
25604            };
25605            let muted_style = style.highlight(fade_out);
25606
25607            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25608            if range.start >= label.filter_range.end {
25609                if range.start > prev_end {
25610                    runs.push((prev_end..range.start, fade_out));
25611                }
25612                runs.push((range.clone(), muted_style));
25613            } else if range.end <= label.filter_range.end {
25614                runs.push((range.clone(), style));
25615            } else {
25616                runs.push((range.start..label.filter_range.end, style));
25617                runs.push((label.filter_range.end..range.end, muted_style));
25618            }
25619            prev_end = cmp::max(prev_end, range.end);
25620
25621            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25622                runs.push((prev_end..label.text.len(), fade_out));
25623            }
25624
25625            runs
25626        })
25627}
25628
25629pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25630    let mut prev_index = 0;
25631    let mut prev_codepoint: Option<char> = None;
25632    text.char_indices()
25633        .chain([(text.len(), '\0')])
25634        .filter_map(move |(index, codepoint)| {
25635            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25636            let is_boundary = index == text.len()
25637                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25638                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25639            if is_boundary {
25640                let chunk = &text[prev_index..index];
25641                prev_index = index;
25642                Some(chunk)
25643            } else {
25644                None
25645            }
25646        })
25647}
25648
25649/// Given a string of text immediately before the cursor, iterates over possible
25650/// strings a snippet could match to. More precisely: returns an iterator over
25651/// suffixes of `text` created by splitting at word boundaries (before & after
25652/// every non-word character).
25653///
25654/// Shorter suffixes are returned first.
25655pub(crate) fn snippet_candidate_suffixes(
25656    text: &str,
25657    is_word_char: impl Fn(char) -> bool,
25658) -> impl std::iter::Iterator<Item = &str> {
25659    let mut prev_index = text.len();
25660    let mut prev_codepoint = None;
25661    text.char_indices()
25662        .rev()
25663        .chain([(0, '\0')])
25664        .filter_map(move |(index, codepoint)| {
25665            let prev_index = std::mem::replace(&mut prev_index, index);
25666            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25667            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25668                None
25669            } else {
25670                let chunk = &text[prev_index..]; // go to end of string
25671                Some(chunk)
25672            }
25673        })
25674}
25675
25676pub trait RangeToAnchorExt: Sized {
25677    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25678
25679    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25680        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25681        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25682    }
25683}
25684
25685impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25686    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25687        let start_offset = self.start.to_offset(snapshot);
25688        let end_offset = self.end.to_offset(snapshot);
25689        if start_offset == end_offset {
25690            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25691        } else {
25692            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25693        }
25694    }
25695}
25696
25697pub trait RowExt {
25698    fn as_f64(&self) -> f64;
25699
25700    fn next_row(&self) -> Self;
25701
25702    fn previous_row(&self) -> Self;
25703
25704    fn minus(&self, other: Self) -> u32;
25705}
25706
25707impl RowExt for DisplayRow {
25708    fn as_f64(&self) -> f64 {
25709        self.0 as _
25710    }
25711
25712    fn next_row(&self) -> Self {
25713        Self(self.0 + 1)
25714    }
25715
25716    fn previous_row(&self) -> Self {
25717        Self(self.0.saturating_sub(1))
25718    }
25719
25720    fn minus(&self, other: Self) -> u32 {
25721        self.0 - other.0
25722    }
25723}
25724
25725impl RowExt for MultiBufferRow {
25726    fn as_f64(&self) -> f64 {
25727        self.0 as _
25728    }
25729
25730    fn next_row(&self) -> Self {
25731        Self(self.0 + 1)
25732    }
25733
25734    fn previous_row(&self) -> Self {
25735        Self(self.0.saturating_sub(1))
25736    }
25737
25738    fn minus(&self, other: Self) -> u32 {
25739        self.0 - other.0
25740    }
25741}
25742
25743trait RowRangeExt {
25744    type Row;
25745
25746    fn len(&self) -> usize;
25747
25748    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25749}
25750
25751impl RowRangeExt for Range<MultiBufferRow> {
25752    type Row = MultiBufferRow;
25753
25754    fn len(&self) -> usize {
25755        (self.end.0 - self.start.0) as usize
25756    }
25757
25758    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25759        (self.start.0..self.end.0).map(MultiBufferRow)
25760    }
25761}
25762
25763impl RowRangeExt for Range<DisplayRow> {
25764    type Row = DisplayRow;
25765
25766    fn len(&self) -> usize {
25767        (self.end.0 - self.start.0) as usize
25768    }
25769
25770    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25771        (self.start.0..self.end.0).map(DisplayRow)
25772    }
25773}
25774
25775/// If select range has more than one line, we
25776/// just point the cursor to range.start.
25777fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25778    if range.start.row == range.end.row {
25779        range
25780    } else {
25781        range.start..range.start
25782    }
25783}
25784pub struct KillRing(ClipboardItem);
25785impl Global for KillRing {}
25786
25787const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25788
25789enum BreakpointPromptEditAction {
25790    Log,
25791    Condition,
25792    HitCondition,
25793}
25794
25795struct BreakpointPromptEditor {
25796    pub(crate) prompt: Entity<Editor>,
25797    editor: WeakEntity<Editor>,
25798    breakpoint_anchor: Anchor,
25799    breakpoint: Breakpoint,
25800    edit_action: BreakpointPromptEditAction,
25801    block_ids: HashSet<CustomBlockId>,
25802    editor_margins: Arc<Mutex<EditorMargins>>,
25803    _subscriptions: Vec<Subscription>,
25804}
25805
25806impl BreakpointPromptEditor {
25807    const MAX_LINES: u8 = 4;
25808
25809    fn new(
25810        editor: WeakEntity<Editor>,
25811        breakpoint_anchor: Anchor,
25812        breakpoint: Breakpoint,
25813        edit_action: BreakpointPromptEditAction,
25814        window: &mut Window,
25815        cx: &mut Context<Self>,
25816    ) -> Self {
25817        let base_text = match edit_action {
25818            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25819            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25820            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25821        }
25822        .map(|msg| msg.to_string())
25823        .unwrap_or_default();
25824
25825        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25826        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25827
25828        let prompt = cx.new(|cx| {
25829            let mut prompt = Editor::new(
25830                EditorMode::AutoHeight {
25831                    min_lines: 1,
25832                    max_lines: Some(Self::MAX_LINES as usize),
25833                },
25834                buffer,
25835                None,
25836                window,
25837                cx,
25838            );
25839            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25840            prompt.set_show_cursor_when_unfocused(false, cx);
25841            prompt.set_placeholder_text(
25842                match edit_action {
25843                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25844                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25845                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25846                },
25847                window,
25848                cx,
25849            );
25850
25851            prompt
25852        });
25853
25854        Self {
25855            prompt,
25856            editor,
25857            breakpoint_anchor,
25858            breakpoint,
25859            edit_action,
25860            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25861            block_ids: Default::default(),
25862            _subscriptions: vec![],
25863        }
25864    }
25865
25866    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25867        self.block_ids.extend(block_ids)
25868    }
25869
25870    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25871        if let Some(editor) = self.editor.upgrade() {
25872            let message = self
25873                .prompt
25874                .read(cx)
25875                .buffer
25876                .read(cx)
25877                .as_singleton()
25878                .expect("A multi buffer in breakpoint prompt isn't possible")
25879                .read(cx)
25880                .as_rope()
25881                .to_string();
25882
25883            editor.update(cx, |editor, cx| {
25884                editor.edit_breakpoint_at_anchor(
25885                    self.breakpoint_anchor,
25886                    self.breakpoint.clone(),
25887                    match self.edit_action {
25888                        BreakpointPromptEditAction::Log => {
25889                            BreakpointEditAction::EditLogMessage(message.into())
25890                        }
25891                        BreakpointPromptEditAction::Condition => {
25892                            BreakpointEditAction::EditCondition(message.into())
25893                        }
25894                        BreakpointPromptEditAction::HitCondition => {
25895                            BreakpointEditAction::EditHitCondition(message.into())
25896                        }
25897                    },
25898                    cx,
25899                );
25900
25901                editor.remove_blocks(self.block_ids.clone(), None, cx);
25902                cx.focus_self(window);
25903            });
25904        }
25905    }
25906
25907    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25908        self.editor
25909            .update(cx, |editor, cx| {
25910                editor.remove_blocks(self.block_ids.clone(), None, cx);
25911                window.focus(&editor.focus_handle);
25912            })
25913            .log_err();
25914    }
25915
25916    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25917        let settings = ThemeSettings::get_global(cx);
25918        let text_style = TextStyle {
25919            color: if self.prompt.read(cx).read_only(cx) {
25920                cx.theme().colors().text_disabled
25921            } else {
25922                cx.theme().colors().text
25923            },
25924            font_family: settings.buffer_font.family.clone(),
25925            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25926            font_size: settings.buffer_font_size(cx).into(),
25927            font_weight: settings.buffer_font.weight,
25928            line_height: relative(settings.buffer_line_height.value()),
25929            ..Default::default()
25930        };
25931        EditorElement::new(
25932            &self.prompt,
25933            EditorStyle {
25934                background: cx.theme().colors().editor_background,
25935                local_player: cx.theme().players().local(),
25936                text: text_style,
25937                ..Default::default()
25938            },
25939        )
25940    }
25941}
25942
25943impl Render for BreakpointPromptEditor {
25944    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25945        let editor_margins = *self.editor_margins.lock();
25946        let gutter_dimensions = editor_margins.gutter;
25947        h_flex()
25948            .key_context("Editor")
25949            .bg(cx.theme().colors().editor_background)
25950            .border_y_1()
25951            .border_color(cx.theme().status().info_border)
25952            .size_full()
25953            .py(window.line_height() / 2.5)
25954            .on_action(cx.listener(Self::confirm))
25955            .on_action(cx.listener(Self::cancel))
25956            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25957            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25958    }
25959}
25960
25961impl Focusable for BreakpointPromptEditor {
25962    fn focus_handle(&self, cx: &App) -> FocusHandle {
25963        self.prompt.focus_handle(cx)
25964    }
25965}
25966
25967fn all_edits_insertions_or_deletions(
25968    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25969    snapshot: &MultiBufferSnapshot,
25970) -> bool {
25971    let mut all_insertions = true;
25972    let mut all_deletions = true;
25973
25974    for (range, new_text) in edits.iter() {
25975        let range_is_empty = range.to_offset(snapshot).is_empty();
25976        let text_is_empty = new_text.is_empty();
25977
25978        if range_is_empty != text_is_empty {
25979            if range_is_empty {
25980                all_deletions = false;
25981            } else {
25982                all_insertions = false;
25983            }
25984        } else {
25985            return false;
25986        }
25987
25988        if !all_insertions && !all_deletions {
25989            return false;
25990        }
25991    }
25992    all_insertions || all_deletions
25993}
25994
25995struct MissingEditPredictionKeybindingTooltip;
25996
25997impl Render for MissingEditPredictionKeybindingTooltip {
25998    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25999        ui::tooltip_container(cx, |container, cx| {
26000            container
26001                .flex_shrink_0()
26002                .max_w_80()
26003                .min_h(rems_from_px(124.))
26004                .justify_between()
26005                .child(
26006                    v_flex()
26007                        .flex_1()
26008                        .text_ui_sm(cx)
26009                        .child(Label::new("Conflict with Accept Keybinding"))
26010                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26011                )
26012                .child(
26013                    h_flex()
26014                        .pb_1()
26015                        .gap_1()
26016                        .items_end()
26017                        .w_full()
26018                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26019                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26020                        }))
26021                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26022                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26023                        })),
26024                )
26025        })
26026    }
26027}
26028
26029#[derive(Debug, Clone, Copy, PartialEq)]
26030pub struct LineHighlight {
26031    pub background: Background,
26032    pub border: Option<gpui::Hsla>,
26033    pub include_gutter: bool,
26034    pub type_id: Option<TypeId>,
26035}
26036
26037struct LineManipulationResult {
26038    pub new_text: String,
26039    pub line_count_before: usize,
26040    pub line_count_after: usize,
26041}
26042
26043fn render_diff_hunk_controls(
26044    row: u32,
26045    status: &DiffHunkStatus,
26046    hunk_range: Range<Anchor>,
26047    is_created_file: bool,
26048    line_height: Pixels,
26049    editor: &Entity<Editor>,
26050    _window: &mut Window,
26051    cx: &mut App,
26052) -> AnyElement {
26053    h_flex()
26054        .h(line_height)
26055        .mr_1()
26056        .gap_1()
26057        .px_0p5()
26058        .pb_1()
26059        .border_x_1()
26060        .border_b_1()
26061        .border_color(cx.theme().colors().border_variant)
26062        .rounded_b_lg()
26063        .bg(cx.theme().colors().editor_background)
26064        .gap_1()
26065        .block_mouse_except_scroll()
26066        .shadow_md()
26067        .child(if status.has_secondary_hunk() {
26068            Button::new(("stage", row as u64), "Stage")
26069                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26070                .tooltip({
26071                    let focus_handle = editor.focus_handle(cx);
26072                    move |_window, cx| {
26073                        Tooltip::for_action_in(
26074                            "Stage Hunk",
26075                            &::git::ToggleStaged,
26076                            &focus_handle,
26077                            cx,
26078                        )
26079                    }
26080                })
26081                .on_click({
26082                    let editor = editor.clone();
26083                    move |_event, _window, cx| {
26084                        editor.update(cx, |editor, cx| {
26085                            editor.stage_or_unstage_diff_hunks(
26086                                true,
26087                                vec![hunk_range.start..hunk_range.start],
26088                                cx,
26089                            );
26090                        });
26091                    }
26092                })
26093        } else {
26094            Button::new(("unstage", row as u64), "Unstage")
26095                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26096                .tooltip({
26097                    let focus_handle = editor.focus_handle(cx);
26098                    move |_window, cx| {
26099                        Tooltip::for_action_in(
26100                            "Unstage Hunk",
26101                            &::git::ToggleStaged,
26102                            &focus_handle,
26103                            cx,
26104                        )
26105                    }
26106                })
26107                .on_click({
26108                    let editor = editor.clone();
26109                    move |_event, _window, cx| {
26110                        editor.update(cx, |editor, cx| {
26111                            editor.stage_or_unstage_diff_hunks(
26112                                false,
26113                                vec![hunk_range.start..hunk_range.start],
26114                                cx,
26115                            );
26116                        });
26117                    }
26118                })
26119        })
26120        .child(
26121            Button::new(("restore", row as u64), "Restore")
26122                .tooltip({
26123                    let focus_handle = editor.focus_handle(cx);
26124                    move |_window, cx| {
26125                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26126                    }
26127                })
26128                .on_click({
26129                    let editor = editor.clone();
26130                    move |_event, window, cx| {
26131                        editor.update(cx, |editor, cx| {
26132                            let snapshot = editor.snapshot(window, cx);
26133                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26134                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26135                        });
26136                    }
26137                })
26138                .disabled(is_created_file),
26139        )
26140        .when(
26141            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26142            |el| {
26143                el.child(
26144                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26145                        .shape(IconButtonShape::Square)
26146                        .icon_size(IconSize::Small)
26147                        // .disabled(!has_multiple_hunks)
26148                        .tooltip({
26149                            let focus_handle = editor.focus_handle(cx);
26150                            move |_window, cx| {
26151                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26152                            }
26153                        })
26154                        .on_click({
26155                            let editor = editor.clone();
26156                            move |_event, window, cx| {
26157                                editor.update(cx, |editor, cx| {
26158                                    let snapshot = editor.snapshot(window, cx);
26159                                    let position =
26160                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26161                                    editor.go_to_hunk_before_or_after_position(
26162                                        &snapshot,
26163                                        position,
26164                                        Direction::Next,
26165                                        window,
26166                                        cx,
26167                                    );
26168                                    editor.expand_selected_diff_hunks(cx);
26169                                });
26170                            }
26171                        }),
26172                )
26173                .child(
26174                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26175                        .shape(IconButtonShape::Square)
26176                        .icon_size(IconSize::Small)
26177                        // .disabled(!has_multiple_hunks)
26178                        .tooltip({
26179                            let focus_handle = editor.focus_handle(cx);
26180                            move |_window, cx| {
26181                                Tooltip::for_action_in(
26182                                    "Previous Hunk",
26183                                    &GoToPreviousHunk,
26184                                    &focus_handle,
26185                                    cx,
26186                                )
26187                            }
26188                        })
26189                        .on_click({
26190                            let editor = editor.clone();
26191                            move |_event, window, cx| {
26192                                editor.update(cx, |editor, cx| {
26193                                    let snapshot = editor.snapshot(window, cx);
26194                                    let point =
26195                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26196                                    editor.go_to_hunk_before_or_after_position(
26197                                        &snapshot,
26198                                        point,
26199                                        Direction::Prev,
26200                                        window,
26201                                        cx,
26202                                    );
26203                                    editor.expand_selected_diff_hunks(cx);
26204                                });
26205                            }
26206                        }),
26207                )
26208            },
26209        )
26210        .into_any_element()
26211}
26212
26213pub fn multibuffer_context_lines(cx: &App) -> u32 {
26214    EditorSettings::try_get(cx)
26215        .map(|settings| settings.excerpt_context_lines)
26216        .unwrap_or(2)
26217        .min(32)
26218}