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.select_next_is_case_sensitive.map_or_else(
15538            || EditorSettings::get_global(cx).search.case_sensitive,
15539            |value| value,
15540        );
15541
15542        let mut builder = AhoCorasickBuilder::new();
15543        builder.ascii_case_insensitive(!case_sensitive);
15544        builder.build(patterns)
15545    }
15546
15547    pub fn find_next_match(
15548        &mut self,
15549        _: &FindNextMatch,
15550        window: &mut Window,
15551        cx: &mut Context<Self>,
15552    ) -> Result<()> {
15553        let selections = self.selections.disjoint_anchors_arc();
15554        match selections.first() {
15555            Some(first) if selections.len() >= 2 => {
15556                self.change_selections(Default::default(), window, cx, |s| {
15557                    s.select_ranges([first.range()]);
15558                });
15559            }
15560            _ => self.select_next(
15561                &SelectNext {
15562                    replace_newest: true,
15563                },
15564                window,
15565                cx,
15566            )?,
15567        }
15568        Ok(())
15569    }
15570
15571    pub fn find_previous_match(
15572        &mut self,
15573        _: &FindPreviousMatch,
15574        window: &mut Window,
15575        cx: &mut Context<Self>,
15576    ) -> Result<()> {
15577        let selections = self.selections.disjoint_anchors_arc();
15578        match selections.last() {
15579            Some(last) if selections.len() >= 2 => {
15580                self.change_selections(Default::default(), window, cx, |s| {
15581                    s.select_ranges([last.range()]);
15582                });
15583            }
15584            _ => self.select_previous(
15585                &SelectPrevious {
15586                    replace_newest: true,
15587                },
15588                window,
15589                cx,
15590            )?,
15591        }
15592        Ok(())
15593    }
15594
15595    pub fn toggle_comments(
15596        &mut self,
15597        action: &ToggleComments,
15598        window: &mut Window,
15599        cx: &mut Context<Self>,
15600    ) {
15601        if self.read_only(cx) {
15602            return;
15603        }
15604        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15605        let text_layout_details = &self.text_layout_details(window);
15606        self.transact(window, cx, |this, window, cx| {
15607            let mut selections = this
15608                .selections
15609                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15610            let mut edits = Vec::new();
15611            let mut selection_edit_ranges = Vec::new();
15612            let mut last_toggled_row = None;
15613            let snapshot = this.buffer.read(cx).read(cx);
15614            let empty_str: Arc<str> = Arc::default();
15615            let mut suffixes_inserted = Vec::new();
15616            let ignore_indent = action.ignore_indent;
15617
15618            fn comment_prefix_range(
15619                snapshot: &MultiBufferSnapshot,
15620                row: MultiBufferRow,
15621                comment_prefix: &str,
15622                comment_prefix_whitespace: &str,
15623                ignore_indent: bool,
15624            ) -> Range<Point> {
15625                let indent_size = if ignore_indent {
15626                    0
15627                } else {
15628                    snapshot.indent_size_for_line(row).len
15629                };
15630
15631                let start = Point::new(row.0, indent_size);
15632
15633                let mut line_bytes = snapshot
15634                    .bytes_in_range(start..snapshot.max_point())
15635                    .flatten()
15636                    .copied();
15637
15638                // If this line currently begins with the line comment prefix, then record
15639                // the range containing the prefix.
15640                if line_bytes
15641                    .by_ref()
15642                    .take(comment_prefix.len())
15643                    .eq(comment_prefix.bytes())
15644                {
15645                    // Include any whitespace that matches the comment prefix.
15646                    let matching_whitespace_len = line_bytes
15647                        .zip(comment_prefix_whitespace.bytes())
15648                        .take_while(|(a, b)| a == b)
15649                        .count() as u32;
15650                    let end = Point::new(
15651                        start.row,
15652                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15653                    );
15654                    start..end
15655                } else {
15656                    start..start
15657                }
15658            }
15659
15660            fn comment_suffix_range(
15661                snapshot: &MultiBufferSnapshot,
15662                row: MultiBufferRow,
15663                comment_suffix: &str,
15664                comment_suffix_has_leading_space: bool,
15665            ) -> Range<Point> {
15666                let end = Point::new(row.0, snapshot.line_len(row));
15667                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15668
15669                let mut line_end_bytes = snapshot
15670                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15671                    .flatten()
15672                    .copied();
15673
15674                let leading_space_len = if suffix_start_column > 0
15675                    && line_end_bytes.next() == Some(b' ')
15676                    && comment_suffix_has_leading_space
15677                {
15678                    1
15679                } else {
15680                    0
15681                };
15682
15683                // If this line currently begins with the line comment prefix, then record
15684                // the range containing the prefix.
15685                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15686                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15687                    start..end
15688                } else {
15689                    end..end
15690                }
15691            }
15692
15693            // TODO: Handle selections that cross excerpts
15694            for selection in &mut selections {
15695                let start_column = snapshot
15696                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15697                    .len;
15698                let language = if let Some(language) =
15699                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15700                {
15701                    language
15702                } else {
15703                    continue;
15704                };
15705
15706                selection_edit_ranges.clear();
15707
15708                // If multiple selections contain a given row, avoid processing that
15709                // row more than once.
15710                let mut start_row = MultiBufferRow(selection.start.row);
15711                if last_toggled_row == Some(start_row) {
15712                    start_row = start_row.next_row();
15713                }
15714                let end_row =
15715                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15716                        MultiBufferRow(selection.end.row - 1)
15717                    } else {
15718                        MultiBufferRow(selection.end.row)
15719                    };
15720                last_toggled_row = Some(end_row);
15721
15722                if start_row > end_row {
15723                    continue;
15724                }
15725
15726                // If the language has line comments, toggle those.
15727                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15728
15729                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15730                if ignore_indent {
15731                    full_comment_prefixes = full_comment_prefixes
15732                        .into_iter()
15733                        .map(|s| Arc::from(s.trim_end()))
15734                        .collect();
15735                }
15736
15737                if !full_comment_prefixes.is_empty() {
15738                    let first_prefix = full_comment_prefixes
15739                        .first()
15740                        .expect("prefixes is non-empty");
15741                    let prefix_trimmed_lengths = full_comment_prefixes
15742                        .iter()
15743                        .map(|p| p.trim_end_matches(' ').len())
15744                        .collect::<SmallVec<[usize; 4]>>();
15745
15746                    let mut all_selection_lines_are_comments = true;
15747
15748                    for row in start_row.0..=end_row.0 {
15749                        let row = MultiBufferRow(row);
15750                        if start_row < end_row && snapshot.is_line_blank(row) {
15751                            continue;
15752                        }
15753
15754                        let prefix_range = full_comment_prefixes
15755                            .iter()
15756                            .zip(prefix_trimmed_lengths.iter().copied())
15757                            .map(|(prefix, trimmed_prefix_len)| {
15758                                comment_prefix_range(
15759                                    snapshot.deref(),
15760                                    row,
15761                                    &prefix[..trimmed_prefix_len],
15762                                    &prefix[trimmed_prefix_len..],
15763                                    ignore_indent,
15764                                )
15765                            })
15766                            .max_by_key(|range| range.end.column - range.start.column)
15767                            .expect("prefixes is non-empty");
15768
15769                        if prefix_range.is_empty() {
15770                            all_selection_lines_are_comments = false;
15771                        }
15772
15773                        selection_edit_ranges.push(prefix_range);
15774                    }
15775
15776                    if all_selection_lines_are_comments {
15777                        edits.extend(
15778                            selection_edit_ranges
15779                                .iter()
15780                                .cloned()
15781                                .map(|range| (range, empty_str.clone())),
15782                        );
15783                    } else {
15784                        let min_column = selection_edit_ranges
15785                            .iter()
15786                            .map(|range| range.start.column)
15787                            .min()
15788                            .unwrap_or(0);
15789                        edits.extend(selection_edit_ranges.iter().map(|range| {
15790                            let position = Point::new(range.start.row, min_column);
15791                            (position..position, first_prefix.clone())
15792                        }));
15793                    }
15794                } else if let Some(BlockCommentConfig {
15795                    start: full_comment_prefix,
15796                    end: comment_suffix,
15797                    ..
15798                }) = language.block_comment()
15799                {
15800                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15801                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15802                    let prefix_range = comment_prefix_range(
15803                        snapshot.deref(),
15804                        start_row,
15805                        comment_prefix,
15806                        comment_prefix_whitespace,
15807                        ignore_indent,
15808                    );
15809                    let suffix_range = comment_suffix_range(
15810                        snapshot.deref(),
15811                        end_row,
15812                        comment_suffix.trim_start_matches(' '),
15813                        comment_suffix.starts_with(' '),
15814                    );
15815
15816                    if prefix_range.is_empty() || suffix_range.is_empty() {
15817                        edits.push((
15818                            prefix_range.start..prefix_range.start,
15819                            full_comment_prefix.clone(),
15820                        ));
15821                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15822                        suffixes_inserted.push((end_row, comment_suffix.len()));
15823                    } else {
15824                        edits.push((prefix_range, empty_str.clone()));
15825                        edits.push((suffix_range, empty_str.clone()));
15826                    }
15827                } else {
15828                    continue;
15829                }
15830            }
15831
15832            drop(snapshot);
15833            this.buffer.update(cx, |buffer, cx| {
15834                buffer.edit(edits, None, cx);
15835            });
15836
15837            // Adjust selections so that they end before any comment suffixes that
15838            // were inserted.
15839            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15840            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15841            let snapshot = this.buffer.read(cx).read(cx);
15842            for selection in &mut selections {
15843                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15844                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15845                        Ordering::Less => {
15846                            suffixes_inserted.next();
15847                            continue;
15848                        }
15849                        Ordering::Greater => break,
15850                        Ordering::Equal => {
15851                            if selection.end.column == snapshot.line_len(row) {
15852                                if selection.is_empty() {
15853                                    selection.start.column -= suffix_len as u32;
15854                                }
15855                                selection.end.column -= suffix_len as u32;
15856                            }
15857                            break;
15858                        }
15859                    }
15860                }
15861            }
15862
15863            drop(snapshot);
15864            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15865
15866            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15867            let selections_on_single_row = selections.windows(2).all(|selections| {
15868                selections[0].start.row == selections[1].start.row
15869                    && selections[0].end.row == selections[1].end.row
15870                    && selections[0].start.row == selections[0].end.row
15871            });
15872            let selections_selecting = selections
15873                .iter()
15874                .any(|selection| selection.start != selection.end);
15875            let advance_downwards = action.advance_downwards
15876                && selections_on_single_row
15877                && !selections_selecting
15878                && !matches!(this.mode, EditorMode::SingleLine);
15879
15880            if advance_downwards {
15881                let snapshot = this.buffer.read(cx).snapshot(cx);
15882
15883                this.change_selections(Default::default(), window, cx, |s| {
15884                    s.move_cursors_with(|display_snapshot, display_point, _| {
15885                        let mut point = display_point.to_point(display_snapshot);
15886                        point.row += 1;
15887                        point = snapshot.clip_point(point, Bias::Left);
15888                        let display_point = point.to_display_point(display_snapshot);
15889                        let goal = SelectionGoal::HorizontalPosition(
15890                            display_snapshot
15891                                .x_for_display_point(display_point, text_layout_details)
15892                                .into(),
15893                        );
15894                        (display_point, goal)
15895                    })
15896                });
15897            }
15898        });
15899    }
15900
15901    pub fn select_enclosing_symbol(
15902        &mut self,
15903        _: &SelectEnclosingSymbol,
15904        window: &mut Window,
15905        cx: &mut Context<Self>,
15906    ) {
15907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15908
15909        let buffer = self.buffer.read(cx).snapshot(cx);
15910        let old_selections = self
15911            .selections
15912            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15913            .into_boxed_slice();
15914
15915        fn update_selection(
15916            selection: &Selection<MultiBufferOffset>,
15917            buffer_snap: &MultiBufferSnapshot,
15918        ) -> Option<Selection<MultiBufferOffset>> {
15919            let cursor = selection.head();
15920            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15921            for symbol in symbols.iter().rev() {
15922                let start = symbol.range.start.to_offset(buffer_snap);
15923                let end = symbol.range.end.to_offset(buffer_snap);
15924                let new_range = start..end;
15925                if start < selection.start || end > selection.end {
15926                    return Some(Selection {
15927                        id: selection.id,
15928                        start: new_range.start,
15929                        end: new_range.end,
15930                        goal: SelectionGoal::None,
15931                        reversed: selection.reversed,
15932                    });
15933                }
15934            }
15935            None
15936        }
15937
15938        let mut selected_larger_symbol = false;
15939        let new_selections = old_selections
15940            .iter()
15941            .map(|selection| match update_selection(selection, &buffer) {
15942                Some(new_selection) => {
15943                    if new_selection.range() != selection.range() {
15944                        selected_larger_symbol = true;
15945                    }
15946                    new_selection
15947                }
15948                None => selection.clone(),
15949            })
15950            .collect::<Vec<_>>();
15951
15952        if selected_larger_symbol {
15953            self.change_selections(Default::default(), window, cx, |s| {
15954                s.select(new_selections);
15955            });
15956        }
15957    }
15958
15959    pub fn select_larger_syntax_node(
15960        &mut self,
15961        _: &SelectLargerSyntaxNode,
15962        window: &mut Window,
15963        cx: &mut Context<Self>,
15964    ) {
15965        let Some(visible_row_count) = self.visible_row_count() else {
15966            return;
15967        };
15968        let old_selections: Box<[_]> = self
15969            .selections
15970            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15971            .into();
15972        if old_selections.is_empty() {
15973            return;
15974        }
15975
15976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15977
15978        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15979        let buffer = self.buffer.read(cx).snapshot(cx);
15980
15981        let mut selected_larger_node = false;
15982        let mut new_selections = old_selections
15983            .iter()
15984            .map(|selection| {
15985                let old_range = selection.start..selection.end;
15986
15987                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15988                    // manually select word at selection
15989                    if ["string_content", "inline"].contains(&node.kind()) {
15990                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15991                        // ignore if word is already selected
15992                        if !word_range.is_empty() && old_range != word_range {
15993                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15994                            // only select word if start and end point belongs to same word
15995                            if word_range == last_word_range {
15996                                selected_larger_node = true;
15997                                return Selection {
15998                                    id: selection.id,
15999                                    start: word_range.start,
16000                                    end: word_range.end,
16001                                    goal: SelectionGoal::None,
16002                                    reversed: selection.reversed,
16003                                };
16004                            }
16005                        }
16006                    }
16007                }
16008
16009                let mut new_range = old_range.clone();
16010                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16011                    new_range = range;
16012                    if !node.is_named() {
16013                        continue;
16014                    }
16015                    if !display_map.intersects_fold(new_range.start)
16016                        && !display_map.intersects_fold(new_range.end)
16017                    {
16018                        break;
16019                    }
16020                }
16021
16022                selected_larger_node |= new_range != old_range;
16023                Selection {
16024                    id: selection.id,
16025                    start: new_range.start,
16026                    end: new_range.end,
16027                    goal: SelectionGoal::None,
16028                    reversed: selection.reversed,
16029                }
16030            })
16031            .collect::<Vec<_>>();
16032
16033        if !selected_larger_node {
16034            return; // don't put this call in the history
16035        }
16036
16037        // scroll based on transformation done to the last selection created by the user
16038        let (last_old, last_new) = old_selections
16039            .last()
16040            .zip(new_selections.last().cloned())
16041            .expect("old_selections isn't empty");
16042
16043        // revert selection
16044        let is_selection_reversed = {
16045            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16046            new_selections.last_mut().expect("checked above").reversed =
16047                should_newest_selection_be_reversed;
16048            should_newest_selection_be_reversed
16049        };
16050
16051        if selected_larger_node {
16052            self.select_syntax_node_history.disable_clearing = true;
16053            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16054                s.select(new_selections.clone());
16055            });
16056            self.select_syntax_node_history.disable_clearing = false;
16057        }
16058
16059        let start_row = last_new.start.to_display_point(&display_map).row().0;
16060        let end_row = last_new.end.to_display_point(&display_map).row().0;
16061        let selection_height = end_row - start_row + 1;
16062        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16063
16064        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16065        let scroll_behavior = if fits_on_the_screen {
16066            self.request_autoscroll(Autoscroll::fit(), cx);
16067            SelectSyntaxNodeScrollBehavior::FitSelection
16068        } else if is_selection_reversed {
16069            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16070            SelectSyntaxNodeScrollBehavior::CursorTop
16071        } else {
16072            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16073            SelectSyntaxNodeScrollBehavior::CursorBottom
16074        };
16075
16076        self.select_syntax_node_history.push((
16077            old_selections,
16078            scroll_behavior,
16079            is_selection_reversed,
16080        ));
16081    }
16082
16083    pub fn select_smaller_syntax_node(
16084        &mut self,
16085        _: &SelectSmallerSyntaxNode,
16086        window: &mut Window,
16087        cx: &mut Context<Self>,
16088    ) {
16089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16090
16091        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16092            self.select_syntax_node_history.pop()
16093        {
16094            if let Some(selection) = selections.last_mut() {
16095                selection.reversed = is_selection_reversed;
16096            }
16097
16098            self.select_syntax_node_history.disable_clearing = true;
16099            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16100                s.select(selections.to_vec());
16101            });
16102            self.select_syntax_node_history.disable_clearing = false;
16103
16104            match scroll_behavior {
16105                SelectSyntaxNodeScrollBehavior::CursorTop => {
16106                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16107                }
16108                SelectSyntaxNodeScrollBehavior::FitSelection => {
16109                    self.request_autoscroll(Autoscroll::fit(), cx);
16110                }
16111                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16112                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16113                }
16114            }
16115        }
16116    }
16117
16118    pub fn unwrap_syntax_node(
16119        &mut self,
16120        _: &UnwrapSyntaxNode,
16121        window: &mut Window,
16122        cx: &mut Context<Self>,
16123    ) {
16124        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16125
16126        let buffer = self.buffer.read(cx).snapshot(cx);
16127        let selections = self
16128            .selections
16129            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16130            .into_iter()
16131            // subtracting the offset requires sorting
16132            .sorted_by_key(|i| i.start);
16133
16134        let full_edits = selections
16135            .into_iter()
16136            .filter_map(|selection| {
16137                let child = if selection.is_empty()
16138                    && let Some((_, ancestor_range)) =
16139                        buffer.syntax_ancestor(selection.start..selection.end)
16140                {
16141                    ancestor_range
16142                } else {
16143                    selection.range()
16144                };
16145
16146                let mut parent = child.clone();
16147                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16148                    parent = ancestor_range;
16149                    if parent.start < child.start || parent.end > child.end {
16150                        break;
16151                    }
16152                }
16153
16154                if parent == child {
16155                    return None;
16156                }
16157                let text = buffer.text_for_range(child).collect::<String>();
16158                Some((selection.id, parent, text))
16159            })
16160            .collect::<Vec<_>>();
16161        if full_edits.is_empty() {
16162            return;
16163        }
16164
16165        self.transact(window, cx, |this, window, cx| {
16166            this.buffer.update(cx, |buffer, cx| {
16167                buffer.edit(
16168                    full_edits
16169                        .iter()
16170                        .map(|(_, p, t)| (p.clone(), t.clone()))
16171                        .collect::<Vec<_>>(),
16172                    None,
16173                    cx,
16174                );
16175            });
16176            this.change_selections(Default::default(), window, cx, |s| {
16177                let mut offset = 0;
16178                let mut selections = vec![];
16179                for (id, parent, text) in full_edits {
16180                    let start = parent.start - offset;
16181                    offset += (parent.end - parent.start) - text.len();
16182                    selections.push(Selection {
16183                        id,
16184                        start,
16185                        end: start + text.len(),
16186                        reversed: false,
16187                        goal: Default::default(),
16188                    });
16189                }
16190                s.select(selections);
16191            });
16192        });
16193    }
16194
16195    pub fn select_next_syntax_node(
16196        &mut self,
16197        _: &SelectNextSyntaxNode,
16198        window: &mut Window,
16199        cx: &mut Context<Self>,
16200    ) {
16201        let old_selections: Box<[_]> = self
16202            .selections
16203            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16204            .into();
16205        if old_selections.is_empty() {
16206            return;
16207        }
16208
16209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16210
16211        let buffer = self.buffer.read(cx).snapshot(cx);
16212        let mut selected_sibling = false;
16213
16214        let new_selections = old_selections
16215            .iter()
16216            .map(|selection| {
16217                let old_range = selection.start..selection.end;
16218
16219                let old_range =
16220                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16221                let excerpt = buffer.excerpt_containing(old_range.clone());
16222
16223                if let Some(mut excerpt) = excerpt
16224                    && let Some(node) = excerpt
16225                        .buffer()
16226                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16227                {
16228                    let new_range = excerpt.map_range_from_buffer(
16229                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16230                    );
16231                    selected_sibling = true;
16232                    Selection {
16233                        id: selection.id,
16234                        start: new_range.start,
16235                        end: new_range.end,
16236                        goal: SelectionGoal::None,
16237                        reversed: selection.reversed,
16238                    }
16239                } else {
16240                    selection.clone()
16241                }
16242            })
16243            .collect::<Vec<_>>();
16244
16245        if selected_sibling {
16246            self.change_selections(
16247                SelectionEffects::scroll(Autoscroll::fit()),
16248                window,
16249                cx,
16250                |s| {
16251                    s.select(new_selections);
16252                },
16253            );
16254        }
16255    }
16256
16257    pub fn select_prev_syntax_node(
16258        &mut self,
16259        _: &SelectPreviousSyntaxNode,
16260        window: &mut Window,
16261        cx: &mut Context<Self>,
16262    ) {
16263        let old_selections: Box<[_]> = self
16264            .selections
16265            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16266            .into();
16267        if old_selections.is_empty() {
16268            return;
16269        }
16270
16271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16272
16273        let buffer = self.buffer.read(cx).snapshot(cx);
16274        let mut selected_sibling = false;
16275
16276        let new_selections = old_selections
16277            .iter()
16278            .map(|selection| {
16279                let old_range = selection.start..selection.end;
16280                let old_range =
16281                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16282                let excerpt = buffer.excerpt_containing(old_range.clone());
16283
16284                if let Some(mut excerpt) = excerpt
16285                    && let Some(node) = excerpt
16286                        .buffer()
16287                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16288                {
16289                    let new_range = excerpt.map_range_from_buffer(
16290                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16291                    );
16292                    selected_sibling = true;
16293                    Selection {
16294                        id: selection.id,
16295                        start: new_range.start,
16296                        end: new_range.end,
16297                        goal: SelectionGoal::None,
16298                        reversed: selection.reversed,
16299                    }
16300                } else {
16301                    selection.clone()
16302                }
16303            })
16304            .collect::<Vec<_>>();
16305
16306        if selected_sibling {
16307            self.change_selections(
16308                SelectionEffects::scroll(Autoscroll::fit()),
16309                window,
16310                cx,
16311                |s| {
16312                    s.select(new_selections);
16313                },
16314            );
16315        }
16316    }
16317
16318    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16319        if !EditorSettings::get_global(cx).gutter.runnables {
16320            self.clear_tasks();
16321            return Task::ready(());
16322        }
16323        let project = self.project().map(Entity::downgrade);
16324        let task_sources = self.lsp_task_sources(cx);
16325        let multi_buffer = self.buffer.downgrade();
16326        cx.spawn_in(window, async move |editor, cx| {
16327            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16328            let Some(project) = project.and_then(|p| p.upgrade()) else {
16329                return;
16330            };
16331            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16332                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16333            }) else {
16334                return;
16335            };
16336
16337            let hide_runnables = project
16338                .update(cx, |project, _| project.is_via_collab())
16339                .unwrap_or(true);
16340            if hide_runnables {
16341                return;
16342            }
16343            let new_rows =
16344                cx.background_spawn({
16345                    let snapshot = display_snapshot.clone();
16346                    async move {
16347                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16348                    }
16349                })
16350                    .await;
16351            let Ok(lsp_tasks) =
16352                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16353            else {
16354                return;
16355            };
16356            let lsp_tasks = lsp_tasks.await;
16357
16358            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16359                lsp_tasks
16360                    .into_iter()
16361                    .flat_map(|(kind, tasks)| {
16362                        tasks.into_iter().filter_map(move |(location, task)| {
16363                            Some((kind.clone(), location?, task))
16364                        })
16365                    })
16366                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16367                        let buffer = location.target.buffer;
16368                        let buffer_snapshot = buffer.read(cx).snapshot();
16369                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16370                            |(excerpt_id, snapshot, _)| {
16371                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16372                                    display_snapshot
16373                                        .buffer_snapshot()
16374                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16375                                } else {
16376                                    None
16377                                }
16378                            },
16379                        );
16380                        if let Some(offset) = offset {
16381                            let task_buffer_range =
16382                                location.target.range.to_point(&buffer_snapshot);
16383                            let context_buffer_range =
16384                                task_buffer_range.to_offset(&buffer_snapshot);
16385                            let context_range = BufferOffset(context_buffer_range.start)
16386                                ..BufferOffset(context_buffer_range.end);
16387
16388                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16389                                .or_insert_with(|| RunnableTasks {
16390                                    templates: Vec::new(),
16391                                    offset,
16392                                    column: task_buffer_range.start.column,
16393                                    extra_variables: HashMap::default(),
16394                                    context_range,
16395                                })
16396                                .templates
16397                                .push((kind, task.original_task().clone()));
16398                        }
16399
16400                        acc
16401                    })
16402            }) else {
16403                return;
16404            };
16405
16406            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16407                buffer.language_settings(cx).tasks.prefer_lsp
16408            }) else {
16409                return;
16410            };
16411
16412            let rows = Self::runnable_rows(
16413                project,
16414                display_snapshot,
16415                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16416                new_rows,
16417                cx.clone(),
16418            )
16419            .await;
16420            editor
16421                .update(cx, |editor, _| {
16422                    editor.clear_tasks();
16423                    for (key, mut value) in rows {
16424                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16425                            value.templates.extend(lsp_tasks.templates);
16426                        }
16427
16428                        editor.insert_tasks(key, value);
16429                    }
16430                    for (key, value) in lsp_tasks_by_rows {
16431                        editor.insert_tasks(key, value);
16432                    }
16433                })
16434                .ok();
16435        })
16436    }
16437    fn fetch_runnable_ranges(
16438        snapshot: &DisplaySnapshot,
16439        range: Range<Anchor>,
16440    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16441        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16442    }
16443
16444    fn runnable_rows(
16445        project: Entity<Project>,
16446        snapshot: DisplaySnapshot,
16447        prefer_lsp: bool,
16448        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16449        cx: AsyncWindowContext,
16450    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16451        cx.spawn(async move |cx| {
16452            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16453            for (run_range, mut runnable) in runnable_ranges {
16454                let Some(tasks) = cx
16455                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16456                    .ok()
16457                else {
16458                    continue;
16459                };
16460                let mut tasks = tasks.await;
16461
16462                if prefer_lsp {
16463                    tasks.retain(|(task_kind, _)| {
16464                        !matches!(task_kind, TaskSourceKind::Language { .. })
16465                    });
16466                }
16467                if tasks.is_empty() {
16468                    continue;
16469                }
16470
16471                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16472                let Some(row) = snapshot
16473                    .buffer_snapshot()
16474                    .buffer_line_for_row(MultiBufferRow(point.row))
16475                    .map(|(_, range)| range.start.row)
16476                else {
16477                    continue;
16478                };
16479
16480                let context_range =
16481                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16482                runnable_rows.push((
16483                    (runnable.buffer_id, row),
16484                    RunnableTasks {
16485                        templates: tasks,
16486                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16487                        context_range,
16488                        column: point.column,
16489                        extra_variables: runnable.extra_captures,
16490                    },
16491                ));
16492            }
16493            runnable_rows
16494        })
16495    }
16496
16497    fn templates_with_tags(
16498        project: &Entity<Project>,
16499        runnable: &mut Runnable,
16500        cx: &mut App,
16501    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16502        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16503            let (worktree_id, file) = project
16504                .buffer_for_id(runnable.buffer, cx)
16505                .and_then(|buffer| buffer.read(cx).file())
16506                .map(|file| (file.worktree_id(cx), file.clone()))
16507                .unzip();
16508
16509            (
16510                project.task_store().read(cx).task_inventory().cloned(),
16511                worktree_id,
16512                file,
16513            )
16514        });
16515
16516        let tags = mem::take(&mut runnable.tags);
16517        let language = runnable.language.clone();
16518        cx.spawn(async move |cx| {
16519            let mut templates_with_tags = Vec::new();
16520            if let Some(inventory) = inventory {
16521                for RunnableTag(tag) in tags {
16522                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16523                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16524                    }) else {
16525                        return templates_with_tags;
16526                    };
16527                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16528                        move |(_, template)| {
16529                            template.tags.iter().any(|source_tag| source_tag == &tag)
16530                        },
16531                    ));
16532                }
16533            }
16534            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16535
16536            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16537                // Strongest source wins; if we have worktree tag binding, prefer that to
16538                // global and language bindings;
16539                // if we have a global binding, prefer that to language binding.
16540                let first_mismatch = templates_with_tags
16541                    .iter()
16542                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16543                if let Some(index) = first_mismatch {
16544                    templates_with_tags.truncate(index);
16545                }
16546            }
16547
16548            templates_with_tags
16549        })
16550    }
16551
16552    pub fn move_to_enclosing_bracket(
16553        &mut self,
16554        _: &MoveToEnclosingBracket,
16555        window: &mut Window,
16556        cx: &mut Context<Self>,
16557    ) {
16558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16559        self.change_selections(Default::default(), window, cx, |s| {
16560            s.move_offsets_with(|snapshot, selection| {
16561                let Some(enclosing_bracket_ranges) =
16562                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16563                else {
16564                    return;
16565                };
16566
16567                let mut best_length = usize::MAX;
16568                let mut best_inside = false;
16569                let mut best_in_bracket_range = false;
16570                let mut best_destination = None;
16571                for (open, close) in enclosing_bracket_ranges {
16572                    let close = close.to_inclusive();
16573                    let length = *close.end() - open.start;
16574                    let inside = selection.start >= open.end && selection.end <= *close.start();
16575                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16576                        || close.contains(&selection.head());
16577
16578                    // If best is next to a bracket and current isn't, skip
16579                    if !in_bracket_range && best_in_bracket_range {
16580                        continue;
16581                    }
16582
16583                    // Prefer smaller lengths unless best is inside and current isn't
16584                    if length > best_length && (best_inside || !inside) {
16585                        continue;
16586                    }
16587
16588                    best_length = length;
16589                    best_inside = inside;
16590                    best_in_bracket_range = in_bracket_range;
16591                    best_destination = Some(
16592                        if close.contains(&selection.start) && close.contains(&selection.end) {
16593                            if inside { open.end } else { open.start }
16594                        } else if inside {
16595                            *close.start()
16596                        } else {
16597                            *close.end()
16598                        },
16599                    );
16600                }
16601
16602                if let Some(destination) = best_destination {
16603                    selection.collapse_to(destination, SelectionGoal::None);
16604                }
16605            })
16606        });
16607    }
16608
16609    pub fn undo_selection(
16610        &mut self,
16611        _: &UndoSelection,
16612        window: &mut Window,
16613        cx: &mut Context<Self>,
16614    ) {
16615        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16616        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16617            self.selection_history.mode = SelectionHistoryMode::Undoing;
16618            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16619                this.end_selection(window, cx);
16620                this.change_selections(
16621                    SelectionEffects::scroll(Autoscroll::newest()),
16622                    window,
16623                    cx,
16624                    |s| s.select_anchors(entry.selections.to_vec()),
16625                );
16626            });
16627            self.selection_history.mode = SelectionHistoryMode::Normal;
16628
16629            self.select_next_state = entry.select_next_state;
16630            self.select_prev_state = entry.select_prev_state;
16631            self.add_selections_state = entry.add_selections_state;
16632        }
16633    }
16634
16635    pub fn redo_selection(
16636        &mut self,
16637        _: &RedoSelection,
16638        window: &mut Window,
16639        cx: &mut Context<Self>,
16640    ) {
16641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16642        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16643            self.selection_history.mode = SelectionHistoryMode::Redoing;
16644            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16645                this.end_selection(window, cx);
16646                this.change_selections(
16647                    SelectionEffects::scroll(Autoscroll::newest()),
16648                    window,
16649                    cx,
16650                    |s| s.select_anchors(entry.selections.to_vec()),
16651                );
16652            });
16653            self.selection_history.mode = SelectionHistoryMode::Normal;
16654
16655            self.select_next_state = entry.select_next_state;
16656            self.select_prev_state = entry.select_prev_state;
16657            self.add_selections_state = entry.add_selections_state;
16658        }
16659    }
16660
16661    pub fn expand_excerpts(
16662        &mut self,
16663        action: &ExpandExcerpts,
16664        _: &mut Window,
16665        cx: &mut Context<Self>,
16666    ) {
16667        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16668    }
16669
16670    pub fn expand_excerpts_down(
16671        &mut self,
16672        action: &ExpandExcerptsDown,
16673        _: &mut Window,
16674        cx: &mut Context<Self>,
16675    ) {
16676        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16677    }
16678
16679    pub fn expand_excerpts_up(
16680        &mut self,
16681        action: &ExpandExcerptsUp,
16682        _: &mut Window,
16683        cx: &mut Context<Self>,
16684    ) {
16685        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16686    }
16687
16688    pub fn expand_excerpts_for_direction(
16689        &mut self,
16690        lines: u32,
16691        direction: ExpandExcerptDirection,
16692
16693        cx: &mut Context<Self>,
16694    ) {
16695        let selections = self.selections.disjoint_anchors_arc();
16696
16697        let lines = if lines == 0 {
16698            EditorSettings::get_global(cx).expand_excerpt_lines
16699        } else {
16700            lines
16701        };
16702
16703        self.buffer.update(cx, |buffer, cx| {
16704            let snapshot = buffer.snapshot(cx);
16705            let mut excerpt_ids = selections
16706                .iter()
16707                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16708                .collect::<Vec<_>>();
16709            excerpt_ids.sort();
16710            excerpt_ids.dedup();
16711            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16712        })
16713    }
16714
16715    pub fn expand_excerpt(
16716        &mut self,
16717        excerpt: ExcerptId,
16718        direction: ExpandExcerptDirection,
16719        window: &mut Window,
16720        cx: &mut Context<Self>,
16721    ) {
16722        let current_scroll_position = self.scroll_position(cx);
16723        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16724        let mut scroll = None;
16725
16726        if direction == ExpandExcerptDirection::Down {
16727            let multi_buffer = self.buffer.read(cx);
16728            let snapshot = multi_buffer.snapshot(cx);
16729            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16730                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16731                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16732            {
16733                let buffer_snapshot = buffer.read(cx).snapshot();
16734                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16735                let last_row = buffer_snapshot.max_point().row;
16736                let lines_below = last_row.saturating_sub(excerpt_end_row);
16737                if lines_below >= lines_to_expand {
16738                    scroll = Some(
16739                        current_scroll_position
16740                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16741                    );
16742                }
16743            }
16744        }
16745        if direction == ExpandExcerptDirection::Up
16746            && self
16747                .buffer
16748                .read(cx)
16749                .snapshot(cx)
16750                .excerpt_before(excerpt)
16751                .is_none()
16752        {
16753            scroll = Some(current_scroll_position);
16754        }
16755
16756        self.buffer.update(cx, |buffer, cx| {
16757            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16758        });
16759
16760        if let Some(new_scroll_position) = scroll {
16761            self.set_scroll_position(new_scroll_position, window, cx);
16762        }
16763    }
16764
16765    pub fn go_to_singleton_buffer_point(
16766        &mut self,
16767        point: Point,
16768        window: &mut Window,
16769        cx: &mut Context<Self>,
16770    ) {
16771        self.go_to_singleton_buffer_range(point..point, window, cx);
16772    }
16773
16774    pub fn go_to_singleton_buffer_range(
16775        &mut self,
16776        range: Range<Point>,
16777        window: &mut Window,
16778        cx: &mut Context<Self>,
16779    ) {
16780        let multibuffer = self.buffer().read(cx);
16781        let Some(buffer) = multibuffer.as_singleton() else {
16782            return;
16783        };
16784        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16785            return;
16786        };
16787        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16788            return;
16789        };
16790        self.change_selections(
16791            SelectionEffects::default().nav_history(true),
16792            window,
16793            cx,
16794            |s| s.select_anchor_ranges([start..end]),
16795        );
16796    }
16797
16798    pub fn go_to_diagnostic(
16799        &mut self,
16800        action: &GoToDiagnostic,
16801        window: &mut Window,
16802        cx: &mut Context<Self>,
16803    ) {
16804        if !self.diagnostics_enabled() {
16805            return;
16806        }
16807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16808        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16809    }
16810
16811    pub fn go_to_prev_diagnostic(
16812        &mut self,
16813        action: &GoToPreviousDiagnostic,
16814        window: &mut Window,
16815        cx: &mut Context<Self>,
16816    ) {
16817        if !self.diagnostics_enabled() {
16818            return;
16819        }
16820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16821        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16822    }
16823
16824    pub fn go_to_diagnostic_impl(
16825        &mut self,
16826        direction: Direction,
16827        severity: GoToDiagnosticSeverityFilter,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) {
16831        let buffer = self.buffer.read(cx).snapshot(cx);
16832        let selection = self
16833            .selections
16834            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16835
16836        let mut active_group_id = None;
16837        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16838            && active_group.active_range.start.to_offset(&buffer) == selection.start
16839        {
16840            active_group_id = Some(active_group.group_id);
16841        }
16842
16843        fn filtered<'a>(
16844            severity: GoToDiagnosticSeverityFilter,
16845            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16846        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16847            diagnostics
16848                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16849                .filter(|entry| entry.range.start != entry.range.end)
16850                .filter(|entry| !entry.diagnostic.is_unnecessary)
16851        }
16852
16853        let before = filtered(
16854            severity,
16855            buffer
16856                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16857                .filter(|entry| entry.range.start <= selection.start),
16858        );
16859        let after = filtered(
16860            severity,
16861            buffer
16862                .diagnostics_in_range(selection.start..buffer.len())
16863                .filter(|entry| entry.range.start >= selection.start),
16864        );
16865
16866        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16867        if direction == Direction::Prev {
16868            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16869            {
16870                for diagnostic in prev_diagnostics.into_iter().rev() {
16871                    if diagnostic.range.start != selection.start
16872                        || active_group_id
16873                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16874                    {
16875                        found = Some(diagnostic);
16876                        break 'outer;
16877                    }
16878                }
16879            }
16880        } else {
16881            for diagnostic in after.chain(before) {
16882                if diagnostic.range.start != selection.start
16883                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16884                {
16885                    found = Some(diagnostic);
16886                    break;
16887                }
16888            }
16889        }
16890        let Some(next_diagnostic) = found else {
16891            return;
16892        };
16893
16894        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16895        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16896            return;
16897        };
16898        let snapshot = self.snapshot(window, cx);
16899        if snapshot.intersects_fold(next_diagnostic.range.start) {
16900            self.unfold_ranges(
16901                std::slice::from_ref(&next_diagnostic.range),
16902                true,
16903                false,
16904                cx,
16905            );
16906        }
16907        self.change_selections(Default::default(), window, cx, |s| {
16908            s.select_ranges(vec![
16909                next_diagnostic.range.start..next_diagnostic.range.start,
16910            ])
16911        });
16912        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16913        self.refresh_edit_prediction(false, true, window, cx);
16914    }
16915
16916    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16918        let snapshot = self.snapshot(window, cx);
16919        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16920        self.go_to_hunk_before_or_after_position(
16921            &snapshot,
16922            selection.head(),
16923            Direction::Next,
16924            window,
16925            cx,
16926        );
16927    }
16928
16929    pub fn go_to_hunk_before_or_after_position(
16930        &mut self,
16931        snapshot: &EditorSnapshot,
16932        position: Point,
16933        direction: Direction,
16934        window: &mut Window,
16935        cx: &mut Context<Editor>,
16936    ) {
16937        let row = if direction == Direction::Next {
16938            self.hunk_after_position(snapshot, position)
16939                .map(|hunk| hunk.row_range.start)
16940        } else {
16941            self.hunk_before_position(snapshot, position)
16942        };
16943
16944        if let Some(row) = row {
16945            let destination = Point::new(row.0, 0);
16946            let autoscroll = Autoscroll::center();
16947
16948            self.unfold_ranges(&[destination..destination], false, false, cx);
16949            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16950                s.select_ranges([destination..destination]);
16951            });
16952        }
16953    }
16954
16955    fn hunk_after_position(
16956        &mut self,
16957        snapshot: &EditorSnapshot,
16958        position: Point,
16959    ) -> Option<MultiBufferDiffHunk> {
16960        snapshot
16961            .buffer_snapshot()
16962            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16963            .find(|hunk| hunk.row_range.start.0 > position.row)
16964            .or_else(|| {
16965                snapshot
16966                    .buffer_snapshot()
16967                    .diff_hunks_in_range(Point::zero()..position)
16968                    .find(|hunk| hunk.row_range.end.0 < position.row)
16969            })
16970    }
16971
16972    fn go_to_prev_hunk(
16973        &mut self,
16974        _: &GoToPreviousHunk,
16975        window: &mut Window,
16976        cx: &mut Context<Self>,
16977    ) {
16978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16979        let snapshot = self.snapshot(window, cx);
16980        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16981        self.go_to_hunk_before_or_after_position(
16982            &snapshot,
16983            selection.head(),
16984            Direction::Prev,
16985            window,
16986            cx,
16987        );
16988    }
16989
16990    fn hunk_before_position(
16991        &mut self,
16992        snapshot: &EditorSnapshot,
16993        position: Point,
16994    ) -> Option<MultiBufferRow> {
16995        snapshot
16996            .buffer_snapshot()
16997            .diff_hunk_before(position)
16998            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16999    }
17000
17001    fn go_to_next_change(
17002        &mut self,
17003        _: &GoToNextChange,
17004        window: &mut Window,
17005        cx: &mut Context<Self>,
17006    ) {
17007        if let Some(selections) = self
17008            .change_list
17009            .next_change(1, Direction::Next)
17010            .map(|s| s.to_vec())
17011        {
17012            self.change_selections(Default::default(), window, cx, |s| {
17013                let map = s.display_snapshot();
17014                s.select_display_ranges(selections.iter().map(|a| {
17015                    let point = a.to_display_point(&map);
17016                    point..point
17017                }))
17018            })
17019        }
17020    }
17021
17022    fn go_to_previous_change(
17023        &mut self,
17024        _: &GoToPreviousChange,
17025        window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        if let Some(selections) = self
17029            .change_list
17030            .next_change(1, Direction::Prev)
17031            .map(|s| s.to_vec())
17032        {
17033            self.change_selections(Default::default(), window, cx, |s| {
17034                let map = s.display_snapshot();
17035                s.select_display_ranges(selections.iter().map(|a| {
17036                    let point = a.to_display_point(&map);
17037                    point..point
17038                }))
17039            })
17040        }
17041    }
17042
17043    pub fn go_to_next_document_highlight(
17044        &mut self,
17045        _: &GoToNextDocumentHighlight,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17050    }
17051
17052    pub fn go_to_prev_document_highlight(
17053        &mut self,
17054        _: &GoToPreviousDocumentHighlight,
17055        window: &mut Window,
17056        cx: &mut Context<Self>,
17057    ) {
17058        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17059    }
17060
17061    pub fn go_to_document_highlight_before_or_after_position(
17062        &mut self,
17063        direction: Direction,
17064        window: &mut Window,
17065        cx: &mut Context<Editor>,
17066    ) {
17067        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17068        let snapshot = self.snapshot(window, cx);
17069        let buffer = &snapshot.buffer_snapshot();
17070        let position = self
17071            .selections
17072            .newest::<Point>(&snapshot.display_snapshot)
17073            .head();
17074        let anchor_position = buffer.anchor_after(position);
17075
17076        // Get all document highlights (both read and write)
17077        let mut all_highlights = Vec::new();
17078
17079        if let Some((_, read_highlights)) = self
17080            .background_highlights
17081            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17082        {
17083            all_highlights.extend(read_highlights.iter());
17084        }
17085
17086        if let Some((_, write_highlights)) = self
17087            .background_highlights
17088            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17089        {
17090            all_highlights.extend(write_highlights.iter());
17091        }
17092
17093        if all_highlights.is_empty() {
17094            return;
17095        }
17096
17097        // Sort highlights by position
17098        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17099
17100        let target_highlight = match direction {
17101            Direction::Next => {
17102                // Find the first highlight after the current position
17103                all_highlights
17104                    .iter()
17105                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17106            }
17107            Direction::Prev => {
17108                // Find the last highlight before the current position
17109                all_highlights
17110                    .iter()
17111                    .rev()
17112                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17113            }
17114        };
17115
17116        if let Some(highlight) = target_highlight {
17117            let destination = highlight.start.to_point(buffer);
17118            let autoscroll = Autoscroll::center();
17119
17120            self.unfold_ranges(&[destination..destination], false, false, cx);
17121            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17122                s.select_ranges([destination..destination]);
17123            });
17124        }
17125    }
17126
17127    fn go_to_line<T: 'static>(
17128        &mut self,
17129        position: Anchor,
17130        highlight_color: Option<Hsla>,
17131        window: &mut Window,
17132        cx: &mut Context<Self>,
17133    ) {
17134        let snapshot = self.snapshot(window, cx).display_snapshot;
17135        let position = position.to_point(&snapshot.buffer_snapshot());
17136        let start = snapshot
17137            .buffer_snapshot()
17138            .clip_point(Point::new(position.row, 0), Bias::Left);
17139        let end = start + Point::new(1, 0);
17140        let start = snapshot.buffer_snapshot().anchor_before(start);
17141        let end = snapshot.buffer_snapshot().anchor_before(end);
17142
17143        self.highlight_rows::<T>(
17144            start..end,
17145            highlight_color
17146                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17147            Default::default(),
17148            cx,
17149        );
17150
17151        if self.buffer.read(cx).is_singleton() {
17152            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17153        }
17154    }
17155
17156    pub fn go_to_definition(
17157        &mut self,
17158        _: &GoToDefinition,
17159        window: &mut Window,
17160        cx: &mut Context<Self>,
17161    ) -> Task<Result<Navigated>> {
17162        let definition =
17163            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17164        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17165        cx.spawn_in(window, async move |editor, cx| {
17166            if definition.await? == Navigated::Yes {
17167                return Ok(Navigated::Yes);
17168            }
17169            match fallback_strategy {
17170                GoToDefinitionFallback::None => Ok(Navigated::No),
17171                GoToDefinitionFallback::FindAllReferences => {
17172                    match editor.update_in(cx, |editor, window, cx| {
17173                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17174                    })? {
17175                        Some(references) => references.await,
17176                        None => Ok(Navigated::No),
17177                    }
17178                }
17179            }
17180        })
17181    }
17182
17183    pub fn go_to_declaration(
17184        &mut self,
17185        _: &GoToDeclaration,
17186        window: &mut Window,
17187        cx: &mut Context<Self>,
17188    ) -> Task<Result<Navigated>> {
17189        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17190    }
17191
17192    pub fn go_to_declaration_split(
17193        &mut self,
17194        _: &GoToDeclaration,
17195        window: &mut Window,
17196        cx: &mut Context<Self>,
17197    ) -> Task<Result<Navigated>> {
17198        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17199    }
17200
17201    pub fn go_to_implementation(
17202        &mut self,
17203        _: &GoToImplementation,
17204        window: &mut Window,
17205        cx: &mut Context<Self>,
17206    ) -> Task<Result<Navigated>> {
17207        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17208    }
17209
17210    pub fn go_to_implementation_split(
17211        &mut self,
17212        _: &GoToImplementationSplit,
17213        window: &mut Window,
17214        cx: &mut Context<Self>,
17215    ) -> Task<Result<Navigated>> {
17216        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17217    }
17218
17219    pub fn go_to_type_definition(
17220        &mut self,
17221        _: &GoToTypeDefinition,
17222        window: &mut Window,
17223        cx: &mut Context<Self>,
17224    ) -> Task<Result<Navigated>> {
17225        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17226    }
17227
17228    pub fn go_to_definition_split(
17229        &mut self,
17230        _: &GoToDefinitionSplit,
17231        window: &mut Window,
17232        cx: &mut Context<Self>,
17233    ) -> Task<Result<Navigated>> {
17234        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17235    }
17236
17237    pub fn go_to_type_definition_split(
17238        &mut self,
17239        _: &GoToTypeDefinitionSplit,
17240        window: &mut Window,
17241        cx: &mut Context<Self>,
17242    ) -> Task<Result<Navigated>> {
17243        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17244    }
17245
17246    fn go_to_definition_of_kind(
17247        &mut self,
17248        kind: GotoDefinitionKind,
17249        split: bool,
17250        window: &mut Window,
17251        cx: &mut Context<Self>,
17252    ) -> Task<Result<Navigated>> {
17253        let Some(provider) = self.semantics_provider.clone() else {
17254            return Task::ready(Ok(Navigated::No));
17255        };
17256        let head = self
17257            .selections
17258            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17259            .head();
17260        let buffer = self.buffer.read(cx);
17261        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17262            return Task::ready(Ok(Navigated::No));
17263        };
17264        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17265            return Task::ready(Ok(Navigated::No));
17266        };
17267
17268        cx.spawn_in(window, async move |editor, cx| {
17269            let Some(definitions) = definitions.await? else {
17270                return Ok(Navigated::No);
17271            };
17272            let navigated = editor
17273                .update_in(cx, |editor, window, cx| {
17274                    editor.navigate_to_hover_links(
17275                        Some(kind),
17276                        definitions
17277                            .into_iter()
17278                            .filter(|location| {
17279                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17280                            })
17281                            .map(HoverLink::Text)
17282                            .collect::<Vec<_>>(),
17283                        split,
17284                        window,
17285                        cx,
17286                    )
17287                })?
17288                .await?;
17289            anyhow::Ok(navigated)
17290        })
17291    }
17292
17293    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17294        let selection = self.selections.newest_anchor();
17295        let head = selection.head();
17296        let tail = selection.tail();
17297
17298        let Some((buffer, start_position)) =
17299            self.buffer.read(cx).text_anchor_for_position(head, cx)
17300        else {
17301            return;
17302        };
17303
17304        let end_position = if head != tail {
17305            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17306                return;
17307            };
17308            Some(pos)
17309        } else {
17310            None
17311        };
17312
17313        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17314            let url = if let Some(end_pos) = end_position {
17315                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17316            } else {
17317                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17318            };
17319
17320            if let Some(url) = url {
17321                cx.update(|window, cx| {
17322                    if parse_zed_link(&url, cx).is_some() {
17323                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17324                    } else {
17325                        cx.open_url(&url);
17326                    }
17327                })?;
17328            }
17329
17330            anyhow::Ok(())
17331        });
17332
17333        url_finder.detach();
17334    }
17335
17336    pub fn open_selected_filename(
17337        &mut self,
17338        _: &OpenSelectedFilename,
17339        window: &mut Window,
17340        cx: &mut Context<Self>,
17341    ) {
17342        let Some(workspace) = self.workspace() else {
17343            return;
17344        };
17345
17346        let position = self.selections.newest_anchor().head();
17347
17348        let Some((buffer, buffer_position)) =
17349            self.buffer.read(cx).text_anchor_for_position(position, cx)
17350        else {
17351            return;
17352        };
17353
17354        let project = self.project.clone();
17355
17356        cx.spawn_in(window, async move |_, cx| {
17357            let result = find_file(&buffer, project, buffer_position, cx).await;
17358
17359            if let Some((_, path)) = result {
17360                workspace
17361                    .update_in(cx, |workspace, window, cx| {
17362                        workspace.open_resolved_path(path, window, cx)
17363                    })?
17364                    .await?;
17365            }
17366            anyhow::Ok(())
17367        })
17368        .detach();
17369    }
17370
17371    pub(crate) fn navigate_to_hover_links(
17372        &mut self,
17373        kind: Option<GotoDefinitionKind>,
17374        definitions: Vec<HoverLink>,
17375        split: bool,
17376        window: &mut Window,
17377        cx: &mut Context<Editor>,
17378    ) -> Task<Result<Navigated>> {
17379        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17380        let mut first_url_or_file = None;
17381        let definitions: Vec<_> = definitions
17382            .into_iter()
17383            .filter_map(|def| match def {
17384                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17385                HoverLink::InlayHint(lsp_location, server_id) => {
17386                    let computation =
17387                        self.compute_target_location(lsp_location, server_id, window, cx);
17388                    Some(cx.background_spawn(computation))
17389                }
17390                HoverLink::Url(url) => {
17391                    first_url_or_file = Some(Either::Left(url));
17392                    None
17393                }
17394                HoverLink::File(path) => {
17395                    first_url_or_file = Some(Either::Right(path));
17396                    None
17397                }
17398            })
17399            .collect();
17400
17401        let workspace = self.workspace();
17402
17403        cx.spawn_in(window, async move |editor, cx| {
17404            let locations: Vec<Location> = future::join_all(definitions)
17405                .await
17406                .into_iter()
17407                .filter_map(|location| location.transpose())
17408                .collect::<Result<_>>()
17409                .context("location tasks")?;
17410            let mut locations = cx.update(|_, cx| {
17411                locations
17412                    .into_iter()
17413                    .map(|location| {
17414                        let buffer = location.buffer.read(cx);
17415                        (location.buffer, location.range.to_point(buffer))
17416                    })
17417                    .into_group_map()
17418            })?;
17419            let mut num_locations = 0;
17420            for ranges in locations.values_mut() {
17421                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17422                ranges.dedup();
17423                num_locations += ranges.len();
17424            }
17425
17426            if num_locations > 1 {
17427                let tab_kind = match kind {
17428                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17429                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17430                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17431                    Some(GotoDefinitionKind::Type) => "Types",
17432                };
17433                let title = editor
17434                    .update_in(cx, |_, _, cx| {
17435                        let target = locations
17436                            .iter()
17437                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17438                            .map(|(buffer, location)| {
17439                                buffer
17440                                    .read(cx)
17441                                    .text_for_range(location.clone())
17442                                    .collect::<String>()
17443                            })
17444                            .filter(|text| !text.contains('\n'))
17445                            .unique()
17446                            .take(3)
17447                            .join(", ");
17448                        if target.is_empty() {
17449                            tab_kind.to_owned()
17450                        } else {
17451                            format!("{tab_kind} for {target}")
17452                        }
17453                    })
17454                    .context("buffer title")?;
17455
17456                let Some(workspace) = workspace else {
17457                    return Ok(Navigated::No);
17458                };
17459
17460                let opened = workspace
17461                    .update_in(cx, |workspace, window, cx| {
17462                        let allow_preview = PreviewTabsSettings::get_global(cx)
17463                            .enable_preview_multibuffer_from_code_navigation;
17464                        Self::open_locations_in_multibuffer(
17465                            workspace,
17466                            locations,
17467                            title,
17468                            split,
17469                            allow_preview,
17470                            MultibufferSelectionMode::First,
17471                            window,
17472                            cx,
17473                        )
17474                    })
17475                    .is_ok();
17476
17477                anyhow::Ok(Navigated::from_bool(opened))
17478            } else if num_locations == 0 {
17479                // If there is one url or file, open it directly
17480                match first_url_or_file {
17481                    Some(Either::Left(url)) => {
17482                        cx.update(|window, cx| {
17483                            if parse_zed_link(&url, cx).is_some() {
17484                                window
17485                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17486                            } else {
17487                                cx.open_url(&url);
17488                            }
17489                        })?;
17490                        Ok(Navigated::Yes)
17491                    }
17492                    Some(Either::Right(path)) => {
17493                        // TODO(andrew): respect preview tab settings
17494                        //               `enable_keep_preview_on_code_navigation` and
17495                        //               `enable_preview_file_from_code_navigation`
17496                        let Some(workspace) = workspace else {
17497                            return Ok(Navigated::No);
17498                        };
17499                        workspace
17500                            .update_in(cx, |workspace, window, cx| {
17501                                workspace.open_resolved_path(path, window, cx)
17502                            })?
17503                            .await?;
17504                        Ok(Navigated::Yes)
17505                    }
17506                    None => Ok(Navigated::No),
17507                }
17508            } else {
17509                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17510                let target_range = target_ranges.first().unwrap().clone();
17511
17512                editor.update_in(cx, |editor, window, cx| {
17513                    let range = target_range.to_point(target_buffer.read(cx));
17514                    let range = editor.range_for_match(&range);
17515                    let range = collapse_multiline_range(range);
17516
17517                    if !split
17518                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17519                    {
17520                        editor.go_to_singleton_buffer_range(range, window, cx);
17521                    } else {
17522                        let Some(workspace) = workspace else {
17523                            return Navigated::No;
17524                        };
17525                        let pane = workspace.read(cx).active_pane().clone();
17526                        window.defer(cx, move |window, cx| {
17527                            let target_editor: Entity<Self> =
17528                                workspace.update(cx, |workspace, cx| {
17529                                    let pane = if split {
17530                                        workspace.adjacent_pane(window, cx)
17531                                    } else {
17532                                        workspace.active_pane().clone()
17533                                    };
17534
17535                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17536                                    let keep_old_preview = preview_tabs_settings
17537                                        .enable_keep_preview_on_code_navigation;
17538                                    let allow_new_preview = preview_tabs_settings
17539                                        .enable_preview_file_from_code_navigation;
17540
17541                                    workspace.open_project_item(
17542                                        pane,
17543                                        target_buffer.clone(),
17544                                        true,
17545                                        true,
17546                                        keep_old_preview,
17547                                        allow_new_preview,
17548                                        window,
17549                                        cx,
17550                                    )
17551                                });
17552                            target_editor.update(cx, |target_editor, cx| {
17553                                // When selecting a definition in a different buffer, disable the nav history
17554                                // to avoid creating a history entry at the previous cursor location.
17555                                pane.update(cx, |pane, _| pane.disable_history());
17556                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17557                                pane.update(cx, |pane, _| pane.enable_history());
17558                            });
17559                        });
17560                    }
17561                    Navigated::Yes
17562                })
17563            }
17564        })
17565    }
17566
17567    fn compute_target_location(
17568        &self,
17569        lsp_location: lsp::Location,
17570        server_id: LanguageServerId,
17571        window: &mut Window,
17572        cx: &mut Context<Self>,
17573    ) -> Task<anyhow::Result<Option<Location>>> {
17574        let Some(project) = self.project.clone() else {
17575            return Task::ready(Ok(None));
17576        };
17577
17578        cx.spawn_in(window, async move |editor, cx| {
17579            let location_task = editor.update(cx, |_, cx| {
17580                project.update(cx, |project, cx| {
17581                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17582                })
17583            })?;
17584            let location = Some({
17585                let target_buffer_handle = location_task.await.context("open local buffer")?;
17586                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17587                    let target_start = target_buffer
17588                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17589                    let target_end = target_buffer
17590                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17591                    target_buffer.anchor_after(target_start)
17592                        ..target_buffer.anchor_before(target_end)
17593                })?;
17594                Location {
17595                    buffer: target_buffer_handle,
17596                    range,
17597                }
17598            });
17599            Ok(location)
17600        })
17601    }
17602
17603    fn go_to_next_reference(
17604        &mut self,
17605        _: &GoToNextReference,
17606        window: &mut Window,
17607        cx: &mut Context<Self>,
17608    ) {
17609        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17610        if let Some(task) = task {
17611            task.detach();
17612        };
17613    }
17614
17615    fn go_to_prev_reference(
17616        &mut self,
17617        _: &GoToPreviousReference,
17618        window: &mut Window,
17619        cx: &mut Context<Self>,
17620    ) {
17621        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17622        if let Some(task) = task {
17623            task.detach();
17624        };
17625    }
17626
17627    pub fn go_to_reference_before_or_after_position(
17628        &mut self,
17629        direction: Direction,
17630        count: usize,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) -> Option<Task<Result<()>>> {
17634        let selection = self.selections.newest_anchor();
17635        let head = selection.head();
17636
17637        let multi_buffer = self.buffer.read(cx);
17638
17639        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17640        let workspace = self.workspace()?;
17641        let project = workspace.read(cx).project().clone();
17642        let references =
17643            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17644        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17645            let Some(locations) = references.await? else {
17646                return Ok(());
17647            };
17648
17649            if locations.is_empty() {
17650                // totally normal - the cursor may be on something which is not
17651                // a symbol (e.g. a keyword)
17652                log::info!("no references found under cursor");
17653                return Ok(());
17654            }
17655
17656            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17657
17658            let (locations, current_location_index) =
17659                multi_buffer.update(cx, |multi_buffer, cx| {
17660                    let mut locations = locations
17661                        .into_iter()
17662                        .filter_map(|loc| {
17663                            let start = multi_buffer.buffer_anchor_to_anchor(
17664                                &loc.buffer,
17665                                loc.range.start,
17666                                cx,
17667                            )?;
17668                            let end = multi_buffer.buffer_anchor_to_anchor(
17669                                &loc.buffer,
17670                                loc.range.end,
17671                                cx,
17672                            )?;
17673                            Some(start..end)
17674                        })
17675                        .collect::<Vec<_>>();
17676
17677                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17678                    // There is an O(n) implementation, but given this list will be
17679                    // small (usually <100 items), the extra O(log(n)) factor isn't
17680                    // worth the (surprisingly large amount of) extra complexity.
17681                    locations
17682                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17683
17684                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17685
17686                    let current_location_index = locations.iter().position(|loc| {
17687                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17688                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17689                    });
17690
17691                    (locations, current_location_index)
17692                })?;
17693
17694            let Some(current_location_index) = current_location_index else {
17695                // This indicates something has gone wrong, because we already
17696                // handle the "no references" case above
17697                log::error!(
17698                    "failed to find current reference under cursor. Total references: {}",
17699                    locations.len()
17700                );
17701                return Ok(());
17702            };
17703
17704            let destination_location_index = match direction {
17705                Direction::Next => (current_location_index + count) % locations.len(),
17706                Direction::Prev => {
17707                    (current_location_index + locations.len() - count % locations.len())
17708                        % locations.len()
17709                }
17710            };
17711
17712            // TODO(cameron): is this needed?
17713            // the thinking is to avoid "jumping to the current location" (avoid
17714            // polluting "jumplist" in vim terms)
17715            if current_location_index == destination_location_index {
17716                return Ok(());
17717            }
17718
17719            let Range { start, end } = locations[destination_location_index];
17720
17721            editor.update_in(cx, |editor, window, cx| {
17722                let effects = SelectionEffects::default();
17723
17724                editor.unfold_ranges(&[start..end], false, false, cx);
17725                editor.change_selections(effects, window, cx, |s| {
17726                    s.select_ranges([start..start]);
17727                });
17728            })?;
17729
17730            Ok(())
17731        }))
17732    }
17733
17734    pub fn find_all_references(
17735        &mut self,
17736        action: &FindAllReferences,
17737        window: &mut Window,
17738        cx: &mut Context<Self>,
17739    ) -> Option<Task<Result<Navigated>>> {
17740        let always_open_multibuffer = action.always_open_multibuffer;
17741        let selection = self.selections.newest_anchor();
17742        let multi_buffer = self.buffer.read(cx);
17743        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17744        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17745        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17746        let head = selection_offset.head();
17747
17748        let head_anchor = multi_buffer_snapshot.anchor_at(
17749            head,
17750            if head < selection_offset.tail() {
17751                Bias::Right
17752            } else {
17753                Bias::Left
17754            },
17755        );
17756
17757        match self
17758            .find_all_references_task_sources
17759            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17760        {
17761            Ok(_) => {
17762                log::info!(
17763                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17764                );
17765                return None;
17766            }
17767            Err(i) => {
17768                self.find_all_references_task_sources.insert(i, head_anchor);
17769            }
17770        }
17771
17772        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17773        let workspace = self.workspace()?;
17774        let project = workspace.read(cx).project().clone();
17775        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17776        Some(cx.spawn_in(window, async move |editor, cx| {
17777            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17778                if let Ok(i) = editor
17779                    .find_all_references_task_sources
17780                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17781                {
17782                    editor.find_all_references_task_sources.remove(i);
17783                }
17784            });
17785
17786            let Some(locations) = references.await? else {
17787                return anyhow::Ok(Navigated::No);
17788            };
17789            let mut locations = cx.update(|_, cx| {
17790                locations
17791                    .into_iter()
17792                    .map(|location| {
17793                        let buffer = location.buffer.read(cx);
17794                        (location.buffer, location.range.to_point(buffer))
17795                    })
17796                    // if special-casing the single-match case, remove ranges
17797                    // that intersect current selection
17798                    .filter(|(location_buffer, location)| {
17799                        if always_open_multibuffer || &buffer != location_buffer {
17800                            return true;
17801                        }
17802
17803                        !location.contains_inclusive(&selection_point.range())
17804                    })
17805                    .into_group_map()
17806            })?;
17807            if locations.is_empty() {
17808                return anyhow::Ok(Navigated::No);
17809            }
17810            for ranges in locations.values_mut() {
17811                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17812                ranges.dedup();
17813            }
17814            let mut num_locations = 0;
17815            for ranges in locations.values_mut() {
17816                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17817                ranges.dedup();
17818                num_locations += ranges.len();
17819            }
17820
17821            if num_locations == 1 && !always_open_multibuffer {
17822                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17823                let target_range = target_ranges.first().unwrap().clone();
17824
17825                return editor.update_in(cx, |editor, window, cx| {
17826                    let range = target_range.to_point(target_buffer.read(cx));
17827                    let range = editor.range_for_match(&range);
17828                    let range = range.start..range.start;
17829
17830                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17831                        editor.go_to_singleton_buffer_range(range, window, cx);
17832                    } else {
17833                        let pane = workspace.read(cx).active_pane().clone();
17834                        window.defer(cx, move |window, cx| {
17835                            let target_editor: Entity<Self> =
17836                                workspace.update(cx, |workspace, cx| {
17837                                    let pane = workspace.active_pane().clone();
17838
17839                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17840                                    let keep_old_preview = preview_tabs_settings
17841                                        .enable_keep_preview_on_code_navigation;
17842                                    let allow_new_preview = preview_tabs_settings
17843                                        .enable_preview_file_from_code_navigation;
17844
17845                                    workspace.open_project_item(
17846                                        pane,
17847                                        target_buffer.clone(),
17848                                        true,
17849                                        true,
17850                                        keep_old_preview,
17851                                        allow_new_preview,
17852                                        window,
17853                                        cx,
17854                                    )
17855                                });
17856                            target_editor.update(cx, |target_editor, cx| {
17857                                // When selecting a definition in a different buffer, disable the nav history
17858                                // to avoid creating a history entry at the previous cursor location.
17859                                pane.update(cx, |pane, _| pane.disable_history());
17860                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17861                                pane.update(cx, |pane, _| pane.enable_history());
17862                            });
17863                        });
17864                    }
17865                    Navigated::No
17866                });
17867            }
17868
17869            workspace.update_in(cx, |workspace, window, cx| {
17870                let target = locations
17871                    .iter()
17872                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17873                    .map(|(buffer, location)| {
17874                        buffer
17875                            .read(cx)
17876                            .text_for_range(location.clone())
17877                            .collect::<String>()
17878                    })
17879                    .filter(|text| !text.contains('\n'))
17880                    .unique()
17881                    .take(3)
17882                    .join(", ");
17883                let title = if target.is_empty() {
17884                    "References".to_owned()
17885                } else {
17886                    format!("References to {target}")
17887                };
17888                let allow_preview = PreviewTabsSettings::get_global(cx)
17889                    .enable_preview_multibuffer_from_code_navigation;
17890                Self::open_locations_in_multibuffer(
17891                    workspace,
17892                    locations,
17893                    title,
17894                    false,
17895                    allow_preview,
17896                    MultibufferSelectionMode::First,
17897                    window,
17898                    cx,
17899                );
17900                Navigated::Yes
17901            })
17902        }))
17903    }
17904
17905    /// Opens a multibuffer with the given project locations in it.
17906    pub fn open_locations_in_multibuffer(
17907        workspace: &mut Workspace,
17908        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17909        title: String,
17910        split: bool,
17911        allow_preview: bool,
17912        multibuffer_selection_mode: MultibufferSelectionMode,
17913        window: &mut Window,
17914        cx: &mut Context<Workspace>,
17915    ) {
17916        if locations.is_empty() {
17917            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17918            return;
17919        }
17920
17921        let capability = workspace.project().read(cx).capability();
17922        let mut ranges = <Vec<Range<Anchor>>>::new();
17923
17924        // a key to find existing multibuffer editors with the same set of locations
17925        // to prevent us from opening more and more multibuffer tabs for searches and the like
17926        let mut key = (title.clone(), vec![]);
17927        let excerpt_buffer = cx.new(|cx| {
17928            let key = &mut key.1;
17929            let mut multibuffer = MultiBuffer::new(capability);
17930            for (buffer, mut ranges_for_buffer) in locations {
17931                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17932                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17933                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17934                    PathKey::for_buffer(&buffer, cx),
17935                    buffer.clone(),
17936                    ranges_for_buffer,
17937                    multibuffer_context_lines(cx),
17938                    cx,
17939                );
17940                ranges.extend(new_ranges)
17941            }
17942
17943            multibuffer.with_title(title)
17944        });
17945        let existing = workspace.active_pane().update(cx, |pane, cx| {
17946            pane.items()
17947                .filter_map(|item| item.downcast::<Editor>())
17948                .find(|editor| {
17949                    editor
17950                        .read(cx)
17951                        .lookup_key
17952                        .as_ref()
17953                        .and_then(|it| {
17954                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17955                        })
17956                        .is_some_and(|it| *it == key)
17957                })
17958        });
17959        let was_existing = existing.is_some();
17960        let editor = existing.unwrap_or_else(|| {
17961            cx.new(|cx| {
17962                let mut editor = Editor::for_multibuffer(
17963                    excerpt_buffer,
17964                    Some(workspace.project().clone()),
17965                    window,
17966                    cx,
17967                );
17968                editor.lookup_key = Some(Box::new(key));
17969                editor
17970            })
17971        });
17972        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17973            MultibufferSelectionMode::First => {
17974                if let Some(first_range) = ranges.first() {
17975                    editor.change_selections(
17976                        SelectionEffects::no_scroll(),
17977                        window,
17978                        cx,
17979                        |selections| {
17980                            selections.clear_disjoint();
17981                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17982                        },
17983                    );
17984                }
17985                editor.highlight_background::<Self>(
17986                    &ranges,
17987                    |_, theme| theme.colors().editor_highlighted_line_background,
17988                    cx,
17989                );
17990            }
17991            MultibufferSelectionMode::All => {
17992                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17993                    selections.clear_disjoint();
17994                    selections.select_anchor_ranges(ranges);
17995                });
17996            }
17997        });
17998
17999        let item = Box::new(editor);
18000
18001        let pane = if split {
18002            workspace.adjacent_pane(window, cx)
18003        } else {
18004            workspace.active_pane().clone()
18005        };
18006        let activate_pane = split;
18007
18008        let mut destination_index = None;
18009        pane.update(cx, |pane, cx| {
18010            if allow_preview && !was_existing {
18011                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18012            }
18013            if was_existing && !allow_preview {
18014                pane.unpreview_item_if_preview(item.item_id());
18015            }
18016            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18017        });
18018    }
18019
18020    pub fn rename(
18021        &mut self,
18022        _: &Rename,
18023        window: &mut Window,
18024        cx: &mut Context<Self>,
18025    ) -> Option<Task<Result<()>>> {
18026        use language::ToOffset as _;
18027
18028        let provider = self.semantics_provider.clone()?;
18029        let selection = self.selections.newest_anchor().clone();
18030        let (cursor_buffer, cursor_buffer_position) = self
18031            .buffer
18032            .read(cx)
18033            .text_anchor_for_position(selection.head(), cx)?;
18034        let (tail_buffer, cursor_buffer_position_end) = self
18035            .buffer
18036            .read(cx)
18037            .text_anchor_for_position(selection.tail(), cx)?;
18038        if tail_buffer != cursor_buffer {
18039            return None;
18040        }
18041
18042        let snapshot = cursor_buffer.read(cx).snapshot();
18043        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18044        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18045        let prepare_rename = provider
18046            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18047            .unwrap_or_else(|| Task::ready(Ok(None)));
18048        drop(snapshot);
18049
18050        Some(cx.spawn_in(window, async move |this, cx| {
18051            let rename_range = if let Some(range) = prepare_rename.await? {
18052                Some(range)
18053            } else {
18054                this.update(cx, |this, cx| {
18055                    let buffer = this.buffer.read(cx).snapshot(cx);
18056                    let mut buffer_highlights = this
18057                        .document_highlights_for_position(selection.head(), &buffer)
18058                        .filter(|highlight| {
18059                            highlight.start.excerpt_id == selection.head().excerpt_id
18060                                && highlight.end.excerpt_id == selection.head().excerpt_id
18061                        });
18062                    buffer_highlights
18063                        .next()
18064                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18065                })?
18066            };
18067            if let Some(rename_range) = rename_range {
18068                this.update_in(cx, |this, window, cx| {
18069                    let snapshot = cursor_buffer.read(cx).snapshot();
18070                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18071                    let cursor_offset_in_rename_range =
18072                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18073                    let cursor_offset_in_rename_range_end =
18074                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18075
18076                    this.take_rename(false, window, cx);
18077                    let buffer = this.buffer.read(cx).read(cx);
18078                    let cursor_offset = selection.head().to_offset(&buffer);
18079                    let rename_start =
18080                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18081                    let rename_end = rename_start + rename_buffer_range.len();
18082                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18083                    let mut old_highlight_id = None;
18084                    let old_name: Arc<str> = buffer
18085                        .chunks(rename_start..rename_end, true)
18086                        .map(|chunk| {
18087                            if old_highlight_id.is_none() {
18088                                old_highlight_id = chunk.syntax_highlight_id;
18089                            }
18090                            chunk.text
18091                        })
18092                        .collect::<String>()
18093                        .into();
18094
18095                    drop(buffer);
18096
18097                    // Position the selection in the rename editor so that it matches the current selection.
18098                    this.show_local_selections = false;
18099                    let rename_editor = cx.new(|cx| {
18100                        let mut editor = Editor::single_line(window, cx);
18101                        editor.buffer.update(cx, |buffer, cx| {
18102                            buffer.edit(
18103                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18104                                None,
18105                                cx,
18106                            )
18107                        });
18108                        let cursor_offset_in_rename_range =
18109                            MultiBufferOffset(cursor_offset_in_rename_range);
18110                        let cursor_offset_in_rename_range_end =
18111                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18112                        let rename_selection_range = match cursor_offset_in_rename_range
18113                            .cmp(&cursor_offset_in_rename_range_end)
18114                        {
18115                            Ordering::Equal => {
18116                                editor.select_all(&SelectAll, window, cx);
18117                                return editor;
18118                            }
18119                            Ordering::Less => {
18120                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18121                            }
18122                            Ordering::Greater => {
18123                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18124                            }
18125                        };
18126                        if rename_selection_range.end.0 > old_name.len() {
18127                            editor.select_all(&SelectAll, window, cx);
18128                        } else {
18129                            editor.change_selections(Default::default(), window, cx, |s| {
18130                                s.select_ranges([rename_selection_range]);
18131                            });
18132                        }
18133                        editor
18134                    });
18135                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18136                        if e == &EditorEvent::Focused {
18137                            cx.emit(EditorEvent::FocusedIn)
18138                        }
18139                    })
18140                    .detach();
18141
18142                    let write_highlights =
18143                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18144                    let read_highlights =
18145                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18146                    let ranges = write_highlights
18147                        .iter()
18148                        .flat_map(|(_, ranges)| ranges.iter())
18149                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18150                        .cloned()
18151                        .collect();
18152
18153                    this.highlight_text::<Rename>(
18154                        ranges,
18155                        HighlightStyle {
18156                            fade_out: Some(0.6),
18157                            ..Default::default()
18158                        },
18159                        cx,
18160                    );
18161                    let rename_focus_handle = rename_editor.focus_handle(cx);
18162                    window.focus(&rename_focus_handle);
18163                    let block_id = this.insert_blocks(
18164                        [BlockProperties {
18165                            style: BlockStyle::Flex,
18166                            placement: BlockPlacement::Below(range.start),
18167                            height: Some(1),
18168                            render: Arc::new({
18169                                let rename_editor = rename_editor.clone();
18170                                move |cx: &mut BlockContext| {
18171                                    let mut text_style = cx.editor_style.text.clone();
18172                                    if let Some(highlight_style) = old_highlight_id
18173                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18174                                    {
18175                                        text_style = text_style.highlight(highlight_style);
18176                                    }
18177                                    div()
18178                                        .block_mouse_except_scroll()
18179                                        .pl(cx.anchor_x)
18180                                        .child(EditorElement::new(
18181                                            &rename_editor,
18182                                            EditorStyle {
18183                                                background: cx.theme().system().transparent,
18184                                                local_player: cx.editor_style.local_player,
18185                                                text: text_style,
18186                                                scrollbar_width: cx.editor_style.scrollbar_width,
18187                                                syntax: cx.editor_style.syntax.clone(),
18188                                                status: cx.editor_style.status.clone(),
18189                                                inlay_hints_style: HighlightStyle {
18190                                                    font_weight: Some(FontWeight::BOLD),
18191                                                    ..make_inlay_hints_style(cx.app)
18192                                                },
18193                                                edit_prediction_styles: make_suggestion_styles(
18194                                                    cx.app,
18195                                                ),
18196                                                ..EditorStyle::default()
18197                                            },
18198                                        ))
18199                                        .into_any_element()
18200                                }
18201                            }),
18202                            priority: 0,
18203                        }],
18204                        Some(Autoscroll::fit()),
18205                        cx,
18206                    )[0];
18207                    this.pending_rename = Some(RenameState {
18208                        range,
18209                        old_name,
18210                        editor: rename_editor,
18211                        block_id,
18212                    });
18213                })?;
18214            }
18215
18216            Ok(())
18217        }))
18218    }
18219
18220    pub fn confirm_rename(
18221        &mut self,
18222        _: &ConfirmRename,
18223        window: &mut Window,
18224        cx: &mut Context<Self>,
18225    ) -> Option<Task<Result<()>>> {
18226        let rename = self.take_rename(false, window, cx)?;
18227        let workspace = self.workspace()?.downgrade();
18228        let (buffer, start) = self
18229            .buffer
18230            .read(cx)
18231            .text_anchor_for_position(rename.range.start, cx)?;
18232        let (end_buffer, _) = self
18233            .buffer
18234            .read(cx)
18235            .text_anchor_for_position(rename.range.end, cx)?;
18236        if buffer != end_buffer {
18237            return None;
18238        }
18239
18240        let old_name = rename.old_name;
18241        let new_name = rename.editor.read(cx).text(cx);
18242
18243        let rename = self.semantics_provider.as_ref()?.perform_rename(
18244            &buffer,
18245            start,
18246            new_name.clone(),
18247            cx,
18248        )?;
18249
18250        Some(cx.spawn_in(window, async move |editor, cx| {
18251            let project_transaction = rename.await?;
18252            Self::open_project_transaction(
18253                &editor,
18254                workspace,
18255                project_transaction,
18256                format!("Rename: {}{}", old_name, new_name),
18257                cx,
18258            )
18259            .await?;
18260
18261            editor.update(cx, |editor, cx| {
18262                editor.refresh_document_highlights(cx);
18263            })?;
18264            Ok(())
18265        }))
18266    }
18267
18268    fn take_rename(
18269        &mut self,
18270        moving_cursor: bool,
18271        window: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) -> Option<RenameState> {
18274        let rename = self.pending_rename.take()?;
18275        if rename.editor.focus_handle(cx).is_focused(window) {
18276            window.focus(&self.focus_handle);
18277        }
18278
18279        self.remove_blocks(
18280            [rename.block_id].into_iter().collect(),
18281            Some(Autoscroll::fit()),
18282            cx,
18283        );
18284        self.clear_highlights::<Rename>(cx);
18285        self.show_local_selections = true;
18286
18287        if moving_cursor {
18288            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18289                editor
18290                    .selections
18291                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18292                    .head()
18293            });
18294
18295            // Update the selection to match the position of the selection inside
18296            // the rename editor.
18297            let snapshot = self.buffer.read(cx).read(cx);
18298            let rename_range = rename.range.to_offset(&snapshot);
18299            let cursor_in_editor = snapshot
18300                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18301                .min(rename_range.end);
18302            drop(snapshot);
18303
18304            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18305                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18306            });
18307        } else {
18308            self.refresh_document_highlights(cx);
18309        }
18310
18311        Some(rename)
18312    }
18313
18314    pub fn pending_rename(&self) -> Option<&RenameState> {
18315        self.pending_rename.as_ref()
18316    }
18317
18318    fn format(
18319        &mut self,
18320        _: &Format,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) -> Option<Task<Result<()>>> {
18324        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18325
18326        let project = match &self.project {
18327            Some(project) => project.clone(),
18328            None => return None,
18329        };
18330
18331        Some(self.perform_format(
18332            project,
18333            FormatTrigger::Manual,
18334            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18335            window,
18336            cx,
18337        ))
18338    }
18339
18340    fn format_selections(
18341        &mut self,
18342        _: &FormatSelections,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) -> Option<Task<Result<()>>> {
18346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18347
18348        let project = match &self.project {
18349            Some(project) => project.clone(),
18350            None => return None,
18351        };
18352
18353        let ranges = self
18354            .selections
18355            .all_adjusted(&self.display_snapshot(cx))
18356            .into_iter()
18357            .map(|selection| selection.range())
18358            .collect_vec();
18359
18360        Some(self.perform_format(
18361            project,
18362            FormatTrigger::Manual,
18363            FormatTarget::Ranges(ranges),
18364            window,
18365            cx,
18366        ))
18367    }
18368
18369    fn perform_format(
18370        &mut self,
18371        project: Entity<Project>,
18372        trigger: FormatTrigger,
18373        target: FormatTarget,
18374        window: &mut Window,
18375        cx: &mut Context<Self>,
18376    ) -> Task<Result<()>> {
18377        let buffer = self.buffer.clone();
18378        let (buffers, target) = match target {
18379            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18380            FormatTarget::Ranges(selection_ranges) => {
18381                let multi_buffer = buffer.read(cx);
18382                let snapshot = multi_buffer.read(cx);
18383                let mut buffers = HashSet::default();
18384                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18385                    BTreeMap::new();
18386                for selection_range in selection_ranges {
18387                    for (buffer, buffer_range, _) in
18388                        snapshot.range_to_buffer_ranges(selection_range)
18389                    {
18390                        let buffer_id = buffer.remote_id();
18391                        let start = buffer.anchor_before(buffer_range.start);
18392                        let end = buffer.anchor_after(buffer_range.end);
18393                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18394                        buffer_id_to_ranges
18395                            .entry(buffer_id)
18396                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18397                            .or_insert_with(|| vec![start..end]);
18398                    }
18399                }
18400                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18401            }
18402        };
18403
18404        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18405        let selections_prev = transaction_id_prev
18406            .and_then(|transaction_id_prev| {
18407                // default to selections as they were after the last edit, if we have them,
18408                // instead of how they are now.
18409                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18410                // will take you back to where you made the last edit, instead of staying where you scrolled
18411                self.selection_history
18412                    .transaction(transaction_id_prev)
18413                    .map(|t| t.0.clone())
18414            })
18415            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18416
18417        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18418        let format = project.update(cx, |project, cx| {
18419            project.format(buffers, target, true, trigger, cx)
18420        });
18421
18422        cx.spawn_in(window, async move |editor, cx| {
18423            let transaction = futures::select_biased! {
18424                transaction = format.log_err().fuse() => transaction,
18425                () = timeout => {
18426                    log::warn!("timed out waiting for formatting");
18427                    None
18428                }
18429            };
18430
18431            buffer
18432                .update(cx, |buffer, cx| {
18433                    if let Some(transaction) = transaction
18434                        && !buffer.is_singleton()
18435                    {
18436                        buffer.push_transaction(&transaction.0, cx);
18437                    }
18438                    cx.notify();
18439                })
18440                .ok();
18441
18442            if let Some(transaction_id_now) =
18443                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18444            {
18445                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18446                if has_new_transaction {
18447                    _ = editor.update(cx, |editor, _| {
18448                        editor
18449                            .selection_history
18450                            .insert_transaction(transaction_id_now, selections_prev);
18451                    });
18452                }
18453            }
18454
18455            Ok(())
18456        })
18457    }
18458
18459    fn organize_imports(
18460        &mut self,
18461        _: &OrganizeImports,
18462        window: &mut Window,
18463        cx: &mut Context<Self>,
18464    ) -> Option<Task<Result<()>>> {
18465        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18466        let project = match &self.project {
18467            Some(project) => project.clone(),
18468            None => return None,
18469        };
18470        Some(self.perform_code_action_kind(
18471            project,
18472            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18473            window,
18474            cx,
18475        ))
18476    }
18477
18478    fn perform_code_action_kind(
18479        &mut self,
18480        project: Entity<Project>,
18481        kind: CodeActionKind,
18482        window: &mut Window,
18483        cx: &mut Context<Self>,
18484    ) -> Task<Result<()>> {
18485        let buffer = self.buffer.clone();
18486        let buffers = buffer.read(cx).all_buffers();
18487        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18488        let apply_action = project.update(cx, |project, cx| {
18489            project.apply_code_action_kind(buffers, kind, true, cx)
18490        });
18491        cx.spawn_in(window, async move |_, cx| {
18492            let transaction = futures::select_biased! {
18493                () = timeout => {
18494                    log::warn!("timed out waiting for executing code action");
18495                    None
18496                }
18497                transaction = apply_action.log_err().fuse() => transaction,
18498            };
18499            buffer
18500                .update(cx, |buffer, cx| {
18501                    // check if we need this
18502                    if let Some(transaction) = transaction
18503                        && !buffer.is_singleton()
18504                    {
18505                        buffer.push_transaction(&transaction.0, cx);
18506                    }
18507                    cx.notify();
18508                })
18509                .ok();
18510            Ok(())
18511        })
18512    }
18513
18514    pub fn restart_language_server(
18515        &mut self,
18516        _: &RestartLanguageServer,
18517        _: &mut Window,
18518        cx: &mut Context<Self>,
18519    ) {
18520        if let Some(project) = self.project.clone() {
18521            self.buffer.update(cx, |multi_buffer, cx| {
18522                project.update(cx, |project, cx| {
18523                    project.restart_language_servers_for_buffers(
18524                        multi_buffer.all_buffers().into_iter().collect(),
18525                        HashSet::default(),
18526                        cx,
18527                    );
18528                });
18529            })
18530        }
18531    }
18532
18533    pub fn stop_language_server(
18534        &mut self,
18535        _: &StopLanguageServer,
18536        _: &mut Window,
18537        cx: &mut Context<Self>,
18538    ) {
18539        if let Some(project) = self.project.clone() {
18540            self.buffer.update(cx, |multi_buffer, cx| {
18541                project.update(cx, |project, cx| {
18542                    project.stop_language_servers_for_buffers(
18543                        multi_buffer.all_buffers().into_iter().collect(),
18544                        HashSet::default(),
18545                        cx,
18546                    );
18547                });
18548            });
18549            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18550        }
18551    }
18552
18553    fn cancel_language_server_work(
18554        workspace: &mut Workspace,
18555        _: &actions::CancelLanguageServerWork,
18556        _: &mut Window,
18557        cx: &mut Context<Workspace>,
18558    ) {
18559        let project = workspace.project();
18560        let buffers = workspace
18561            .active_item(cx)
18562            .and_then(|item| item.act_as::<Editor>(cx))
18563            .map_or(HashSet::default(), |editor| {
18564                editor.read(cx).buffer.read(cx).all_buffers()
18565            });
18566        project.update(cx, |project, cx| {
18567            project.cancel_language_server_work_for_buffers(buffers, cx);
18568        });
18569    }
18570
18571    fn show_character_palette(
18572        &mut self,
18573        _: &ShowCharacterPalette,
18574        window: &mut Window,
18575        _: &mut Context<Self>,
18576    ) {
18577        window.show_character_palette();
18578    }
18579
18580    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18581        if !self.diagnostics_enabled() {
18582            return;
18583        }
18584
18585        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18586            let buffer = self.buffer.read(cx).snapshot(cx);
18587            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18588            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18589            let is_valid = buffer
18590                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18591                .any(|entry| {
18592                    entry.diagnostic.is_primary
18593                        && !entry.range.is_empty()
18594                        && entry.range.start == primary_range_start
18595                        && entry.diagnostic.message == active_diagnostics.active_message
18596                });
18597
18598            if !is_valid {
18599                self.dismiss_diagnostics(cx);
18600            }
18601        }
18602    }
18603
18604    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18605        match &self.active_diagnostics {
18606            ActiveDiagnostic::Group(group) => Some(group),
18607            _ => None,
18608        }
18609    }
18610
18611    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18612        if !self.diagnostics_enabled() {
18613            return;
18614        }
18615        self.dismiss_diagnostics(cx);
18616        self.active_diagnostics = ActiveDiagnostic::All;
18617    }
18618
18619    fn activate_diagnostics(
18620        &mut self,
18621        buffer_id: BufferId,
18622        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18627            return;
18628        }
18629        self.dismiss_diagnostics(cx);
18630        let snapshot = self.snapshot(window, cx);
18631        let buffer = self.buffer.read(cx).snapshot(cx);
18632        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18633            return;
18634        };
18635
18636        let diagnostic_group = buffer
18637            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18638            .collect::<Vec<_>>();
18639
18640        let language_registry = self
18641            .project()
18642            .map(|project| project.read(cx).languages().clone());
18643
18644        let blocks = renderer.render_group(
18645            diagnostic_group,
18646            buffer_id,
18647            snapshot,
18648            cx.weak_entity(),
18649            language_registry,
18650            cx,
18651        );
18652
18653        let blocks = self.display_map.update(cx, |display_map, cx| {
18654            display_map.insert_blocks(blocks, cx).into_iter().collect()
18655        });
18656        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18657            active_range: buffer.anchor_before(diagnostic.range.start)
18658                ..buffer.anchor_after(diagnostic.range.end),
18659            active_message: diagnostic.diagnostic.message.clone(),
18660            group_id: diagnostic.diagnostic.group_id,
18661            blocks,
18662        });
18663        cx.notify();
18664    }
18665
18666    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18667        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18668            return;
18669        };
18670
18671        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18672        if let ActiveDiagnostic::Group(group) = prev {
18673            self.display_map.update(cx, |display_map, cx| {
18674                display_map.remove_blocks(group.blocks, cx);
18675            });
18676            cx.notify();
18677        }
18678    }
18679
18680    /// Disable inline diagnostics rendering for this editor.
18681    pub fn disable_inline_diagnostics(&mut self) {
18682        self.inline_diagnostics_enabled = false;
18683        self.inline_diagnostics_update = Task::ready(());
18684        self.inline_diagnostics.clear();
18685    }
18686
18687    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18688        self.diagnostics_enabled = false;
18689        self.dismiss_diagnostics(cx);
18690        self.inline_diagnostics_update = Task::ready(());
18691        self.inline_diagnostics.clear();
18692    }
18693
18694    pub fn disable_word_completions(&mut self) {
18695        self.word_completions_enabled = false;
18696    }
18697
18698    pub fn diagnostics_enabled(&self) -> bool {
18699        self.diagnostics_enabled && self.mode.is_full()
18700    }
18701
18702    pub fn inline_diagnostics_enabled(&self) -> bool {
18703        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18704    }
18705
18706    pub fn show_inline_diagnostics(&self) -> bool {
18707        self.show_inline_diagnostics
18708    }
18709
18710    pub fn toggle_inline_diagnostics(
18711        &mut self,
18712        _: &ToggleInlineDiagnostics,
18713        window: &mut Window,
18714        cx: &mut Context<Editor>,
18715    ) {
18716        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18717        self.refresh_inline_diagnostics(false, window, cx);
18718    }
18719
18720    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18721        self.diagnostics_max_severity = severity;
18722        self.display_map.update(cx, |display_map, _| {
18723            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18724        });
18725    }
18726
18727    pub fn toggle_diagnostics(
18728        &mut self,
18729        _: &ToggleDiagnostics,
18730        window: &mut Window,
18731        cx: &mut Context<Editor>,
18732    ) {
18733        if !self.diagnostics_enabled() {
18734            return;
18735        }
18736
18737        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18738            EditorSettings::get_global(cx)
18739                .diagnostics_max_severity
18740                .filter(|severity| severity != &DiagnosticSeverity::Off)
18741                .unwrap_or(DiagnosticSeverity::Hint)
18742        } else {
18743            DiagnosticSeverity::Off
18744        };
18745        self.set_max_diagnostics_severity(new_severity, cx);
18746        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18747            self.active_diagnostics = ActiveDiagnostic::None;
18748            self.inline_diagnostics_update = Task::ready(());
18749            self.inline_diagnostics.clear();
18750        } else {
18751            self.refresh_inline_diagnostics(false, window, cx);
18752        }
18753
18754        cx.notify();
18755    }
18756
18757    pub fn toggle_minimap(
18758        &mut self,
18759        _: &ToggleMinimap,
18760        window: &mut Window,
18761        cx: &mut Context<Editor>,
18762    ) {
18763        if self.supports_minimap(cx) {
18764            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18765        }
18766    }
18767
18768    fn refresh_inline_diagnostics(
18769        &mut self,
18770        debounce: bool,
18771        window: &mut Window,
18772        cx: &mut Context<Self>,
18773    ) {
18774        let max_severity = ProjectSettings::get_global(cx)
18775            .diagnostics
18776            .inline
18777            .max_severity
18778            .unwrap_or(self.diagnostics_max_severity);
18779
18780        if !self.inline_diagnostics_enabled()
18781            || !self.diagnostics_enabled()
18782            || !self.show_inline_diagnostics
18783            || max_severity == DiagnosticSeverity::Off
18784        {
18785            self.inline_diagnostics_update = Task::ready(());
18786            self.inline_diagnostics.clear();
18787            return;
18788        }
18789
18790        let debounce_ms = ProjectSettings::get_global(cx)
18791            .diagnostics
18792            .inline
18793            .update_debounce_ms;
18794        let debounce = if debounce && debounce_ms > 0 {
18795            Some(Duration::from_millis(debounce_ms))
18796        } else {
18797            None
18798        };
18799        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18800            if let Some(debounce) = debounce {
18801                cx.background_executor().timer(debounce).await;
18802            }
18803            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18804                editor
18805                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18806                    .ok()
18807            }) else {
18808                return;
18809            };
18810
18811            let new_inline_diagnostics = cx
18812                .background_spawn(async move {
18813                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18814                    for diagnostic_entry in
18815                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18816                    {
18817                        let message = diagnostic_entry
18818                            .diagnostic
18819                            .message
18820                            .split_once('\n')
18821                            .map(|(line, _)| line)
18822                            .map(SharedString::new)
18823                            .unwrap_or_else(|| {
18824                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18825                            });
18826                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18827                        let (Ok(i) | Err(i)) = inline_diagnostics
18828                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18829                        inline_diagnostics.insert(
18830                            i,
18831                            (
18832                                start_anchor,
18833                                InlineDiagnostic {
18834                                    message,
18835                                    group_id: diagnostic_entry.diagnostic.group_id,
18836                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18837                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18838                                    severity: diagnostic_entry.diagnostic.severity,
18839                                },
18840                            ),
18841                        );
18842                    }
18843                    inline_diagnostics
18844                })
18845                .await;
18846
18847            editor
18848                .update(cx, |editor, cx| {
18849                    editor.inline_diagnostics = new_inline_diagnostics;
18850                    cx.notify();
18851                })
18852                .ok();
18853        });
18854    }
18855
18856    fn pull_diagnostics(
18857        &mut self,
18858        buffer_id: Option<BufferId>,
18859        window: &Window,
18860        cx: &mut Context<Self>,
18861    ) -> Option<()> {
18862        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18863            return None;
18864        }
18865        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18866            .diagnostics
18867            .lsp_pull_diagnostics;
18868        if !pull_diagnostics_settings.enabled {
18869            return None;
18870        }
18871        let project = self.project()?.downgrade();
18872
18873        let mut edited_buffer_ids = HashSet::default();
18874        let mut edited_worktree_ids = HashSet::default();
18875        let edited_buffers = match buffer_id {
18876            Some(buffer_id) => {
18877                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18878                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18879                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18880                edited_worktree_ids.insert(worktree_id);
18881                vec![buffer]
18882            }
18883            None => self
18884                .buffer()
18885                .read(cx)
18886                .all_buffers()
18887                .into_iter()
18888                .filter(|buffer| {
18889                    let buffer = buffer.read(cx);
18890                    match buffer.file().map(|f| f.worktree_id(cx)) {
18891                        Some(worktree_id) => {
18892                            edited_buffer_ids.insert(buffer.remote_id());
18893                            edited_worktree_ids.insert(worktree_id);
18894                            true
18895                        }
18896                        None => false,
18897                    }
18898                })
18899                .collect::<Vec<_>>(),
18900        };
18901
18902        if edited_buffers.is_empty() {
18903            self.pull_diagnostics_task = Task::ready(());
18904            self.pull_diagnostics_background_task = Task::ready(());
18905            return None;
18906        }
18907
18908        let mut already_used_buffers = HashSet::default();
18909        let related_open_buffers = self
18910            .workspace
18911            .as_ref()
18912            .and_then(|(workspace, _)| workspace.upgrade())
18913            .into_iter()
18914            .flat_map(|workspace| workspace.read(cx).panes())
18915            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18916            .filter(|editor| editor != &cx.entity())
18917            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18918            .filter(|buffer| {
18919                let buffer = buffer.read(cx);
18920                let buffer_id = buffer.remote_id();
18921                if already_used_buffers.insert(buffer_id) {
18922                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18923                        return !edited_buffer_ids.contains(&buffer_id)
18924                            && !edited_worktree_ids.contains(&worktree_id);
18925                    }
18926                }
18927                false
18928            })
18929            .collect::<Vec<_>>();
18930
18931        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18932        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18933            if buffers.is_empty() {
18934                return Task::ready(());
18935            }
18936            let project_weak = project.clone();
18937            cx.spawn_in(window, async move |_, cx| {
18938                cx.background_executor().timer(delay).await;
18939
18940                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18941                    buffers
18942                        .into_iter()
18943                        .filter_map(|buffer| {
18944                            project_weak
18945                                .update(cx, |project, cx| {
18946                                    project.lsp_store().update(cx, |lsp_store, cx| {
18947                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18948                                    })
18949                                })
18950                                .ok()
18951                        })
18952                        .collect::<FuturesUnordered<_>>()
18953                }) else {
18954                    return;
18955                };
18956
18957                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18958                    if let Err(e) = pull_task {
18959                        log::error!("Failed to update project diagnostics: {e:#}");
18960                    }
18961                }
18962            })
18963        };
18964
18965        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18966        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18967
18968        Some(())
18969    }
18970
18971    pub fn set_selections_from_remote(
18972        &mut self,
18973        selections: Vec<Selection<Anchor>>,
18974        pending_selection: Option<Selection<Anchor>>,
18975        window: &mut Window,
18976        cx: &mut Context<Self>,
18977    ) {
18978        let old_cursor_position = self.selections.newest_anchor().head();
18979        self.selections
18980            .change_with(&self.display_snapshot(cx), |s| {
18981                s.select_anchors(selections);
18982                if let Some(pending_selection) = pending_selection {
18983                    s.set_pending(pending_selection, SelectMode::Character);
18984                } else {
18985                    s.clear_pending();
18986                }
18987            });
18988        self.selections_did_change(
18989            false,
18990            &old_cursor_position,
18991            SelectionEffects::default(),
18992            window,
18993            cx,
18994        );
18995    }
18996
18997    pub fn transact(
18998        &mut self,
18999        window: &mut Window,
19000        cx: &mut Context<Self>,
19001        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19002    ) -> Option<TransactionId> {
19003        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19004            this.start_transaction_at(Instant::now(), window, cx);
19005            update(this, window, cx);
19006            this.end_transaction_at(Instant::now(), cx)
19007        })
19008    }
19009
19010    pub fn start_transaction_at(
19011        &mut self,
19012        now: Instant,
19013        window: &mut Window,
19014        cx: &mut Context<Self>,
19015    ) -> Option<TransactionId> {
19016        self.end_selection(window, cx);
19017        if let Some(tx_id) = self
19018            .buffer
19019            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19020        {
19021            self.selection_history
19022                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19023            cx.emit(EditorEvent::TransactionBegun {
19024                transaction_id: tx_id,
19025            });
19026            Some(tx_id)
19027        } else {
19028            None
19029        }
19030    }
19031
19032    pub fn end_transaction_at(
19033        &mut self,
19034        now: Instant,
19035        cx: &mut Context<Self>,
19036    ) -> Option<TransactionId> {
19037        if let Some(transaction_id) = self
19038            .buffer
19039            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19040        {
19041            if let Some((_, end_selections)) =
19042                self.selection_history.transaction_mut(transaction_id)
19043            {
19044                *end_selections = Some(self.selections.disjoint_anchors_arc());
19045            } else {
19046                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19047            }
19048
19049            cx.emit(EditorEvent::Edited { transaction_id });
19050            Some(transaction_id)
19051        } else {
19052            None
19053        }
19054    }
19055
19056    pub fn modify_transaction_selection_history(
19057        &mut self,
19058        transaction_id: TransactionId,
19059        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19060    ) -> bool {
19061        self.selection_history
19062            .transaction_mut(transaction_id)
19063            .map(modify)
19064            .is_some()
19065    }
19066
19067    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19068        if self.selection_mark_mode {
19069            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19070                s.move_with(|_, sel| {
19071                    sel.collapse_to(sel.head(), SelectionGoal::None);
19072                });
19073            })
19074        }
19075        self.selection_mark_mode = true;
19076        cx.notify();
19077    }
19078
19079    pub fn swap_selection_ends(
19080        &mut self,
19081        _: &actions::SwapSelectionEnds,
19082        window: &mut Window,
19083        cx: &mut Context<Self>,
19084    ) {
19085        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19086            s.move_with(|_, sel| {
19087                if sel.start != sel.end {
19088                    sel.reversed = !sel.reversed
19089                }
19090            });
19091        });
19092        self.request_autoscroll(Autoscroll::newest(), cx);
19093        cx.notify();
19094    }
19095
19096    pub fn toggle_focus(
19097        workspace: &mut Workspace,
19098        _: &actions::ToggleFocus,
19099        window: &mut Window,
19100        cx: &mut Context<Workspace>,
19101    ) {
19102        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19103            return;
19104        };
19105        workspace.activate_item(&item, true, true, window, cx);
19106    }
19107
19108    pub fn toggle_fold(
19109        &mut self,
19110        _: &actions::ToggleFold,
19111        window: &mut Window,
19112        cx: &mut Context<Self>,
19113    ) {
19114        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19115            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19116            let selection = self.selections.newest::<Point>(&display_map);
19117
19118            let range = if selection.is_empty() {
19119                let point = selection.head().to_display_point(&display_map);
19120                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19121                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19122                    .to_point(&display_map);
19123                start..end
19124            } else {
19125                selection.range()
19126            };
19127            if display_map.folds_in_range(range).next().is_some() {
19128                self.unfold_lines(&Default::default(), window, cx)
19129            } else {
19130                self.fold(&Default::default(), window, cx)
19131            }
19132        } else {
19133            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19134            let buffer_ids: HashSet<_> = self
19135                .selections
19136                .disjoint_anchor_ranges()
19137                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19138                .collect();
19139
19140            let should_unfold = buffer_ids
19141                .iter()
19142                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19143
19144            for buffer_id in buffer_ids {
19145                if should_unfold {
19146                    self.unfold_buffer(buffer_id, cx);
19147                } else {
19148                    self.fold_buffer(buffer_id, cx);
19149                }
19150            }
19151        }
19152    }
19153
19154    pub fn toggle_fold_recursive(
19155        &mut self,
19156        _: &actions::ToggleFoldRecursive,
19157        window: &mut Window,
19158        cx: &mut Context<Self>,
19159    ) {
19160        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19161
19162        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19163        let range = if selection.is_empty() {
19164            let point = selection.head().to_display_point(&display_map);
19165            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19166            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19167                .to_point(&display_map);
19168            start..end
19169        } else {
19170            selection.range()
19171        };
19172        if display_map.folds_in_range(range).next().is_some() {
19173            self.unfold_recursive(&Default::default(), window, cx)
19174        } else {
19175            self.fold_recursive(&Default::default(), window, cx)
19176        }
19177    }
19178
19179    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19180        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19181            let mut to_fold = Vec::new();
19182            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19183            let selections = self.selections.all_adjusted(&display_map);
19184
19185            for selection in selections {
19186                let range = selection.range().sorted();
19187                let buffer_start_row = range.start.row;
19188
19189                if range.start.row != range.end.row {
19190                    let mut found = false;
19191                    let mut row = range.start.row;
19192                    while row <= range.end.row {
19193                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19194                        {
19195                            found = true;
19196                            row = crease.range().end.row + 1;
19197                            to_fold.push(crease);
19198                        } else {
19199                            row += 1
19200                        }
19201                    }
19202                    if found {
19203                        continue;
19204                    }
19205                }
19206
19207                for row in (0..=range.start.row).rev() {
19208                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19209                        && crease.range().end.row >= buffer_start_row
19210                    {
19211                        to_fold.push(crease);
19212                        if row <= range.start.row {
19213                            break;
19214                        }
19215                    }
19216                }
19217            }
19218
19219            self.fold_creases(to_fold, true, window, cx);
19220        } else {
19221            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19222            let buffer_ids = self
19223                .selections
19224                .disjoint_anchor_ranges()
19225                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19226                .collect::<HashSet<_>>();
19227            for buffer_id in buffer_ids {
19228                self.fold_buffer(buffer_id, cx);
19229            }
19230        }
19231    }
19232
19233    pub fn toggle_fold_all(
19234        &mut self,
19235        _: &actions::ToggleFoldAll,
19236        window: &mut Window,
19237        cx: &mut Context<Self>,
19238    ) {
19239        if self.buffer.read(cx).is_singleton() {
19240            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19241            let has_folds = display_map
19242                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19243                .next()
19244                .is_some();
19245
19246            if has_folds {
19247                self.unfold_all(&actions::UnfoldAll, window, cx);
19248            } else {
19249                self.fold_all(&actions::FoldAll, window, cx);
19250            }
19251        } else {
19252            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19253            let should_unfold = buffer_ids
19254                .iter()
19255                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19256
19257            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19258                editor
19259                    .update_in(cx, |editor, _, cx| {
19260                        for buffer_id in buffer_ids {
19261                            if should_unfold {
19262                                editor.unfold_buffer(buffer_id, cx);
19263                            } else {
19264                                editor.fold_buffer(buffer_id, cx);
19265                            }
19266                        }
19267                    })
19268                    .ok();
19269            });
19270        }
19271    }
19272
19273    fn fold_at_level(
19274        &mut self,
19275        fold_at: &FoldAtLevel,
19276        window: &mut Window,
19277        cx: &mut Context<Self>,
19278    ) {
19279        if !self.buffer.read(cx).is_singleton() {
19280            return;
19281        }
19282
19283        let fold_at_level = fold_at.0;
19284        let snapshot = self.buffer.read(cx).snapshot(cx);
19285        let mut to_fold = Vec::new();
19286        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19287
19288        let row_ranges_to_keep: Vec<Range<u32>> = self
19289            .selections
19290            .all::<Point>(&self.display_snapshot(cx))
19291            .into_iter()
19292            .map(|sel| sel.start.row..sel.end.row)
19293            .collect();
19294
19295        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19296            while start_row < end_row {
19297                match self
19298                    .snapshot(window, cx)
19299                    .crease_for_buffer_row(MultiBufferRow(start_row))
19300                {
19301                    Some(crease) => {
19302                        let nested_start_row = crease.range().start.row + 1;
19303                        let nested_end_row = crease.range().end.row;
19304
19305                        if current_level < fold_at_level {
19306                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19307                        } else if current_level == fold_at_level {
19308                            // Fold iff there is no selection completely contained within the fold region
19309                            if !row_ranges_to_keep.iter().any(|selection| {
19310                                selection.end >= nested_start_row
19311                                    && selection.start <= nested_end_row
19312                            }) {
19313                                to_fold.push(crease);
19314                            }
19315                        }
19316
19317                        start_row = nested_end_row + 1;
19318                    }
19319                    None => start_row += 1,
19320                }
19321            }
19322        }
19323
19324        self.fold_creases(to_fold, true, window, cx);
19325    }
19326
19327    pub fn fold_at_level_1(
19328        &mut self,
19329        _: &actions::FoldAtLevel1,
19330        window: &mut Window,
19331        cx: &mut Context<Self>,
19332    ) {
19333        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19334    }
19335
19336    pub fn fold_at_level_2(
19337        &mut self,
19338        _: &actions::FoldAtLevel2,
19339        window: &mut Window,
19340        cx: &mut Context<Self>,
19341    ) {
19342        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19343    }
19344
19345    pub fn fold_at_level_3(
19346        &mut self,
19347        _: &actions::FoldAtLevel3,
19348        window: &mut Window,
19349        cx: &mut Context<Self>,
19350    ) {
19351        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19352    }
19353
19354    pub fn fold_at_level_4(
19355        &mut self,
19356        _: &actions::FoldAtLevel4,
19357        window: &mut Window,
19358        cx: &mut Context<Self>,
19359    ) {
19360        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19361    }
19362
19363    pub fn fold_at_level_5(
19364        &mut self,
19365        _: &actions::FoldAtLevel5,
19366        window: &mut Window,
19367        cx: &mut Context<Self>,
19368    ) {
19369        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19370    }
19371
19372    pub fn fold_at_level_6(
19373        &mut self,
19374        _: &actions::FoldAtLevel6,
19375        window: &mut Window,
19376        cx: &mut Context<Self>,
19377    ) {
19378        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19379    }
19380
19381    pub fn fold_at_level_7(
19382        &mut self,
19383        _: &actions::FoldAtLevel7,
19384        window: &mut Window,
19385        cx: &mut Context<Self>,
19386    ) {
19387        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19388    }
19389
19390    pub fn fold_at_level_8(
19391        &mut self,
19392        _: &actions::FoldAtLevel8,
19393        window: &mut Window,
19394        cx: &mut Context<Self>,
19395    ) {
19396        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19397    }
19398
19399    pub fn fold_at_level_9(
19400        &mut self,
19401        _: &actions::FoldAtLevel9,
19402        window: &mut Window,
19403        cx: &mut Context<Self>,
19404    ) {
19405        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19406    }
19407
19408    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19409        if self.buffer.read(cx).is_singleton() {
19410            let mut fold_ranges = Vec::new();
19411            let snapshot = self.buffer.read(cx).snapshot(cx);
19412
19413            for row in 0..snapshot.max_row().0 {
19414                if let Some(foldable_range) = self
19415                    .snapshot(window, cx)
19416                    .crease_for_buffer_row(MultiBufferRow(row))
19417                {
19418                    fold_ranges.push(foldable_range);
19419                }
19420            }
19421
19422            self.fold_creases(fold_ranges, true, window, cx);
19423        } else {
19424            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19425                editor
19426                    .update_in(cx, |editor, _, cx| {
19427                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19428                            editor.fold_buffer(buffer_id, cx);
19429                        }
19430                    })
19431                    .ok();
19432            });
19433        }
19434    }
19435
19436    pub fn fold_function_bodies(
19437        &mut self,
19438        _: &actions::FoldFunctionBodies,
19439        window: &mut Window,
19440        cx: &mut Context<Self>,
19441    ) {
19442        let snapshot = self.buffer.read(cx).snapshot(cx);
19443
19444        let ranges = snapshot
19445            .text_object_ranges(
19446                MultiBufferOffset(0)..snapshot.len(),
19447                TreeSitterOptions::default(),
19448            )
19449            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19450            .collect::<Vec<_>>();
19451
19452        let creases = ranges
19453            .into_iter()
19454            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19455            .collect();
19456
19457        self.fold_creases(creases, true, window, cx);
19458    }
19459
19460    pub fn fold_recursive(
19461        &mut self,
19462        _: &actions::FoldRecursive,
19463        window: &mut Window,
19464        cx: &mut Context<Self>,
19465    ) {
19466        let mut to_fold = Vec::new();
19467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19468        let selections = self.selections.all_adjusted(&display_map);
19469
19470        for selection in selections {
19471            let range = selection.range().sorted();
19472            let buffer_start_row = range.start.row;
19473
19474            if range.start.row != range.end.row {
19475                let mut found = false;
19476                for row in range.start.row..=range.end.row {
19477                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19478                        found = true;
19479                        to_fold.push(crease);
19480                    }
19481                }
19482                if found {
19483                    continue;
19484                }
19485            }
19486
19487            for row in (0..=range.start.row).rev() {
19488                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19489                    if crease.range().end.row >= buffer_start_row {
19490                        to_fold.push(crease);
19491                    } else {
19492                        break;
19493                    }
19494                }
19495            }
19496        }
19497
19498        self.fold_creases(to_fold, true, window, cx);
19499    }
19500
19501    pub fn fold_at(
19502        &mut self,
19503        buffer_row: MultiBufferRow,
19504        window: &mut Window,
19505        cx: &mut Context<Self>,
19506    ) {
19507        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19508
19509        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19510            let autoscroll = self
19511                .selections
19512                .all::<Point>(&display_map)
19513                .iter()
19514                .any(|selection| crease.range().overlaps(&selection.range()));
19515
19516            self.fold_creases(vec![crease], autoscroll, window, cx);
19517        }
19518    }
19519
19520    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19521        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19522            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19523            let buffer = display_map.buffer_snapshot();
19524            let selections = self.selections.all::<Point>(&display_map);
19525            let ranges = selections
19526                .iter()
19527                .map(|s| {
19528                    let range = s.display_range(&display_map).sorted();
19529                    let mut start = range.start.to_point(&display_map);
19530                    let mut end = range.end.to_point(&display_map);
19531                    start.column = 0;
19532                    end.column = buffer.line_len(MultiBufferRow(end.row));
19533                    start..end
19534                })
19535                .collect::<Vec<_>>();
19536
19537            self.unfold_ranges(&ranges, true, true, cx);
19538        } else {
19539            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19540            let buffer_ids = self
19541                .selections
19542                .disjoint_anchor_ranges()
19543                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19544                .collect::<HashSet<_>>();
19545            for buffer_id in buffer_ids {
19546                self.unfold_buffer(buffer_id, cx);
19547            }
19548        }
19549    }
19550
19551    pub fn unfold_recursive(
19552        &mut self,
19553        _: &UnfoldRecursive,
19554        _window: &mut Window,
19555        cx: &mut Context<Self>,
19556    ) {
19557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19558        let selections = self.selections.all::<Point>(&display_map);
19559        let ranges = selections
19560            .iter()
19561            .map(|s| {
19562                let mut range = s.display_range(&display_map).sorted();
19563                *range.start.column_mut() = 0;
19564                *range.end.column_mut() = display_map.line_len(range.end.row());
19565                let start = range.start.to_point(&display_map);
19566                let end = range.end.to_point(&display_map);
19567                start..end
19568            })
19569            .collect::<Vec<_>>();
19570
19571        self.unfold_ranges(&ranges, true, true, cx);
19572    }
19573
19574    pub fn unfold_at(
19575        &mut self,
19576        buffer_row: MultiBufferRow,
19577        _window: &mut Window,
19578        cx: &mut Context<Self>,
19579    ) {
19580        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19581
19582        let intersection_range = Point::new(buffer_row.0, 0)
19583            ..Point::new(
19584                buffer_row.0,
19585                display_map.buffer_snapshot().line_len(buffer_row),
19586            );
19587
19588        let autoscroll = self
19589            .selections
19590            .all::<Point>(&display_map)
19591            .iter()
19592            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19593
19594        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19595    }
19596
19597    pub fn unfold_all(
19598        &mut self,
19599        _: &actions::UnfoldAll,
19600        _window: &mut Window,
19601        cx: &mut Context<Self>,
19602    ) {
19603        if self.buffer.read(cx).is_singleton() {
19604            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19605            self.unfold_ranges(
19606                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19607                true,
19608                true,
19609                cx,
19610            );
19611        } else {
19612            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19613                editor
19614                    .update(cx, |editor, cx| {
19615                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19616                            editor.unfold_buffer(buffer_id, cx);
19617                        }
19618                    })
19619                    .ok();
19620            });
19621        }
19622    }
19623
19624    pub fn fold_selected_ranges(
19625        &mut self,
19626        _: &FoldSelectedRanges,
19627        window: &mut Window,
19628        cx: &mut Context<Self>,
19629    ) {
19630        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19631        let selections = self.selections.all_adjusted(&display_map);
19632        let ranges = selections
19633            .into_iter()
19634            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19635            .collect::<Vec<_>>();
19636        self.fold_creases(ranges, true, window, cx);
19637    }
19638
19639    pub fn fold_ranges<T: ToOffset + Clone>(
19640        &mut self,
19641        ranges: Vec<Range<T>>,
19642        auto_scroll: bool,
19643        window: &mut Window,
19644        cx: &mut Context<Self>,
19645    ) {
19646        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19647        let ranges = ranges
19648            .into_iter()
19649            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19650            .collect::<Vec<_>>();
19651        self.fold_creases(ranges, auto_scroll, window, cx);
19652    }
19653
19654    pub fn fold_creases<T: ToOffset + Clone>(
19655        &mut self,
19656        creases: Vec<Crease<T>>,
19657        auto_scroll: bool,
19658        _window: &mut Window,
19659        cx: &mut Context<Self>,
19660    ) {
19661        if creases.is_empty() {
19662            return;
19663        }
19664
19665        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19666
19667        if auto_scroll {
19668            self.request_autoscroll(Autoscroll::fit(), cx);
19669        }
19670
19671        cx.notify();
19672
19673        self.scrollbar_marker_state.dirty = true;
19674        self.folds_did_change(cx);
19675    }
19676
19677    /// Removes any folds whose ranges intersect any of the given ranges.
19678    pub fn unfold_ranges<T: ToOffset + Clone>(
19679        &mut self,
19680        ranges: &[Range<T>],
19681        inclusive: bool,
19682        auto_scroll: bool,
19683        cx: &mut Context<Self>,
19684    ) {
19685        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19686            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19687        });
19688        self.folds_did_change(cx);
19689    }
19690
19691    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19692        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19693            return;
19694        }
19695
19696        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19697        self.display_map.update(cx, |display_map, cx| {
19698            display_map.fold_buffers([buffer_id], cx)
19699        });
19700
19701        let snapshot = self.display_snapshot(cx);
19702        self.selections.change_with(&snapshot, |selections| {
19703            selections.remove_selections_from_buffer(buffer_id);
19704        });
19705
19706        cx.emit(EditorEvent::BufferFoldToggled {
19707            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19708            folded: true,
19709        });
19710        cx.notify();
19711    }
19712
19713    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19714        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19715            return;
19716        }
19717        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19718        self.display_map.update(cx, |display_map, cx| {
19719            display_map.unfold_buffers([buffer_id], cx);
19720        });
19721        cx.emit(EditorEvent::BufferFoldToggled {
19722            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19723            folded: false,
19724        });
19725        cx.notify();
19726    }
19727
19728    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19729        self.display_map.read(cx).is_buffer_folded(buffer)
19730    }
19731
19732    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19733        self.display_map.read(cx).folded_buffers()
19734    }
19735
19736    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19737        self.display_map.update(cx, |display_map, cx| {
19738            display_map.disable_header_for_buffer(buffer_id, cx);
19739        });
19740        cx.notify();
19741    }
19742
19743    /// Removes any folds with the given ranges.
19744    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19745        &mut self,
19746        ranges: &[Range<T>],
19747        type_id: TypeId,
19748        auto_scroll: bool,
19749        cx: &mut Context<Self>,
19750    ) {
19751        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19752            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19753        });
19754        self.folds_did_change(cx);
19755    }
19756
19757    fn remove_folds_with<T: ToOffset + Clone>(
19758        &mut self,
19759        ranges: &[Range<T>],
19760        auto_scroll: bool,
19761        cx: &mut Context<Self>,
19762        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19763    ) {
19764        if ranges.is_empty() {
19765            return;
19766        }
19767
19768        let mut buffers_affected = HashSet::default();
19769        let multi_buffer = self.buffer().read(cx);
19770        for range in ranges {
19771            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19772                buffers_affected.insert(buffer.read(cx).remote_id());
19773            };
19774        }
19775
19776        self.display_map.update(cx, update);
19777
19778        if auto_scroll {
19779            self.request_autoscroll(Autoscroll::fit(), cx);
19780        }
19781
19782        cx.notify();
19783        self.scrollbar_marker_state.dirty = true;
19784        self.active_indent_guides_state.dirty = true;
19785    }
19786
19787    pub fn update_renderer_widths(
19788        &mut self,
19789        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19790        cx: &mut Context<Self>,
19791    ) -> bool {
19792        self.display_map
19793            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19794    }
19795
19796    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19797        self.display_map.read(cx).fold_placeholder.clone()
19798    }
19799
19800    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19801        self.use_base_text_line_numbers = show;
19802    }
19803
19804    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19805        self.buffer.update(cx, |buffer, cx| {
19806            buffer.set_all_diff_hunks_expanded(cx);
19807        });
19808    }
19809
19810    pub fn expand_all_diff_hunks(
19811        &mut self,
19812        _: &ExpandAllDiffHunks,
19813        _window: &mut Window,
19814        cx: &mut Context<Self>,
19815    ) {
19816        self.buffer.update(cx, |buffer, cx| {
19817            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19818        });
19819    }
19820
19821    pub fn collapse_all_diff_hunks(
19822        &mut self,
19823        _: &CollapseAllDiffHunks,
19824        _window: &mut Window,
19825        cx: &mut Context<Self>,
19826    ) {
19827        self.buffer.update(cx, |buffer, cx| {
19828            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19829        });
19830    }
19831
19832    pub fn toggle_selected_diff_hunks(
19833        &mut self,
19834        _: &ToggleSelectedDiffHunks,
19835        _window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        let ranges: Vec<_> = self
19839            .selections
19840            .disjoint_anchors()
19841            .iter()
19842            .map(|s| s.range())
19843            .collect();
19844        self.toggle_diff_hunks_in_ranges(ranges, cx);
19845    }
19846
19847    pub fn diff_hunks_in_ranges<'a>(
19848        &'a self,
19849        ranges: &'a [Range<Anchor>],
19850        buffer: &'a MultiBufferSnapshot,
19851    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19852        ranges.iter().flat_map(move |range| {
19853            let end_excerpt_id = range.end.excerpt_id;
19854            let range = range.to_point(buffer);
19855            let mut peek_end = range.end;
19856            if range.end.row < buffer.max_row().0 {
19857                peek_end = Point::new(range.end.row + 1, 0);
19858            }
19859            buffer
19860                .diff_hunks_in_range(range.start..peek_end)
19861                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19862        })
19863    }
19864
19865    pub fn has_stageable_diff_hunks_in_ranges(
19866        &self,
19867        ranges: &[Range<Anchor>],
19868        snapshot: &MultiBufferSnapshot,
19869    ) -> bool {
19870        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19871        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19872    }
19873
19874    pub fn toggle_staged_selected_diff_hunks(
19875        &mut self,
19876        _: &::git::ToggleStaged,
19877        _: &mut Window,
19878        cx: &mut Context<Self>,
19879    ) {
19880        let snapshot = self.buffer.read(cx).snapshot(cx);
19881        let ranges: Vec<_> = self
19882            .selections
19883            .disjoint_anchors()
19884            .iter()
19885            .map(|s| s.range())
19886            .collect();
19887        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19888        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19889    }
19890
19891    pub fn set_render_diff_hunk_controls(
19892        &mut self,
19893        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19894        cx: &mut Context<Self>,
19895    ) {
19896        self.render_diff_hunk_controls = render_diff_hunk_controls;
19897        cx.notify();
19898    }
19899
19900    pub fn stage_and_next(
19901        &mut self,
19902        _: &::git::StageAndNext,
19903        window: &mut Window,
19904        cx: &mut Context<Self>,
19905    ) {
19906        self.do_stage_or_unstage_and_next(true, window, cx);
19907    }
19908
19909    pub fn unstage_and_next(
19910        &mut self,
19911        _: &::git::UnstageAndNext,
19912        window: &mut Window,
19913        cx: &mut Context<Self>,
19914    ) {
19915        self.do_stage_or_unstage_and_next(false, window, cx);
19916    }
19917
19918    pub fn stage_or_unstage_diff_hunks(
19919        &mut self,
19920        stage: bool,
19921        ranges: Vec<Range<Anchor>>,
19922        cx: &mut Context<Self>,
19923    ) {
19924        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19925        cx.spawn(async move |this, cx| {
19926            task.await?;
19927            this.update(cx, |this, cx| {
19928                let snapshot = this.buffer.read(cx).snapshot(cx);
19929                let chunk_by = this
19930                    .diff_hunks_in_ranges(&ranges, &snapshot)
19931                    .chunk_by(|hunk| hunk.buffer_id);
19932                for (buffer_id, hunks) in &chunk_by {
19933                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19934                }
19935            })
19936        })
19937        .detach_and_log_err(cx);
19938    }
19939
19940    fn save_buffers_for_ranges_if_needed(
19941        &mut self,
19942        ranges: &[Range<Anchor>],
19943        cx: &mut Context<Editor>,
19944    ) -> Task<Result<()>> {
19945        let multibuffer = self.buffer.read(cx);
19946        let snapshot = multibuffer.read(cx);
19947        let buffer_ids: HashSet<_> = ranges
19948            .iter()
19949            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19950            .collect();
19951        drop(snapshot);
19952
19953        let mut buffers = HashSet::default();
19954        for buffer_id in buffer_ids {
19955            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19956                let buffer = buffer_entity.read(cx);
19957                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19958                {
19959                    buffers.insert(buffer_entity);
19960                }
19961            }
19962        }
19963
19964        if let Some(project) = &self.project {
19965            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19966        } else {
19967            Task::ready(Ok(()))
19968        }
19969    }
19970
19971    fn do_stage_or_unstage_and_next(
19972        &mut self,
19973        stage: bool,
19974        window: &mut Window,
19975        cx: &mut Context<Self>,
19976    ) {
19977        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19978
19979        if ranges.iter().any(|range| range.start != range.end) {
19980            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19981            return;
19982        }
19983
19984        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19985        let snapshot = self.snapshot(window, cx);
19986        let position = self
19987            .selections
19988            .newest::<Point>(&snapshot.display_snapshot)
19989            .head();
19990        let mut row = snapshot
19991            .buffer_snapshot()
19992            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19993            .find(|hunk| hunk.row_range.start.0 > position.row)
19994            .map(|hunk| hunk.row_range.start);
19995
19996        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19997        // Outside of the project diff editor, wrap around to the beginning.
19998        if !all_diff_hunks_expanded {
19999            row = row.or_else(|| {
20000                snapshot
20001                    .buffer_snapshot()
20002                    .diff_hunks_in_range(Point::zero()..position)
20003                    .find(|hunk| hunk.row_range.end.0 < position.row)
20004                    .map(|hunk| hunk.row_range.start)
20005            });
20006        }
20007
20008        if let Some(row) = row {
20009            let destination = Point::new(row.0, 0);
20010            let autoscroll = Autoscroll::center();
20011
20012            self.unfold_ranges(&[destination..destination], false, false, cx);
20013            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20014                s.select_ranges([destination..destination]);
20015            });
20016        }
20017    }
20018
20019    fn do_stage_or_unstage(
20020        &self,
20021        stage: bool,
20022        buffer_id: BufferId,
20023        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20024        cx: &mut App,
20025    ) -> Option<()> {
20026        let project = self.project()?;
20027        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20028        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20029        let buffer_snapshot = buffer.read(cx).snapshot();
20030        let file_exists = buffer_snapshot
20031            .file()
20032            .is_some_and(|file| file.disk_state().exists());
20033        diff.update(cx, |diff, cx| {
20034            diff.stage_or_unstage_hunks(
20035                stage,
20036                &hunks
20037                    .map(|hunk| buffer_diff::DiffHunk {
20038                        buffer_range: hunk.buffer_range,
20039                        // We don't need to pass in word diffs here because they're only used for rendering and
20040                        // this function changes internal state
20041                        base_word_diffs: Vec::default(),
20042                        buffer_word_diffs: Vec::default(),
20043                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20044                            ..hunk.diff_base_byte_range.end.0,
20045                        secondary_status: hunk.secondary_status,
20046                        range: Point::zero()..Point::zero(), // unused
20047                    })
20048                    .collect::<Vec<_>>(),
20049                &buffer_snapshot,
20050                file_exists,
20051                cx,
20052            )
20053        });
20054        None
20055    }
20056
20057    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20058        let ranges: Vec<_> = self
20059            .selections
20060            .disjoint_anchors()
20061            .iter()
20062            .map(|s| s.range())
20063            .collect();
20064        self.buffer
20065            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20066    }
20067
20068    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20069        self.buffer.update(cx, |buffer, cx| {
20070            let ranges = vec![Anchor::min()..Anchor::max()];
20071            if !buffer.all_diff_hunks_expanded()
20072                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20073            {
20074                buffer.collapse_diff_hunks(ranges, cx);
20075                true
20076            } else {
20077                false
20078            }
20079        })
20080    }
20081
20082    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20083        if self.buffer.read(cx).all_diff_hunks_expanded() {
20084            return true;
20085        }
20086        let ranges = vec![Anchor::min()..Anchor::max()];
20087        self.buffer
20088            .read(cx)
20089            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20090    }
20091
20092    fn toggle_diff_hunks_in_ranges(
20093        &mut self,
20094        ranges: Vec<Range<Anchor>>,
20095        cx: &mut Context<Editor>,
20096    ) {
20097        self.buffer.update(cx, |buffer, cx| {
20098            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20099            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20100        })
20101    }
20102
20103    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20104        self.buffer.update(cx, |buffer, cx| {
20105            let snapshot = buffer.snapshot(cx);
20106            let excerpt_id = range.end.excerpt_id;
20107            let point_range = range.to_point(&snapshot);
20108            let expand = !buffer.single_hunk_is_expanded(range, cx);
20109            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20110        })
20111    }
20112
20113    pub(crate) fn apply_all_diff_hunks(
20114        &mut self,
20115        _: &ApplyAllDiffHunks,
20116        window: &mut Window,
20117        cx: &mut Context<Self>,
20118    ) {
20119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20120
20121        let buffers = self.buffer.read(cx).all_buffers();
20122        for branch_buffer in buffers {
20123            branch_buffer.update(cx, |branch_buffer, cx| {
20124                branch_buffer.merge_into_base(Vec::new(), cx);
20125            });
20126        }
20127
20128        if let Some(project) = self.project.clone() {
20129            self.save(
20130                SaveOptions {
20131                    format: true,
20132                    autosave: false,
20133                },
20134                project,
20135                window,
20136                cx,
20137            )
20138            .detach_and_log_err(cx);
20139        }
20140    }
20141
20142    pub(crate) fn apply_selected_diff_hunks(
20143        &mut self,
20144        _: &ApplyDiffHunk,
20145        window: &mut Window,
20146        cx: &mut Context<Self>,
20147    ) {
20148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20149        let snapshot = self.snapshot(window, cx);
20150        let hunks = snapshot.hunks_for_ranges(
20151            self.selections
20152                .all(&snapshot.display_snapshot)
20153                .into_iter()
20154                .map(|selection| selection.range()),
20155        );
20156        let mut ranges_by_buffer = HashMap::default();
20157        self.transact(window, cx, |editor, _window, cx| {
20158            for hunk in hunks {
20159                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20160                    ranges_by_buffer
20161                        .entry(buffer.clone())
20162                        .or_insert_with(Vec::new)
20163                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20164                }
20165            }
20166
20167            for (buffer, ranges) in ranges_by_buffer {
20168                buffer.update(cx, |buffer, cx| {
20169                    buffer.merge_into_base(ranges, cx);
20170                });
20171            }
20172        });
20173
20174        if let Some(project) = self.project.clone() {
20175            self.save(
20176                SaveOptions {
20177                    format: true,
20178                    autosave: false,
20179                },
20180                project,
20181                window,
20182                cx,
20183            )
20184            .detach_and_log_err(cx);
20185        }
20186    }
20187
20188    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20189        if hovered != self.gutter_hovered {
20190            self.gutter_hovered = hovered;
20191            cx.notify();
20192        }
20193    }
20194
20195    pub fn insert_blocks(
20196        &mut self,
20197        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20198        autoscroll: Option<Autoscroll>,
20199        cx: &mut Context<Self>,
20200    ) -> Vec<CustomBlockId> {
20201        let blocks = self
20202            .display_map
20203            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20204        if let Some(autoscroll) = autoscroll {
20205            self.request_autoscroll(autoscroll, cx);
20206        }
20207        cx.notify();
20208        blocks
20209    }
20210
20211    pub fn resize_blocks(
20212        &mut self,
20213        heights: HashMap<CustomBlockId, u32>,
20214        autoscroll: Option<Autoscroll>,
20215        cx: &mut Context<Self>,
20216    ) {
20217        self.display_map
20218            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20219        if let Some(autoscroll) = autoscroll {
20220            self.request_autoscroll(autoscroll, cx);
20221        }
20222        cx.notify();
20223    }
20224
20225    pub fn replace_blocks(
20226        &mut self,
20227        renderers: HashMap<CustomBlockId, RenderBlock>,
20228        autoscroll: Option<Autoscroll>,
20229        cx: &mut Context<Self>,
20230    ) {
20231        self.display_map
20232            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20233        if let Some(autoscroll) = autoscroll {
20234            self.request_autoscroll(autoscroll, cx);
20235        }
20236        cx.notify();
20237    }
20238
20239    pub fn remove_blocks(
20240        &mut self,
20241        block_ids: HashSet<CustomBlockId>,
20242        autoscroll: Option<Autoscroll>,
20243        cx: &mut Context<Self>,
20244    ) {
20245        self.display_map.update(cx, |display_map, cx| {
20246            display_map.remove_blocks(block_ids, cx)
20247        });
20248        if let Some(autoscroll) = autoscroll {
20249            self.request_autoscroll(autoscroll, cx);
20250        }
20251        cx.notify();
20252    }
20253
20254    pub fn row_for_block(
20255        &self,
20256        block_id: CustomBlockId,
20257        cx: &mut Context<Self>,
20258    ) -> Option<DisplayRow> {
20259        self.display_map
20260            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20261    }
20262
20263    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20264        self.focused_block = Some(focused_block);
20265    }
20266
20267    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20268        self.focused_block.take()
20269    }
20270
20271    pub fn insert_creases(
20272        &mut self,
20273        creases: impl IntoIterator<Item = Crease<Anchor>>,
20274        cx: &mut Context<Self>,
20275    ) -> Vec<CreaseId> {
20276        self.display_map
20277            .update(cx, |map, cx| map.insert_creases(creases, cx))
20278    }
20279
20280    pub fn remove_creases(
20281        &mut self,
20282        ids: impl IntoIterator<Item = CreaseId>,
20283        cx: &mut Context<Self>,
20284    ) -> Vec<(CreaseId, Range<Anchor>)> {
20285        self.display_map
20286            .update(cx, |map, cx| map.remove_creases(ids, cx))
20287    }
20288
20289    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20290        self.display_map
20291            .update(cx, |map, cx| map.snapshot(cx))
20292            .longest_row()
20293    }
20294
20295    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20296        self.display_map
20297            .update(cx, |map, cx| map.snapshot(cx))
20298            .max_point()
20299    }
20300
20301    pub fn text(&self, cx: &App) -> String {
20302        self.buffer.read(cx).read(cx).text()
20303    }
20304
20305    pub fn is_empty(&self, cx: &App) -> bool {
20306        self.buffer.read(cx).read(cx).is_empty()
20307    }
20308
20309    pub fn text_option(&self, cx: &App) -> Option<String> {
20310        let text = self.text(cx);
20311        let text = text.trim();
20312
20313        if text.is_empty() {
20314            return None;
20315        }
20316
20317        Some(text.to_string())
20318    }
20319
20320    pub fn set_text(
20321        &mut self,
20322        text: impl Into<Arc<str>>,
20323        window: &mut Window,
20324        cx: &mut Context<Self>,
20325    ) {
20326        self.transact(window, cx, |this, _, cx| {
20327            this.buffer
20328                .read(cx)
20329                .as_singleton()
20330                .expect("you can only call set_text on editors for singleton buffers")
20331                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20332        });
20333    }
20334
20335    pub fn display_text(&self, cx: &mut App) -> String {
20336        self.display_map
20337            .update(cx, |map, cx| map.snapshot(cx))
20338            .text()
20339    }
20340
20341    fn create_minimap(
20342        &self,
20343        minimap_settings: MinimapSettings,
20344        window: &mut Window,
20345        cx: &mut Context<Self>,
20346    ) -> Option<Entity<Self>> {
20347        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20348            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20349    }
20350
20351    fn initialize_new_minimap(
20352        &self,
20353        minimap_settings: MinimapSettings,
20354        window: &mut Window,
20355        cx: &mut Context<Self>,
20356    ) -> Entity<Self> {
20357        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20358
20359        let mut minimap = Editor::new_internal(
20360            EditorMode::Minimap {
20361                parent: cx.weak_entity(),
20362            },
20363            self.buffer.clone(),
20364            None,
20365            Some(self.display_map.clone()),
20366            window,
20367            cx,
20368        );
20369        minimap.scroll_manager.clone_state(&self.scroll_manager);
20370        minimap.set_text_style_refinement(TextStyleRefinement {
20371            font_size: Some(MINIMAP_FONT_SIZE),
20372            font_weight: Some(MINIMAP_FONT_WEIGHT),
20373            ..Default::default()
20374        });
20375        minimap.update_minimap_configuration(minimap_settings, cx);
20376        cx.new(|_| minimap)
20377    }
20378
20379    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20380        let current_line_highlight = minimap_settings
20381            .current_line_highlight
20382            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20383        self.set_current_line_highlight(Some(current_line_highlight));
20384    }
20385
20386    pub fn minimap(&self) -> Option<&Entity<Self>> {
20387        self.minimap
20388            .as_ref()
20389            .filter(|_| self.minimap_visibility.visible())
20390    }
20391
20392    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20393        let mut wrap_guides = smallvec![];
20394
20395        if self.show_wrap_guides == Some(false) {
20396            return wrap_guides;
20397        }
20398
20399        let settings = self.buffer.read(cx).language_settings(cx);
20400        if settings.show_wrap_guides {
20401            match self.soft_wrap_mode(cx) {
20402                SoftWrap::Column(soft_wrap) => {
20403                    wrap_guides.push((soft_wrap as usize, true));
20404                }
20405                SoftWrap::Bounded(soft_wrap) => {
20406                    wrap_guides.push((soft_wrap as usize, true));
20407                }
20408                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20409            }
20410            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20411        }
20412
20413        wrap_guides
20414    }
20415
20416    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20417        let settings = self.buffer.read(cx).language_settings(cx);
20418        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20419        match mode {
20420            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20421                SoftWrap::None
20422            }
20423            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20424            language_settings::SoftWrap::PreferredLineLength => {
20425                SoftWrap::Column(settings.preferred_line_length)
20426            }
20427            language_settings::SoftWrap::Bounded => {
20428                SoftWrap::Bounded(settings.preferred_line_length)
20429            }
20430        }
20431    }
20432
20433    pub fn set_soft_wrap_mode(
20434        &mut self,
20435        mode: language_settings::SoftWrap,
20436
20437        cx: &mut Context<Self>,
20438    ) {
20439        self.soft_wrap_mode_override = Some(mode);
20440        cx.notify();
20441    }
20442
20443    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20444        self.hard_wrap = hard_wrap;
20445        cx.notify();
20446    }
20447
20448    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20449        self.text_style_refinement = Some(style);
20450    }
20451
20452    /// called by the Element so we know what style we were most recently rendered with.
20453    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20454        // We intentionally do not inform the display map about the minimap style
20455        // so that wrapping is not recalculated and stays consistent for the editor
20456        // and its linked minimap.
20457        if !self.mode.is_minimap() {
20458            let font = style.text.font();
20459            let font_size = style.text.font_size.to_pixels(window.rem_size());
20460            let display_map = self
20461                .placeholder_display_map
20462                .as_ref()
20463                .filter(|_| self.is_empty(cx))
20464                .unwrap_or(&self.display_map);
20465
20466            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20467        }
20468        self.style = Some(style);
20469    }
20470
20471    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20472        if self.style.is_none() {
20473            self.style = Some(self.create_style(cx));
20474        }
20475        self.style.as_ref().unwrap()
20476    }
20477
20478    // Called by the element. This method is not designed to be called outside of the editor
20479    // element's layout code because it does not notify when rewrapping is computed synchronously.
20480    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20481        if self.is_empty(cx) {
20482            self.placeholder_display_map
20483                .as_ref()
20484                .map_or(false, |display_map| {
20485                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20486                })
20487        } else {
20488            self.display_map
20489                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20490        }
20491    }
20492
20493    pub fn set_soft_wrap(&mut self) {
20494        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20495    }
20496
20497    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20498        if self.soft_wrap_mode_override.is_some() {
20499            self.soft_wrap_mode_override.take();
20500        } else {
20501            let soft_wrap = match self.soft_wrap_mode(cx) {
20502                SoftWrap::GitDiff => return,
20503                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20504                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20505                    language_settings::SoftWrap::None
20506                }
20507            };
20508            self.soft_wrap_mode_override = Some(soft_wrap);
20509        }
20510        cx.notify();
20511    }
20512
20513    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20514        let Some(workspace) = self.workspace() else {
20515            return;
20516        };
20517        let fs = workspace.read(cx).app_state().fs.clone();
20518        let current_show = TabBarSettings::get_global(cx).show;
20519        update_settings_file(fs, cx, move |setting, _| {
20520            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20521        });
20522    }
20523
20524    pub fn toggle_indent_guides(
20525        &mut self,
20526        _: &ToggleIndentGuides,
20527        _: &mut Window,
20528        cx: &mut Context<Self>,
20529    ) {
20530        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20531            self.buffer
20532                .read(cx)
20533                .language_settings(cx)
20534                .indent_guides
20535                .enabled
20536        });
20537        self.show_indent_guides = Some(!currently_enabled);
20538        cx.notify();
20539    }
20540
20541    fn should_show_indent_guides(&self) -> Option<bool> {
20542        self.show_indent_guides
20543    }
20544
20545    pub fn disable_indent_guides_for_buffer(
20546        &mut self,
20547        buffer_id: BufferId,
20548        cx: &mut Context<Self>,
20549    ) {
20550        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20551        cx.notify();
20552    }
20553
20554    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20555        self.buffers_with_disabled_indent_guides
20556            .contains(&buffer_id)
20557    }
20558
20559    pub fn toggle_line_numbers(
20560        &mut self,
20561        _: &ToggleLineNumbers,
20562        _: &mut Window,
20563        cx: &mut Context<Self>,
20564    ) {
20565        let mut editor_settings = EditorSettings::get_global(cx).clone();
20566        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20567        EditorSettings::override_global(editor_settings, cx);
20568    }
20569
20570    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20571        if let Some(show_line_numbers) = self.show_line_numbers {
20572            return show_line_numbers;
20573        }
20574        EditorSettings::get_global(cx).gutter.line_numbers
20575    }
20576
20577    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20578        match (
20579            self.use_relative_line_numbers,
20580            EditorSettings::get_global(cx).relative_line_numbers,
20581        ) {
20582            (None, setting) => setting,
20583            (Some(false), _) => RelativeLineNumbers::Disabled,
20584            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20585            (Some(true), _) => RelativeLineNumbers::Enabled,
20586        }
20587    }
20588
20589    pub fn toggle_relative_line_numbers(
20590        &mut self,
20591        _: &ToggleRelativeLineNumbers,
20592        _: &mut Window,
20593        cx: &mut Context<Self>,
20594    ) {
20595        let is_relative = self.relative_line_numbers(cx);
20596        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20597    }
20598
20599    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20600        self.use_relative_line_numbers = is_relative;
20601        cx.notify();
20602    }
20603
20604    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20605        self.show_gutter = show_gutter;
20606        cx.notify();
20607    }
20608
20609    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20610        self.show_scrollbars = ScrollbarAxes {
20611            horizontal: show,
20612            vertical: show,
20613        };
20614        cx.notify();
20615    }
20616
20617    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20618        self.show_scrollbars.vertical = show;
20619        cx.notify();
20620    }
20621
20622    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20623        self.show_scrollbars.horizontal = show;
20624        cx.notify();
20625    }
20626
20627    pub fn set_minimap_visibility(
20628        &mut self,
20629        minimap_visibility: MinimapVisibility,
20630        window: &mut Window,
20631        cx: &mut Context<Self>,
20632    ) {
20633        if self.minimap_visibility != minimap_visibility {
20634            if minimap_visibility.visible() && self.minimap.is_none() {
20635                let minimap_settings = EditorSettings::get_global(cx).minimap;
20636                self.minimap =
20637                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20638            }
20639            self.minimap_visibility = minimap_visibility;
20640            cx.notify();
20641        }
20642    }
20643
20644    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20645        self.set_show_scrollbars(false, cx);
20646        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20647    }
20648
20649    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20650        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20651    }
20652
20653    /// Normally the text in full mode and auto height editors is padded on the
20654    /// left side by roughly half a character width for improved hit testing.
20655    ///
20656    /// Use this method to disable this for cases where this is not wanted (e.g.
20657    /// if you want to align the editor text with some other text above or below)
20658    /// or if you want to add this padding to single-line editors.
20659    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20660        self.offset_content = offset_content;
20661        cx.notify();
20662    }
20663
20664    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20665        self.show_line_numbers = Some(show_line_numbers);
20666        cx.notify();
20667    }
20668
20669    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20670        self.disable_expand_excerpt_buttons = true;
20671        cx.notify();
20672    }
20673
20674    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20675        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20676        cx.notify();
20677    }
20678
20679    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20680        self.show_code_actions = Some(show_code_actions);
20681        cx.notify();
20682    }
20683
20684    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20685        self.show_runnables = Some(show_runnables);
20686        cx.notify();
20687    }
20688
20689    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20690        self.show_breakpoints = Some(show_breakpoints);
20691        cx.notify();
20692    }
20693
20694    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20695        if self.display_map.read(cx).masked != masked {
20696            self.display_map.update(cx, |map, _| map.masked = masked);
20697        }
20698        cx.notify()
20699    }
20700
20701    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20702        self.show_wrap_guides = Some(show_wrap_guides);
20703        cx.notify();
20704    }
20705
20706    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20707        self.show_indent_guides = Some(show_indent_guides);
20708        cx.notify();
20709    }
20710
20711    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20712        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20713            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20714                && let Some(dir) = file.abs_path(cx).parent()
20715            {
20716                return Some(dir.to_owned());
20717            }
20718        }
20719
20720        None
20721    }
20722
20723    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20724        self.active_excerpt(cx)?
20725            .1
20726            .read(cx)
20727            .file()
20728            .and_then(|f| f.as_local())
20729    }
20730
20731    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20732        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20733            let buffer = buffer.read(cx);
20734            if let Some(project_path) = buffer.project_path(cx) {
20735                let project = self.project()?.read(cx);
20736                project.absolute_path(&project_path, cx)
20737            } else {
20738                buffer
20739                    .file()
20740                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20741            }
20742        })
20743    }
20744
20745    pub fn reveal_in_finder(
20746        &mut self,
20747        _: &RevealInFileManager,
20748        _window: &mut Window,
20749        cx: &mut Context<Self>,
20750    ) {
20751        if let Some(target) = self.target_file(cx) {
20752            cx.reveal_path(&target.abs_path(cx));
20753        }
20754    }
20755
20756    pub fn copy_path(
20757        &mut self,
20758        _: &zed_actions::workspace::CopyPath,
20759        _window: &mut Window,
20760        cx: &mut Context<Self>,
20761    ) {
20762        if let Some(path) = self.target_file_abs_path(cx)
20763            && let Some(path) = path.to_str()
20764        {
20765            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20766        } else {
20767            cx.propagate();
20768        }
20769    }
20770
20771    pub fn copy_relative_path(
20772        &mut self,
20773        _: &zed_actions::workspace::CopyRelativePath,
20774        _window: &mut Window,
20775        cx: &mut Context<Self>,
20776    ) {
20777        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20778            let project = self.project()?.read(cx);
20779            let path = buffer.read(cx).file()?.path();
20780            let path = path.display(project.path_style(cx));
20781            Some(path)
20782        }) {
20783            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20784        } else {
20785            cx.propagate();
20786        }
20787    }
20788
20789    /// Returns the project path for the editor's buffer, if any buffer is
20790    /// opened in the editor.
20791    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20792        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20793            buffer.read(cx).project_path(cx)
20794        } else {
20795            None
20796        }
20797    }
20798
20799    // Returns true if the editor handled a go-to-line request
20800    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20801        maybe!({
20802            let breakpoint_store = self.breakpoint_store.as_ref()?;
20803
20804            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20805            else {
20806                self.clear_row_highlights::<ActiveDebugLine>();
20807                return None;
20808            };
20809
20810            let position = active_stack_frame.position;
20811            let buffer_id = position.buffer_id?;
20812            let snapshot = self
20813                .project
20814                .as_ref()?
20815                .read(cx)
20816                .buffer_for_id(buffer_id, cx)?
20817                .read(cx)
20818                .snapshot();
20819
20820            let mut handled = false;
20821            for (id, ExcerptRange { context, .. }) in
20822                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20823            {
20824                if context.start.cmp(&position, &snapshot).is_ge()
20825                    || context.end.cmp(&position, &snapshot).is_lt()
20826                {
20827                    continue;
20828                }
20829                let snapshot = self.buffer.read(cx).snapshot(cx);
20830                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20831
20832                handled = true;
20833                self.clear_row_highlights::<ActiveDebugLine>();
20834
20835                self.go_to_line::<ActiveDebugLine>(
20836                    multibuffer_anchor,
20837                    Some(cx.theme().colors().editor_debugger_active_line_background),
20838                    window,
20839                    cx,
20840                );
20841
20842                cx.notify();
20843            }
20844
20845            handled.then_some(())
20846        })
20847        .is_some()
20848    }
20849
20850    pub fn copy_file_name_without_extension(
20851        &mut self,
20852        _: &CopyFileNameWithoutExtension,
20853        _: &mut Window,
20854        cx: &mut Context<Self>,
20855    ) {
20856        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20857            let file = buffer.read(cx).file()?;
20858            file.path().file_stem()
20859        }) {
20860            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20861        }
20862    }
20863
20864    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20865        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20866            let file = buffer.read(cx).file()?;
20867            Some(file.file_name(cx))
20868        }) {
20869            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20870        }
20871    }
20872
20873    pub fn toggle_git_blame(
20874        &mut self,
20875        _: &::git::Blame,
20876        window: &mut Window,
20877        cx: &mut Context<Self>,
20878    ) {
20879        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20880
20881        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20882            self.start_git_blame(true, window, cx);
20883        }
20884
20885        cx.notify();
20886    }
20887
20888    pub fn toggle_git_blame_inline(
20889        &mut self,
20890        _: &ToggleGitBlameInline,
20891        window: &mut Window,
20892        cx: &mut Context<Self>,
20893    ) {
20894        self.toggle_git_blame_inline_internal(true, window, cx);
20895        cx.notify();
20896    }
20897
20898    pub fn open_git_blame_commit(
20899        &mut self,
20900        _: &OpenGitBlameCommit,
20901        window: &mut Window,
20902        cx: &mut Context<Self>,
20903    ) {
20904        self.open_git_blame_commit_internal(window, cx);
20905    }
20906
20907    fn open_git_blame_commit_internal(
20908        &mut self,
20909        window: &mut Window,
20910        cx: &mut Context<Self>,
20911    ) -> Option<()> {
20912        let blame = self.blame.as_ref()?;
20913        let snapshot = self.snapshot(window, cx);
20914        let cursor = self
20915            .selections
20916            .newest::<Point>(&snapshot.display_snapshot)
20917            .head();
20918        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20919        let (_, blame_entry) = blame
20920            .update(cx, |blame, cx| {
20921                blame
20922                    .blame_for_rows(
20923                        &[RowInfo {
20924                            buffer_id: Some(buffer.remote_id()),
20925                            buffer_row: Some(point.row),
20926                            ..Default::default()
20927                        }],
20928                        cx,
20929                    )
20930                    .next()
20931            })
20932            .flatten()?;
20933        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20934        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20935        let workspace = self.workspace()?.downgrade();
20936        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20937        None
20938    }
20939
20940    pub fn git_blame_inline_enabled(&self) -> bool {
20941        self.git_blame_inline_enabled
20942    }
20943
20944    pub fn toggle_selection_menu(
20945        &mut self,
20946        _: &ToggleSelectionMenu,
20947        _: &mut Window,
20948        cx: &mut Context<Self>,
20949    ) {
20950        self.show_selection_menu = self
20951            .show_selection_menu
20952            .map(|show_selections_menu| !show_selections_menu)
20953            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20954
20955        cx.notify();
20956    }
20957
20958    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20959        self.show_selection_menu
20960            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20961    }
20962
20963    fn start_git_blame(
20964        &mut self,
20965        user_triggered: bool,
20966        window: &mut Window,
20967        cx: &mut Context<Self>,
20968    ) {
20969        if let Some(project) = self.project() {
20970            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20971                && buffer.read(cx).file().is_none()
20972            {
20973                return;
20974            }
20975
20976            let focused = self.focus_handle(cx).contains_focused(window, cx);
20977
20978            let project = project.clone();
20979            let blame = cx
20980                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20981            self.blame_subscription =
20982                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20983            self.blame = Some(blame);
20984        }
20985    }
20986
20987    fn toggle_git_blame_inline_internal(
20988        &mut self,
20989        user_triggered: bool,
20990        window: &mut Window,
20991        cx: &mut Context<Self>,
20992    ) {
20993        if self.git_blame_inline_enabled {
20994            self.git_blame_inline_enabled = false;
20995            self.show_git_blame_inline = false;
20996            self.show_git_blame_inline_delay_task.take();
20997        } else {
20998            self.git_blame_inline_enabled = true;
20999            self.start_git_blame_inline(user_triggered, window, cx);
21000        }
21001
21002        cx.notify();
21003    }
21004
21005    fn start_git_blame_inline(
21006        &mut self,
21007        user_triggered: bool,
21008        window: &mut Window,
21009        cx: &mut Context<Self>,
21010    ) {
21011        self.start_git_blame(user_triggered, window, cx);
21012
21013        if ProjectSettings::get_global(cx)
21014            .git
21015            .inline_blame_delay()
21016            .is_some()
21017        {
21018            self.start_inline_blame_timer(window, cx);
21019        } else {
21020            self.show_git_blame_inline = true
21021        }
21022    }
21023
21024    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21025        self.blame.as_ref()
21026    }
21027
21028    pub fn show_git_blame_gutter(&self) -> bool {
21029        self.show_git_blame_gutter
21030    }
21031
21032    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21033        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21034    }
21035
21036    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21037        self.show_git_blame_inline
21038            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21039            && !self.newest_selection_head_on_empty_line(cx)
21040            && self.has_blame_entries(cx)
21041    }
21042
21043    fn has_blame_entries(&self, cx: &App) -> bool {
21044        self.blame()
21045            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21046    }
21047
21048    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21049        let cursor_anchor = self.selections.newest_anchor().head();
21050
21051        let snapshot = self.buffer.read(cx).snapshot(cx);
21052        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21053
21054        snapshot.line_len(buffer_row) == 0
21055    }
21056
21057    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21058        let buffer_and_selection = maybe!({
21059            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21060            let selection_range = selection.range();
21061
21062            let multi_buffer = self.buffer().read(cx);
21063            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21064            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21065
21066            let (buffer, range, _) = if selection.reversed {
21067                buffer_ranges.first()
21068            } else {
21069                buffer_ranges.last()
21070            }?;
21071
21072            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21073            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21074
21075            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21076                let selection = start_row_in_buffer..end_row_in_buffer;
21077
21078                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21079            };
21080
21081            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21082
21083            Some((
21084                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21085                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
21086                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
21087            ))
21088        });
21089
21090        let Some((buffer, selection)) = buffer_and_selection else {
21091            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21092        };
21093
21094        let Some(project) = self.project() else {
21095            return Task::ready(Err(anyhow!("editor does not have project")));
21096        };
21097
21098        project.update(cx, |project, cx| {
21099            project.get_permalink_to_line(&buffer, selection, cx)
21100        })
21101    }
21102
21103    pub fn copy_permalink_to_line(
21104        &mut self,
21105        _: &CopyPermalinkToLine,
21106        window: &mut Window,
21107        cx: &mut Context<Self>,
21108    ) {
21109        let permalink_task = self.get_permalink_to_line(cx);
21110        let workspace = self.workspace();
21111
21112        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21113            Ok(permalink) => {
21114                cx.update(|_, cx| {
21115                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21116                })
21117                .ok();
21118            }
21119            Err(err) => {
21120                let message = format!("Failed to copy permalink: {err}");
21121
21122                anyhow::Result::<()>::Err(err).log_err();
21123
21124                if let Some(workspace) = workspace {
21125                    workspace
21126                        .update_in(cx, |workspace, _, cx| {
21127                            struct CopyPermalinkToLine;
21128
21129                            workspace.show_toast(
21130                                Toast::new(
21131                                    NotificationId::unique::<CopyPermalinkToLine>(),
21132                                    message,
21133                                ),
21134                                cx,
21135                            )
21136                        })
21137                        .ok();
21138                }
21139            }
21140        })
21141        .detach();
21142    }
21143
21144    pub fn copy_file_location(
21145        &mut self,
21146        _: &CopyFileLocation,
21147        _: &mut Window,
21148        cx: &mut Context<Self>,
21149    ) {
21150        let selection = self
21151            .selections
21152            .newest::<Point>(&self.display_snapshot(cx))
21153            .start
21154            .row
21155            + 1;
21156        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21157            let project = self.project()?.read(cx);
21158            let file = buffer.read(cx).file()?;
21159            let path = file.path().display(project.path_style(cx));
21160
21161            Some(format!("{path}:{selection}"))
21162        }) {
21163            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21164        }
21165    }
21166
21167    pub fn open_permalink_to_line(
21168        &mut self,
21169        _: &OpenPermalinkToLine,
21170        window: &mut Window,
21171        cx: &mut Context<Self>,
21172    ) {
21173        let permalink_task = self.get_permalink_to_line(cx);
21174        let workspace = self.workspace();
21175
21176        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21177            Ok(permalink) => {
21178                cx.update(|_, cx| {
21179                    cx.open_url(permalink.as_ref());
21180                })
21181                .ok();
21182            }
21183            Err(err) => {
21184                let message = format!("Failed to open permalink: {err}");
21185
21186                anyhow::Result::<()>::Err(err).log_err();
21187
21188                if let Some(workspace) = workspace {
21189                    workspace
21190                        .update(cx, |workspace, cx| {
21191                            struct OpenPermalinkToLine;
21192
21193                            workspace.show_toast(
21194                                Toast::new(
21195                                    NotificationId::unique::<OpenPermalinkToLine>(),
21196                                    message,
21197                                ),
21198                                cx,
21199                            )
21200                        })
21201                        .ok();
21202                }
21203            }
21204        })
21205        .detach();
21206    }
21207
21208    pub fn insert_uuid_v4(
21209        &mut self,
21210        _: &InsertUuidV4,
21211        window: &mut Window,
21212        cx: &mut Context<Self>,
21213    ) {
21214        self.insert_uuid(UuidVersion::V4, window, cx);
21215    }
21216
21217    pub fn insert_uuid_v7(
21218        &mut self,
21219        _: &InsertUuidV7,
21220        window: &mut Window,
21221        cx: &mut Context<Self>,
21222    ) {
21223        self.insert_uuid(UuidVersion::V7, window, cx);
21224    }
21225
21226    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21228        self.transact(window, cx, |this, window, cx| {
21229            let edits = this
21230                .selections
21231                .all::<Point>(&this.display_snapshot(cx))
21232                .into_iter()
21233                .map(|selection| {
21234                    let uuid = match version {
21235                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21236                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21237                    };
21238
21239                    (selection.range(), uuid.to_string())
21240                });
21241            this.edit(edits, cx);
21242            this.refresh_edit_prediction(true, false, window, cx);
21243        });
21244    }
21245
21246    pub fn open_selections_in_multibuffer(
21247        &mut self,
21248        _: &OpenSelectionsInMultibuffer,
21249        window: &mut Window,
21250        cx: &mut Context<Self>,
21251    ) {
21252        let multibuffer = self.buffer.read(cx);
21253
21254        let Some(buffer) = multibuffer.as_singleton() else {
21255            return;
21256        };
21257
21258        let Some(workspace) = self.workspace() else {
21259            return;
21260        };
21261
21262        let title = multibuffer.title(cx).to_string();
21263
21264        let locations = self
21265            .selections
21266            .all_anchors(&self.display_snapshot(cx))
21267            .iter()
21268            .map(|selection| {
21269                (
21270                    buffer.clone(),
21271                    (selection.start.text_anchor..selection.end.text_anchor)
21272                        .to_point(buffer.read(cx)),
21273                )
21274            })
21275            .into_group_map();
21276
21277        cx.spawn_in(window, async move |_, cx| {
21278            workspace.update_in(cx, |workspace, window, cx| {
21279                Self::open_locations_in_multibuffer(
21280                    workspace,
21281                    locations,
21282                    format!("Selections for '{title}'"),
21283                    false,
21284                    false,
21285                    MultibufferSelectionMode::All,
21286                    window,
21287                    cx,
21288                );
21289            })
21290        })
21291        .detach();
21292    }
21293
21294    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21295    /// last highlight added will be used.
21296    ///
21297    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21298    pub fn highlight_rows<T: 'static>(
21299        &mut self,
21300        range: Range<Anchor>,
21301        color: Hsla,
21302        options: RowHighlightOptions,
21303        cx: &mut Context<Self>,
21304    ) {
21305        let snapshot = self.buffer().read(cx).snapshot(cx);
21306        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21307        let ix = row_highlights.binary_search_by(|highlight| {
21308            Ordering::Equal
21309                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21310                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21311        });
21312
21313        if let Err(mut ix) = ix {
21314            let index = post_inc(&mut self.highlight_order);
21315
21316            // If this range intersects with the preceding highlight, then merge it with
21317            // the preceding highlight. Otherwise insert a new highlight.
21318            let mut merged = false;
21319            if ix > 0 {
21320                let prev_highlight = &mut row_highlights[ix - 1];
21321                if prev_highlight
21322                    .range
21323                    .end
21324                    .cmp(&range.start, &snapshot)
21325                    .is_ge()
21326                {
21327                    ix -= 1;
21328                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21329                        prev_highlight.range.end = range.end;
21330                    }
21331                    merged = true;
21332                    prev_highlight.index = index;
21333                    prev_highlight.color = color;
21334                    prev_highlight.options = options;
21335                }
21336            }
21337
21338            if !merged {
21339                row_highlights.insert(
21340                    ix,
21341                    RowHighlight {
21342                        range,
21343                        index,
21344                        color,
21345                        options,
21346                        type_id: TypeId::of::<T>(),
21347                    },
21348                );
21349            }
21350
21351            // If any of the following highlights intersect with this one, merge them.
21352            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21353                let highlight = &row_highlights[ix];
21354                if next_highlight
21355                    .range
21356                    .start
21357                    .cmp(&highlight.range.end, &snapshot)
21358                    .is_le()
21359                {
21360                    if next_highlight
21361                        .range
21362                        .end
21363                        .cmp(&highlight.range.end, &snapshot)
21364                        .is_gt()
21365                    {
21366                        row_highlights[ix].range.end = next_highlight.range.end;
21367                    }
21368                    row_highlights.remove(ix + 1);
21369                } else {
21370                    break;
21371                }
21372            }
21373        }
21374    }
21375
21376    /// Remove any highlighted row ranges of the given type that intersect the
21377    /// given ranges.
21378    pub fn remove_highlighted_rows<T: 'static>(
21379        &mut self,
21380        ranges_to_remove: Vec<Range<Anchor>>,
21381        cx: &mut Context<Self>,
21382    ) {
21383        let snapshot = self.buffer().read(cx).snapshot(cx);
21384        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21385        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21386        row_highlights.retain(|highlight| {
21387            while let Some(range_to_remove) = ranges_to_remove.peek() {
21388                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21389                    Ordering::Less | Ordering::Equal => {
21390                        ranges_to_remove.next();
21391                    }
21392                    Ordering::Greater => {
21393                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21394                            Ordering::Less | Ordering::Equal => {
21395                                return false;
21396                            }
21397                            Ordering::Greater => break,
21398                        }
21399                    }
21400                }
21401            }
21402
21403            true
21404        })
21405    }
21406
21407    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21408    pub fn clear_row_highlights<T: 'static>(&mut self) {
21409        self.highlighted_rows.remove(&TypeId::of::<T>());
21410    }
21411
21412    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21413    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21414        self.highlighted_rows
21415            .get(&TypeId::of::<T>())
21416            .map_or(&[] as &[_], |vec| vec.as_slice())
21417            .iter()
21418            .map(|highlight| (highlight.range.clone(), highlight.color))
21419    }
21420
21421    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21422    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21423    /// Allows to ignore certain kinds of highlights.
21424    pub fn highlighted_display_rows(
21425        &self,
21426        window: &mut Window,
21427        cx: &mut App,
21428    ) -> BTreeMap<DisplayRow, LineHighlight> {
21429        let snapshot = self.snapshot(window, cx);
21430        let mut used_highlight_orders = HashMap::default();
21431        self.highlighted_rows
21432            .iter()
21433            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21434            .fold(
21435                BTreeMap::<DisplayRow, LineHighlight>::new(),
21436                |mut unique_rows, highlight| {
21437                    let start = highlight.range.start.to_display_point(&snapshot);
21438                    let end = highlight.range.end.to_display_point(&snapshot);
21439                    let start_row = start.row().0;
21440                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21441                    {
21442                        end.row().0.saturating_sub(1)
21443                    } else {
21444                        end.row().0
21445                    };
21446                    for row in start_row..=end_row {
21447                        let used_index =
21448                            used_highlight_orders.entry(row).or_insert(highlight.index);
21449                        if highlight.index >= *used_index {
21450                            *used_index = highlight.index;
21451                            unique_rows.insert(
21452                                DisplayRow(row),
21453                                LineHighlight {
21454                                    include_gutter: highlight.options.include_gutter,
21455                                    border: None,
21456                                    background: highlight.color.into(),
21457                                    type_id: Some(highlight.type_id),
21458                                },
21459                            );
21460                        }
21461                    }
21462                    unique_rows
21463                },
21464            )
21465    }
21466
21467    pub fn highlighted_display_row_for_autoscroll(
21468        &self,
21469        snapshot: &DisplaySnapshot,
21470    ) -> Option<DisplayRow> {
21471        self.highlighted_rows
21472            .values()
21473            .flat_map(|highlighted_rows| highlighted_rows.iter())
21474            .filter_map(|highlight| {
21475                if highlight.options.autoscroll {
21476                    Some(highlight.range.start.to_display_point(snapshot).row())
21477                } else {
21478                    None
21479                }
21480            })
21481            .min()
21482    }
21483
21484    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21485        self.highlight_background::<SearchWithinRange>(
21486            ranges,
21487            |_, colors| colors.colors().editor_document_highlight_read_background,
21488            cx,
21489        )
21490    }
21491
21492    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21493        self.breadcrumb_header = Some(new_header);
21494    }
21495
21496    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21497        self.clear_background_highlights::<SearchWithinRange>(cx);
21498    }
21499
21500    pub fn highlight_background<T: 'static>(
21501        &mut self,
21502        ranges: &[Range<Anchor>],
21503        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21504        cx: &mut Context<Self>,
21505    ) {
21506        self.background_highlights.insert(
21507            HighlightKey::Type(TypeId::of::<T>()),
21508            (Arc::new(color_fetcher), Arc::from(ranges)),
21509        );
21510        self.scrollbar_marker_state.dirty = true;
21511        cx.notify();
21512    }
21513
21514    pub fn highlight_background_key<T: 'static>(
21515        &mut self,
21516        key: usize,
21517        ranges: &[Range<Anchor>],
21518        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21519        cx: &mut Context<Self>,
21520    ) {
21521        self.background_highlights.insert(
21522            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21523            (Arc::new(color_fetcher), Arc::from(ranges)),
21524        );
21525        self.scrollbar_marker_state.dirty = true;
21526        cx.notify();
21527    }
21528
21529    pub fn clear_background_highlights<T: 'static>(
21530        &mut self,
21531        cx: &mut Context<Self>,
21532    ) -> Option<BackgroundHighlight> {
21533        let text_highlights = self
21534            .background_highlights
21535            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21536        if !text_highlights.1.is_empty() {
21537            self.scrollbar_marker_state.dirty = true;
21538            cx.notify();
21539        }
21540        Some(text_highlights)
21541    }
21542
21543    pub fn highlight_gutter<T: 'static>(
21544        &mut self,
21545        ranges: impl Into<Vec<Range<Anchor>>>,
21546        color_fetcher: fn(&App) -> Hsla,
21547        cx: &mut Context<Self>,
21548    ) {
21549        self.gutter_highlights
21550            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21551        cx.notify();
21552    }
21553
21554    pub fn clear_gutter_highlights<T: 'static>(
21555        &mut self,
21556        cx: &mut Context<Self>,
21557    ) -> Option<GutterHighlight> {
21558        cx.notify();
21559        self.gutter_highlights.remove(&TypeId::of::<T>())
21560    }
21561
21562    pub fn insert_gutter_highlight<T: 'static>(
21563        &mut self,
21564        range: Range<Anchor>,
21565        color_fetcher: fn(&App) -> Hsla,
21566        cx: &mut Context<Self>,
21567    ) {
21568        let snapshot = self.buffer().read(cx).snapshot(cx);
21569        let mut highlights = self
21570            .gutter_highlights
21571            .remove(&TypeId::of::<T>())
21572            .map(|(_, highlights)| highlights)
21573            .unwrap_or_default();
21574        let ix = highlights.binary_search_by(|highlight| {
21575            Ordering::Equal
21576                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21577                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21578        });
21579        if let Err(ix) = ix {
21580            highlights.insert(ix, range);
21581        }
21582        self.gutter_highlights
21583            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21584    }
21585
21586    pub fn remove_gutter_highlights<T: 'static>(
21587        &mut self,
21588        ranges_to_remove: Vec<Range<Anchor>>,
21589        cx: &mut Context<Self>,
21590    ) {
21591        let snapshot = self.buffer().read(cx).snapshot(cx);
21592        let Some((color_fetcher, mut gutter_highlights)) =
21593            self.gutter_highlights.remove(&TypeId::of::<T>())
21594        else {
21595            return;
21596        };
21597        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21598        gutter_highlights.retain(|highlight| {
21599            while let Some(range_to_remove) = ranges_to_remove.peek() {
21600                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21601                    Ordering::Less | Ordering::Equal => {
21602                        ranges_to_remove.next();
21603                    }
21604                    Ordering::Greater => {
21605                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21606                            Ordering::Less | Ordering::Equal => {
21607                                return false;
21608                            }
21609                            Ordering::Greater => break,
21610                        }
21611                    }
21612                }
21613            }
21614
21615            true
21616        });
21617        self.gutter_highlights
21618            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21619    }
21620
21621    #[cfg(feature = "test-support")]
21622    pub fn all_text_highlights(
21623        &self,
21624        window: &mut Window,
21625        cx: &mut Context<Self>,
21626    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21627        let snapshot = self.snapshot(window, cx);
21628        self.display_map.update(cx, |display_map, _| {
21629            display_map
21630                .all_text_highlights()
21631                .map(|highlight| {
21632                    let (style, ranges) = highlight.as_ref();
21633                    (
21634                        *style,
21635                        ranges
21636                            .iter()
21637                            .map(|range| range.clone().to_display_points(&snapshot))
21638                            .collect(),
21639                    )
21640                })
21641                .collect()
21642        })
21643    }
21644
21645    #[cfg(feature = "test-support")]
21646    pub fn all_text_background_highlights(
21647        &self,
21648        window: &mut Window,
21649        cx: &mut Context<Self>,
21650    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21651        let snapshot = self.snapshot(window, cx);
21652        let buffer = &snapshot.buffer_snapshot();
21653        let start = buffer.anchor_before(MultiBufferOffset(0));
21654        let end = buffer.anchor_after(buffer.len());
21655        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21656    }
21657
21658    #[cfg(any(test, feature = "test-support"))]
21659    pub fn sorted_background_highlights_in_range(
21660        &self,
21661        search_range: Range<Anchor>,
21662        display_snapshot: &DisplaySnapshot,
21663        theme: &Theme,
21664    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21665        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21666        res.sort_by(|a, b| {
21667            a.0.start
21668                .cmp(&b.0.start)
21669                .then_with(|| a.0.end.cmp(&b.0.end))
21670                .then_with(|| a.1.cmp(&b.1))
21671        });
21672        res
21673    }
21674
21675    #[cfg(feature = "test-support")]
21676    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21677        let snapshot = self.buffer().read(cx).snapshot(cx);
21678
21679        let highlights = self
21680            .background_highlights
21681            .get(&HighlightKey::Type(TypeId::of::<
21682                items::BufferSearchHighlights,
21683            >()));
21684
21685        if let Some((_color, ranges)) = highlights {
21686            ranges
21687                .iter()
21688                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21689                .collect_vec()
21690        } else {
21691            vec![]
21692        }
21693    }
21694
21695    fn document_highlights_for_position<'a>(
21696        &'a self,
21697        position: Anchor,
21698        buffer: &'a MultiBufferSnapshot,
21699    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21700        let read_highlights = self
21701            .background_highlights
21702            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21703            .map(|h| &h.1);
21704        let write_highlights = self
21705            .background_highlights
21706            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21707            .map(|h| &h.1);
21708        let left_position = position.bias_left(buffer);
21709        let right_position = position.bias_right(buffer);
21710        read_highlights
21711            .into_iter()
21712            .chain(write_highlights)
21713            .flat_map(move |ranges| {
21714                let start_ix = match ranges.binary_search_by(|probe| {
21715                    let cmp = probe.end.cmp(&left_position, buffer);
21716                    if cmp.is_ge() {
21717                        Ordering::Greater
21718                    } else {
21719                        Ordering::Less
21720                    }
21721                }) {
21722                    Ok(i) | Err(i) => i,
21723                };
21724
21725                ranges[start_ix..]
21726                    .iter()
21727                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21728            })
21729    }
21730
21731    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21732        self.background_highlights
21733            .get(&HighlightKey::Type(TypeId::of::<T>()))
21734            .is_some_and(|(_, highlights)| !highlights.is_empty())
21735    }
21736
21737    /// Returns all background highlights for a given range.
21738    ///
21739    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21740    pub fn background_highlights_in_range(
21741        &self,
21742        search_range: Range<Anchor>,
21743        display_snapshot: &DisplaySnapshot,
21744        theme: &Theme,
21745    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21746        let mut results = Vec::new();
21747        for (color_fetcher, ranges) in self.background_highlights.values() {
21748            let start_ix = match ranges.binary_search_by(|probe| {
21749                let cmp = probe
21750                    .end
21751                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21752                if cmp.is_gt() {
21753                    Ordering::Greater
21754                } else {
21755                    Ordering::Less
21756                }
21757            }) {
21758                Ok(i) | Err(i) => i,
21759            };
21760            for (index, range) in ranges[start_ix..].iter().enumerate() {
21761                if range
21762                    .start
21763                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21764                    .is_ge()
21765                {
21766                    break;
21767                }
21768
21769                let color = color_fetcher(&(start_ix + index), theme);
21770                let start = range.start.to_display_point(display_snapshot);
21771                let end = range.end.to_display_point(display_snapshot);
21772                results.push((start..end, color))
21773            }
21774        }
21775        results
21776    }
21777
21778    pub fn gutter_highlights_in_range(
21779        &self,
21780        search_range: Range<Anchor>,
21781        display_snapshot: &DisplaySnapshot,
21782        cx: &App,
21783    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21784        let mut results = Vec::new();
21785        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21786            let color = color_fetcher(cx);
21787            let start_ix = match ranges.binary_search_by(|probe| {
21788                let cmp = probe
21789                    .end
21790                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21791                if cmp.is_gt() {
21792                    Ordering::Greater
21793                } else {
21794                    Ordering::Less
21795                }
21796            }) {
21797                Ok(i) | Err(i) => i,
21798            };
21799            for range in &ranges[start_ix..] {
21800                if range
21801                    .start
21802                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21803                    .is_ge()
21804                {
21805                    break;
21806                }
21807
21808                let start = range.start.to_display_point(display_snapshot);
21809                let end = range.end.to_display_point(display_snapshot);
21810                results.push((start..end, color))
21811            }
21812        }
21813        results
21814    }
21815
21816    /// Get the text ranges corresponding to the redaction query
21817    pub fn redacted_ranges(
21818        &self,
21819        search_range: Range<Anchor>,
21820        display_snapshot: &DisplaySnapshot,
21821        cx: &App,
21822    ) -> Vec<Range<DisplayPoint>> {
21823        display_snapshot
21824            .buffer_snapshot()
21825            .redacted_ranges(search_range, |file| {
21826                if let Some(file) = file {
21827                    file.is_private()
21828                        && EditorSettings::get(
21829                            Some(SettingsLocation {
21830                                worktree_id: file.worktree_id(cx),
21831                                path: file.path().as_ref(),
21832                            }),
21833                            cx,
21834                        )
21835                        .redact_private_values
21836                } else {
21837                    false
21838                }
21839            })
21840            .map(|range| {
21841                range.start.to_display_point(display_snapshot)
21842                    ..range.end.to_display_point(display_snapshot)
21843            })
21844            .collect()
21845    }
21846
21847    pub fn highlight_text_key<T: 'static>(
21848        &mut self,
21849        key: usize,
21850        ranges: Vec<Range<Anchor>>,
21851        style: HighlightStyle,
21852        merge: bool,
21853        cx: &mut Context<Self>,
21854    ) {
21855        self.display_map.update(cx, |map, cx| {
21856            map.highlight_text(
21857                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21858                ranges,
21859                style,
21860                merge,
21861                cx,
21862            );
21863        });
21864        cx.notify();
21865    }
21866
21867    pub fn highlight_text<T: 'static>(
21868        &mut self,
21869        ranges: Vec<Range<Anchor>>,
21870        style: HighlightStyle,
21871        cx: &mut Context<Self>,
21872    ) {
21873        self.display_map.update(cx, |map, cx| {
21874            map.highlight_text(
21875                HighlightKey::Type(TypeId::of::<T>()),
21876                ranges,
21877                style,
21878                false,
21879                cx,
21880            )
21881        });
21882        cx.notify();
21883    }
21884
21885    pub fn text_highlights<'a, T: 'static>(
21886        &'a self,
21887        cx: &'a App,
21888    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21889        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21890    }
21891
21892    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21893        let cleared = self
21894            .display_map
21895            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21896        if cleared {
21897            cx.notify();
21898        }
21899    }
21900
21901    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21902        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21903            && self.focus_handle.is_focused(window)
21904    }
21905
21906    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21907        self.show_cursor_when_unfocused = is_enabled;
21908        cx.notify();
21909    }
21910
21911    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21912        cx.notify();
21913    }
21914
21915    fn on_debug_session_event(
21916        &mut self,
21917        _session: Entity<Session>,
21918        event: &SessionEvent,
21919        cx: &mut Context<Self>,
21920    ) {
21921        if let SessionEvent::InvalidateInlineValue = event {
21922            self.refresh_inline_values(cx);
21923        }
21924    }
21925
21926    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21927        let Some(project) = self.project.clone() else {
21928            return;
21929        };
21930
21931        if !self.inline_value_cache.enabled {
21932            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21933            self.splice_inlays(&inlays, Vec::new(), cx);
21934            return;
21935        }
21936
21937        let current_execution_position = self
21938            .highlighted_rows
21939            .get(&TypeId::of::<ActiveDebugLine>())
21940            .and_then(|lines| lines.last().map(|line| line.range.end));
21941
21942        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21943            let inline_values = editor
21944                .update(cx, |editor, cx| {
21945                    let Some(current_execution_position) = current_execution_position else {
21946                        return Some(Task::ready(Ok(Vec::new())));
21947                    };
21948
21949                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21950                        let snapshot = buffer.snapshot(cx);
21951
21952                        let excerpt = snapshot.excerpt_containing(
21953                            current_execution_position..current_execution_position,
21954                        )?;
21955
21956                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21957                    })?;
21958
21959                    let range =
21960                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21961
21962                    project.inline_values(buffer, range, cx)
21963                })
21964                .ok()
21965                .flatten()?
21966                .await
21967                .context("refreshing debugger inlays")
21968                .log_err()?;
21969
21970            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21971
21972            for (buffer_id, inline_value) in inline_values
21973                .into_iter()
21974                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21975            {
21976                buffer_inline_values
21977                    .entry(buffer_id)
21978                    .or_default()
21979                    .push(inline_value);
21980            }
21981
21982            editor
21983                .update(cx, |editor, cx| {
21984                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21985                    let mut new_inlays = Vec::default();
21986
21987                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21988                        let buffer_id = buffer_snapshot.remote_id();
21989                        buffer_inline_values
21990                            .get(&buffer_id)
21991                            .into_iter()
21992                            .flatten()
21993                            .for_each(|hint| {
21994                                let inlay = Inlay::debugger(
21995                                    post_inc(&mut editor.next_inlay_id),
21996                                    Anchor::in_buffer(excerpt_id, hint.position),
21997                                    hint.text(),
21998                                );
21999                                if !inlay.text().chars().contains(&'\n') {
22000                                    new_inlays.push(inlay);
22001                                }
22002                            });
22003                    }
22004
22005                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22006                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22007
22008                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22009                })
22010                .ok()?;
22011            Some(())
22012        });
22013    }
22014
22015    fn on_buffer_event(
22016        &mut self,
22017        multibuffer: &Entity<MultiBuffer>,
22018        event: &multi_buffer::Event,
22019        window: &mut Window,
22020        cx: &mut Context<Self>,
22021    ) {
22022        match event {
22023            multi_buffer::Event::Edited { edited_buffer } => {
22024                self.scrollbar_marker_state.dirty = true;
22025                self.active_indent_guides_state.dirty = true;
22026                self.refresh_active_diagnostics(cx);
22027                self.refresh_code_actions(window, cx);
22028                self.refresh_single_line_folds(window, cx);
22029                self.refresh_matching_bracket_highlights(window, cx);
22030                if self.has_active_edit_prediction() {
22031                    self.update_visible_edit_prediction(window, cx);
22032                }
22033
22034                if let Some(buffer) = edited_buffer {
22035                    if buffer.read(cx).file().is_none() {
22036                        cx.emit(EditorEvent::TitleChanged);
22037                    }
22038
22039                    if self.project.is_some() {
22040                        let buffer_id = buffer.read(cx).remote_id();
22041                        self.register_buffer(buffer_id, cx);
22042                        self.update_lsp_data(Some(buffer_id), window, cx);
22043                        self.refresh_inlay_hints(
22044                            InlayHintRefreshReason::BufferEdited(buffer_id),
22045                            cx,
22046                        );
22047                    }
22048                }
22049
22050                cx.emit(EditorEvent::BufferEdited);
22051                cx.emit(SearchEvent::MatchesInvalidated);
22052
22053                let Some(project) = &self.project else { return };
22054                let (telemetry, is_via_ssh) = {
22055                    let project = project.read(cx);
22056                    let telemetry = project.client().telemetry().clone();
22057                    let is_via_ssh = project.is_via_remote_server();
22058                    (telemetry, is_via_ssh)
22059                };
22060                telemetry.log_edit_event("editor", is_via_ssh);
22061            }
22062            multi_buffer::Event::ExcerptsAdded {
22063                buffer,
22064                predecessor,
22065                excerpts,
22066            } => {
22067                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22068                let buffer_id = buffer.read(cx).remote_id();
22069                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22070                    && let Some(project) = &self.project
22071                {
22072                    update_uncommitted_diff_for_buffer(
22073                        cx.entity(),
22074                        project,
22075                        [buffer.clone()],
22076                        self.buffer.clone(),
22077                        cx,
22078                    )
22079                    .detach();
22080                }
22081                self.update_lsp_data(Some(buffer_id), window, cx);
22082                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22083                self.colorize_brackets(false, cx);
22084                cx.emit(EditorEvent::ExcerptsAdded {
22085                    buffer: buffer.clone(),
22086                    predecessor: *predecessor,
22087                    excerpts: excerpts.clone(),
22088                });
22089            }
22090            multi_buffer::Event::ExcerptsRemoved {
22091                ids,
22092                removed_buffer_ids,
22093            } => {
22094                if let Some(inlay_hints) = &mut self.inlay_hints {
22095                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22096                }
22097                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22098                for buffer_id in removed_buffer_ids {
22099                    self.registered_buffers.remove(buffer_id);
22100                }
22101                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22102                cx.emit(EditorEvent::ExcerptsRemoved {
22103                    ids: ids.clone(),
22104                    removed_buffer_ids: removed_buffer_ids.clone(),
22105                });
22106            }
22107            multi_buffer::Event::ExcerptsEdited {
22108                excerpt_ids,
22109                buffer_ids,
22110            } => {
22111                self.display_map.update(cx, |map, cx| {
22112                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22113                });
22114                cx.emit(EditorEvent::ExcerptsEdited {
22115                    ids: excerpt_ids.clone(),
22116                });
22117            }
22118            multi_buffer::Event::ExcerptsExpanded { ids } => {
22119                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22120                self.refresh_document_highlights(cx);
22121                for id in ids {
22122                    self.fetched_tree_sitter_chunks.remove(id);
22123                }
22124                self.colorize_brackets(false, cx);
22125                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22126            }
22127            multi_buffer::Event::Reparsed(buffer_id) => {
22128                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22129                self.refresh_selected_text_highlights(true, window, cx);
22130                self.colorize_brackets(true, cx);
22131                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22132
22133                cx.emit(EditorEvent::Reparsed(*buffer_id));
22134            }
22135            multi_buffer::Event::DiffHunksToggled => {
22136                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22137            }
22138            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22139                if !is_fresh_language {
22140                    self.registered_buffers.remove(&buffer_id);
22141                }
22142                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22143                cx.emit(EditorEvent::Reparsed(*buffer_id));
22144                cx.notify();
22145            }
22146            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22147            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22148            multi_buffer::Event::FileHandleChanged
22149            | multi_buffer::Event::Reloaded
22150            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22151            multi_buffer::Event::DiagnosticsUpdated => {
22152                self.update_diagnostics_state(window, cx);
22153            }
22154            _ => {}
22155        };
22156    }
22157
22158    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22159        if !self.diagnostics_enabled() {
22160            return;
22161        }
22162        self.refresh_active_diagnostics(cx);
22163        self.refresh_inline_diagnostics(true, window, cx);
22164        self.scrollbar_marker_state.dirty = true;
22165        cx.notify();
22166    }
22167
22168    pub fn start_temporary_diff_override(&mut self) {
22169        self.load_diff_task.take();
22170        self.temporary_diff_override = true;
22171    }
22172
22173    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22174        self.temporary_diff_override = false;
22175        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22176        self.buffer.update(cx, |buffer, cx| {
22177            buffer.set_all_diff_hunks_collapsed(cx);
22178        });
22179
22180        if let Some(project) = self.project.clone() {
22181            self.load_diff_task = Some(
22182                update_uncommitted_diff_for_buffer(
22183                    cx.entity(),
22184                    &project,
22185                    self.buffer.read(cx).all_buffers(),
22186                    self.buffer.clone(),
22187                    cx,
22188                )
22189                .shared(),
22190            );
22191        }
22192    }
22193
22194    fn on_display_map_changed(
22195        &mut self,
22196        _: Entity<DisplayMap>,
22197        _: &mut Window,
22198        cx: &mut Context<Self>,
22199    ) {
22200        cx.notify();
22201    }
22202
22203    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22204        if !self.mode.is_full() {
22205            return None;
22206        }
22207
22208        let theme_settings = theme::ThemeSettings::get_global(cx);
22209        let theme = cx.theme();
22210        let accent_colors = theme.accents().clone();
22211
22212        let accent_overrides = theme_settings
22213            .theme_overrides
22214            .get(theme.name.as_ref())
22215            .map(|theme_style| &theme_style.accents)
22216            .into_iter()
22217            .flatten()
22218            .chain(
22219                theme_settings
22220                    .experimental_theme_overrides
22221                    .as_ref()
22222                    .map(|overrides| &overrides.accents)
22223                    .into_iter()
22224                    .flatten(),
22225            )
22226            .flat_map(|accent| accent.0.clone())
22227            .collect();
22228
22229        Some(AccentData {
22230            colors: accent_colors,
22231            overrides: accent_overrides,
22232        })
22233    }
22234
22235    fn fetch_applicable_language_settings(
22236        &self,
22237        cx: &App,
22238    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22239        if !self.mode.is_full() {
22240            return HashMap::default();
22241        }
22242
22243        self.buffer().read(cx).all_buffers().into_iter().fold(
22244            HashMap::default(),
22245            |mut acc, buffer| {
22246                let buffer = buffer.read(cx);
22247                let language = buffer.language().map(|language| language.name());
22248                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22249                    let file = buffer.file();
22250                    v.insert(language_settings(language, file, cx).into_owned());
22251                }
22252                acc
22253            },
22254        )
22255    }
22256
22257    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22258        let new_language_settings = self.fetch_applicable_language_settings(cx);
22259        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22260        self.applicable_language_settings = new_language_settings;
22261
22262        let new_accents = self.fetch_accent_data(cx);
22263        let accents_changed = new_accents != self.accent_data;
22264        self.accent_data = new_accents;
22265
22266        if self.diagnostics_enabled() {
22267            let new_severity = EditorSettings::get_global(cx)
22268                .diagnostics_max_severity
22269                .unwrap_or(DiagnosticSeverity::Hint);
22270            self.set_max_diagnostics_severity(new_severity, cx);
22271        }
22272        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22273        self.update_edit_prediction_settings(cx);
22274        self.refresh_edit_prediction(true, false, window, cx);
22275        self.refresh_inline_values(cx);
22276        self.refresh_inlay_hints(
22277            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22278                self.selections.newest_anchor().head(),
22279                &self.buffer.read(cx).snapshot(cx),
22280                cx,
22281            )),
22282            cx,
22283        );
22284
22285        let old_cursor_shape = self.cursor_shape;
22286        let old_show_breadcrumbs = self.show_breadcrumbs;
22287
22288        {
22289            let editor_settings = EditorSettings::get_global(cx);
22290            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22291            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22292            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22293            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22294        }
22295
22296        if old_cursor_shape != self.cursor_shape {
22297            cx.emit(EditorEvent::CursorShapeChanged);
22298        }
22299
22300        if old_show_breadcrumbs != self.show_breadcrumbs {
22301            cx.emit(EditorEvent::BreadcrumbsChanged);
22302        }
22303
22304        let project_settings = ProjectSettings::get_global(cx);
22305        self.buffer_serialization = self
22306            .should_serialize_buffer()
22307            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22308
22309        if self.mode.is_full() {
22310            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22311            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22312            if self.show_inline_diagnostics != show_inline_diagnostics {
22313                self.show_inline_diagnostics = show_inline_diagnostics;
22314                self.refresh_inline_diagnostics(false, window, cx);
22315            }
22316
22317            if self.git_blame_inline_enabled != inline_blame_enabled {
22318                self.toggle_git_blame_inline_internal(false, window, cx);
22319            }
22320
22321            let minimap_settings = EditorSettings::get_global(cx).minimap;
22322            if self.minimap_visibility != MinimapVisibility::Disabled {
22323                if self.minimap_visibility.settings_visibility()
22324                    != minimap_settings.minimap_enabled()
22325                {
22326                    self.set_minimap_visibility(
22327                        MinimapVisibility::for_mode(self.mode(), cx),
22328                        window,
22329                        cx,
22330                    );
22331                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22332                    minimap_entity.update(cx, |minimap_editor, cx| {
22333                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22334                    })
22335                }
22336            }
22337
22338            if language_settings_changed || accents_changed {
22339                self.colorize_brackets(true, cx);
22340            }
22341
22342            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22343                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22344            }) {
22345                if !inlay_splice.is_empty() {
22346                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22347                }
22348                self.refresh_colors_for_visible_range(None, window, cx);
22349            }
22350        }
22351
22352        cx.notify();
22353    }
22354
22355    pub fn set_searchable(&mut self, searchable: bool) {
22356        self.searchable = searchable;
22357    }
22358
22359    pub fn searchable(&self) -> bool {
22360        self.searchable
22361    }
22362
22363    pub fn open_excerpts_in_split(
22364        &mut self,
22365        _: &OpenExcerptsSplit,
22366        window: &mut Window,
22367        cx: &mut Context<Self>,
22368    ) {
22369        self.open_excerpts_common(None, true, window, cx)
22370    }
22371
22372    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22373        self.open_excerpts_common(None, false, window, cx)
22374    }
22375
22376    fn open_excerpts_common(
22377        &mut self,
22378        jump_data: Option<JumpData>,
22379        split: bool,
22380        window: &mut Window,
22381        cx: &mut Context<Self>,
22382    ) {
22383        let Some(workspace) = self.workspace() else {
22384            cx.propagate();
22385            return;
22386        };
22387
22388        if self.buffer.read(cx).is_singleton() {
22389            cx.propagate();
22390            return;
22391        }
22392
22393        let mut new_selections_by_buffer = HashMap::default();
22394        match &jump_data {
22395            Some(JumpData::MultiBufferPoint {
22396                excerpt_id,
22397                position,
22398                anchor,
22399                line_offset_from_top,
22400            }) => {
22401                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22402                if let Some(buffer) = multi_buffer_snapshot
22403                    .buffer_id_for_excerpt(*excerpt_id)
22404                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22405                {
22406                    let buffer_snapshot = buffer.read(cx).snapshot();
22407                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22408                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22409                    } else {
22410                        buffer_snapshot.clip_point(*position, Bias::Left)
22411                    };
22412                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22413                    new_selections_by_buffer.insert(
22414                        buffer,
22415                        (
22416                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22417                            Some(*line_offset_from_top),
22418                        ),
22419                    );
22420                }
22421            }
22422            Some(JumpData::MultiBufferRow {
22423                row,
22424                line_offset_from_top,
22425            }) => {
22426                let point = MultiBufferPoint::new(row.0, 0);
22427                if let Some((buffer, buffer_point, _)) =
22428                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22429                {
22430                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22431                    new_selections_by_buffer
22432                        .entry(buffer)
22433                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22434                        .0
22435                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22436                }
22437            }
22438            None => {
22439                let selections = self
22440                    .selections
22441                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22442                let multi_buffer = self.buffer.read(cx);
22443                for selection in selections {
22444                    for (snapshot, range, _, anchor) in multi_buffer
22445                        .snapshot(cx)
22446                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22447                    {
22448                        if let Some(anchor) = anchor {
22449                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22450                            else {
22451                                continue;
22452                            };
22453                            let offset = text::ToOffset::to_offset(
22454                                &anchor.text_anchor,
22455                                &buffer_handle.read(cx).snapshot(),
22456                            );
22457                            let range = BufferOffset(offset)..BufferOffset(offset);
22458                            new_selections_by_buffer
22459                                .entry(buffer_handle)
22460                                .or_insert((Vec::new(), None))
22461                                .0
22462                                .push(range)
22463                        } else {
22464                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22465                            else {
22466                                continue;
22467                            };
22468                            new_selections_by_buffer
22469                                .entry(buffer_handle)
22470                                .or_insert((Vec::new(), None))
22471                                .0
22472                                .push(range)
22473                        }
22474                    }
22475                }
22476            }
22477        }
22478
22479        new_selections_by_buffer
22480            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22481
22482        if new_selections_by_buffer.is_empty() {
22483            return;
22484        }
22485
22486        // We defer the pane interaction because we ourselves are a workspace item
22487        // and activating a new item causes the pane to call a method on us reentrantly,
22488        // which panics if we're on the stack.
22489        window.defer(cx, move |window, cx| {
22490            workspace.update(cx, |workspace, cx| {
22491                let pane = if split {
22492                    workspace.adjacent_pane(window, cx)
22493                } else {
22494                    workspace.active_pane().clone()
22495                };
22496
22497                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22498                    let buffer_read = buffer.read(cx);
22499                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22500                        (true, project::File::from_dyn(Some(file)).is_some())
22501                    } else {
22502                        (false, false)
22503                    };
22504
22505                    // If project file is none workspace.open_project_item will fail to open the excerpt
22506                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22507                    // so we check if there's a tab match in that case first
22508                    let editor = (!has_file || !is_project_file)
22509                        .then(|| {
22510                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22511                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22512                            // Instead, we try to activate the existing editor in the pane first.
22513                            let (editor, pane_item_index, pane_item_id) =
22514                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22515                                    let editor = item.downcast::<Editor>()?;
22516                                    let singleton_buffer =
22517                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22518                                    if singleton_buffer == buffer {
22519                                        Some((editor, i, item.item_id()))
22520                                    } else {
22521                                        None
22522                                    }
22523                                })?;
22524                            pane.update(cx, |pane, cx| {
22525                                pane.activate_item(pane_item_index, true, true, window, cx);
22526                                if !PreviewTabsSettings::get_global(cx)
22527                                    .enable_preview_from_multibuffer
22528                                {
22529                                    pane.unpreview_item_if_preview(pane_item_id);
22530                                }
22531                            });
22532                            Some(editor)
22533                        })
22534                        .flatten()
22535                        .unwrap_or_else(|| {
22536                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22537                                .enable_keep_preview_on_code_navigation;
22538                            let allow_new_preview =
22539                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22540                            workspace.open_project_item::<Self>(
22541                                pane.clone(),
22542                                buffer,
22543                                true,
22544                                true,
22545                                keep_old_preview,
22546                                allow_new_preview,
22547                                window,
22548                                cx,
22549                            )
22550                        });
22551
22552                    editor.update(cx, |editor, cx| {
22553                        if has_file && !is_project_file {
22554                            editor.set_read_only(true);
22555                        }
22556                        let autoscroll = match scroll_offset {
22557                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22558                            None => Autoscroll::newest(),
22559                        };
22560                        let nav_history = editor.nav_history.take();
22561                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22562                        let Some((&excerpt_id, _, buffer_snapshot)) =
22563                            multibuffer_snapshot.as_singleton()
22564                        else {
22565                            return;
22566                        };
22567                        editor.change_selections(
22568                            SelectionEffects::scroll(autoscroll),
22569                            window,
22570                            cx,
22571                            |s| {
22572                                s.select_ranges(ranges.into_iter().map(|range| {
22573                                    let range = buffer_snapshot.anchor_before(range.start)
22574                                        ..buffer_snapshot.anchor_after(range.end);
22575                                    multibuffer_snapshot
22576                                        .anchor_range_in_excerpt(excerpt_id, range)
22577                                        .unwrap()
22578                                }));
22579                            },
22580                        );
22581                        editor.nav_history = nav_history;
22582                    });
22583                }
22584            })
22585        });
22586    }
22587
22588    // Allow opening excerpts for buffers that either belong to the current project
22589    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22590    // are also supported so tests and other in-memory views keep working.
22591    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22592        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22593    }
22594
22595    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22596        let snapshot = self.buffer.read(cx).read(cx);
22597        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22598        Some(
22599            ranges
22600                .iter()
22601                .map(move |range| {
22602                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22603                })
22604                .collect(),
22605        )
22606    }
22607
22608    fn selection_replacement_ranges(
22609        &self,
22610        range: Range<MultiBufferOffsetUtf16>,
22611        cx: &mut App,
22612    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22613        let selections = self
22614            .selections
22615            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22616        let newest_selection = selections
22617            .iter()
22618            .max_by_key(|selection| selection.id)
22619            .unwrap();
22620        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22621        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22622        let snapshot = self.buffer.read(cx).read(cx);
22623        selections
22624            .into_iter()
22625            .map(|mut selection| {
22626                selection.start.0.0 =
22627                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22628                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22629                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22630                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22631            })
22632            .collect()
22633    }
22634
22635    fn report_editor_event(
22636        &self,
22637        reported_event: ReportEditorEvent,
22638        file_extension: Option<String>,
22639        cx: &App,
22640    ) {
22641        if cfg!(any(test, feature = "test-support")) {
22642            return;
22643        }
22644
22645        let Some(project) = &self.project else { return };
22646
22647        // If None, we are in a file without an extension
22648        let file = self
22649            .buffer
22650            .read(cx)
22651            .as_singleton()
22652            .and_then(|b| b.read(cx).file());
22653        let file_extension = file_extension.or(file
22654            .as_ref()
22655            .and_then(|file| Path::new(file.file_name(cx)).extension())
22656            .and_then(|e| e.to_str())
22657            .map(|a| a.to_string()));
22658
22659        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22660            .map(|vim_mode| vim_mode.0)
22661            .unwrap_or(false);
22662
22663        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22664        let copilot_enabled = edit_predictions_provider
22665            == language::language_settings::EditPredictionProvider::Copilot;
22666        let copilot_enabled_for_language = self
22667            .buffer
22668            .read(cx)
22669            .language_settings(cx)
22670            .show_edit_predictions;
22671
22672        let project = project.read(cx);
22673        let event_type = reported_event.event_type();
22674
22675        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22676            telemetry::event!(
22677                event_type,
22678                type = if auto_saved {"autosave"} else {"manual"},
22679                file_extension,
22680                vim_mode,
22681                copilot_enabled,
22682                copilot_enabled_for_language,
22683                edit_predictions_provider,
22684                is_via_ssh = project.is_via_remote_server(),
22685            );
22686        } else {
22687            telemetry::event!(
22688                event_type,
22689                file_extension,
22690                vim_mode,
22691                copilot_enabled,
22692                copilot_enabled_for_language,
22693                edit_predictions_provider,
22694                is_via_ssh = project.is_via_remote_server(),
22695            );
22696        };
22697    }
22698
22699    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22700    /// with each line being an array of {text, highlight} objects.
22701    fn copy_highlight_json(
22702        &mut self,
22703        _: &CopyHighlightJson,
22704        window: &mut Window,
22705        cx: &mut Context<Self>,
22706    ) {
22707        #[derive(Serialize)]
22708        struct Chunk<'a> {
22709            text: String,
22710            highlight: Option<&'a str>,
22711        }
22712
22713        let snapshot = self.buffer.read(cx).snapshot(cx);
22714        let range = self
22715            .selected_text_range(false, window, cx)
22716            .and_then(|selection| {
22717                if selection.range.is_empty() {
22718                    None
22719                } else {
22720                    Some(
22721                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22722                            selection.range.start,
22723                        )))
22724                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22725                                selection.range.end,
22726                            ))),
22727                    )
22728                }
22729            })
22730            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22731
22732        let chunks = snapshot.chunks(range, true);
22733        let mut lines = Vec::new();
22734        let mut line: VecDeque<Chunk> = VecDeque::new();
22735
22736        let Some(style) = self.style.as_ref() else {
22737            return;
22738        };
22739
22740        for chunk in chunks {
22741            let highlight = chunk
22742                .syntax_highlight_id
22743                .and_then(|id| id.name(&style.syntax));
22744            let mut chunk_lines = chunk.text.split('\n').peekable();
22745            while let Some(text) = chunk_lines.next() {
22746                let mut merged_with_last_token = false;
22747                if let Some(last_token) = line.back_mut()
22748                    && last_token.highlight == highlight
22749                {
22750                    last_token.text.push_str(text);
22751                    merged_with_last_token = true;
22752                }
22753
22754                if !merged_with_last_token {
22755                    line.push_back(Chunk {
22756                        text: text.into(),
22757                        highlight,
22758                    });
22759                }
22760
22761                if chunk_lines.peek().is_some() {
22762                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22763                        line.pop_front();
22764                    }
22765                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22766                        line.pop_back();
22767                    }
22768
22769                    lines.push(mem::take(&mut line));
22770                }
22771            }
22772        }
22773
22774        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22775            return;
22776        };
22777        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22778    }
22779
22780    pub fn open_context_menu(
22781        &mut self,
22782        _: &OpenContextMenu,
22783        window: &mut Window,
22784        cx: &mut Context<Self>,
22785    ) {
22786        self.request_autoscroll(Autoscroll::newest(), cx);
22787        let position = self
22788            .selections
22789            .newest_display(&self.display_snapshot(cx))
22790            .start;
22791        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22792    }
22793
22794    pub fn replay_insert_event(
22795        &mut self,
22796        text: &str,
22797        relative_utf16_range: Option<Range<isize>>,
22798        window: &mut Window,
22799        cx: &mut Context<Self>,
22800    ) {
22801        if !self.input_enabled {
22802            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22803            return;
22804        }
22805        if let Some(relative_utf16_range) = relative_utf16_range {
22806            let selections = self
22807                .selections
22808                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22809            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22810                let new_ranges = selections.into_iter().map(|range| {
22811                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22812                        range
22813                            .head()
22814                            .0
22815                            .0
22816                            .saturating_add_signed(relative_utf16_range.start),
22817                    ));
22818                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22819                        range
22820                            .head()
22821                            .0
22822                            .0
22823                            .saturating_add_signed(relative_utf16_range.end),
22824                    ));
22825                    start..end
22826                });
22827                s.select_ranges(new_ranges);
22828            });
22829        }
22830
22831        self.handle_input(text, window, cx);
22832    }
22833
22834    pub fn is_focused(&self, window: &Window) -> bool {
22835        self.focus_handle.is_focused(window)
22836    }
22837
22838    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22839        cx.emit(EditorEvent::Focused);
22840
22841        if let Some(descendant) = self
22842            .last_focused_descendant
22843            .take()
22844            .and_then(|descendant| descendant.upgrade())
22845        {
22846            window.focus(&descendant);
22847        } else {
22848            if let Some(blame) = self.blame.as_ref() {
22849                blame.update(cx, GitBlame::focus)
22850            }
22851
22852            self.blink_manager.update(cx, BlinkManager::enable);
22853            self.show_cursor_names(window, cx);
22854            self.buffer.update(cx, |buffer, cx| {
22855                buffer.finalize_last_transaction(cx);
22856                if self.leader_id.is_none() {
22857                    buffer.set_active_selections(
22858                        &self.selections.disjoint_anchors_arc(),
22859                        self.selections.line_mode(),
22860                        self.cursor_shape,
22861                        cx,
22862                    );
22863                }
22864            });
22865
22866            if let Some(position_map) = self.last_position_map.clone() {
22867                EditorElement::mouse_moved(
22868                    self,
22869                    &MouseMoveEvent {
22870                        position: window.mouse_position(),
22871                        pressed_button: None,
22872                        modifiers: window.modifiers(),
22873                    },
22874                    &position_map,
22875                    window,
22876                    cx,
22877                );
22878            }
22879        }
22880    }
22881
22882    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22883        cx.emit(EditorEvent::FocusedIn)
22884    }
22885
22886    fn handle_focus_out(
22887        &mut self,
22888        event: FocusOutEvent,
22889        _window: &mut Window,
22890        cx: &mut Context<Self>,
22891    ) {
22892        if event.blurred != self.focus_handle {
22893            self.last_focused_descendant = Some(event.blurred);
22894        }
22895        self.selection_drag_state = SelectionDragState::None;
22896        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22897    }
22898
22899    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22900        self.blink_manager.update(cx, BlinkManager::disable);
22901        self.buffer
22902            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22903
22904        if let Some(blame) = self.blame.as_ref() {
22905            blame.update(cx, GitBlame::blur)
22906        }
22907        if !self.hover_state.focused(window, cx) {
22908            hide_hover(self, cx);
22909        }
22910        if !self
22911            .context_menu
22912            .borrow()
22913            .as_ref()
22914            .is_some_and(|context_menu| context_menu.focused(window, cx))
22915        {
22916            self.hide_context_menu(window, cx);
22917        }
22918        self.take_active_edit_prediction(cx);
22919        cx.emit(EditorEvent::Blurred);
22920        cx.notify();
22921    }
22922
22923    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22924        let mut pending: String = window
22925            .pending_input_keystrokes()
22926            .into_iter()
22927            .flatten()
22928            .filter_map(|keystroke| keystroke.key_char.clone())
22929            .collect();
22930
22931        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22932            pending = "".to_string();
22933        }
22934
22935        let existing_pending = self
22936            .text_highlights::<PendingInput>(cx)
22937            .map(|(_, ranges)| ranges.to_vec());
22938        if existing_pending.is_none() && pending.is_empty() {
22939            return;
22940        }
22941        let transaction =
22942            self.transact(window, cx, |this, window, cx| {
22943                let selections = this
22944                    .selections
22945                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22946                let edits = selections
22947                    .iter()
22948                    .map(|selection| (selection.end..selection.end, pending.clone()));
22949                this.edit(edits, cx);
22950                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22951                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22952                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22953                    }));
22954                });
22955                if let Some(existing_ranges) = existing_pending {
22956                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22957                    this.edit(edits, cx);
22958                }
22959            });
22960
22961        let snapshot = self.snapshot(window, cx);
22962        let ranges = self
22963            .selections
22964            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22965            .into_iter()
22966            .map(|selection| {
22967                snapshot.buffer_snapshot().anchor_after(selection.end)
22968                    ..snapshot
22969                        .buffer_snapshot()
22970                        .anchor_before(selection.end + pending.len())
22971            })
22972            .collect();
22973
22974        if pending.is_empty() {
22975            self.clear_highlights::<PendingInput>(cx);
22976        } else {
22977            self.highlight_text::<PendingInput>(
22978                ranges,
22979                HighlightStyle {
22980                    underline: Some(UnderlineStyle {
22981                        thickness: px(1.),
22982                        color: None,
22983                        wavy: false,
22984                    }),
22985                    ..Default::default()
22986                },
22987                cx,
22988            );
22989        }
22990
22991        self.ime_transaction = self.ime_transaction.or(transaction);
22992        if let Some(transaction) = self.ime_transaction {
22993            self.buffer.update(cx, |buffer, cx| {
22994                buffer.group_until_transaction(transaction, cx);
22995            });
22996        }
22997
22998        if self.text_highlights::<PendingInput>(cx).is_none() {
22999            self.ime_transaction.take();
23000        }
23001    }
23002
23003    pub fn register_action_renderer(
23004        &mut self,
23005        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23006    ) -> Subscription {
23007        let id = self.next_editor_action_id.post_inc();
23008        self.editor_actions
23009            .borrow_mut()
23010            .insert(id, Box::new(listener));
23011
23012        let editor_actions = self.editor_actions.clone();
23013        Subscription::new(move || {
23014            editor_actions.borrow_mut().remove(&id);
23015        })
23016    }
23017
23018    pub fn register_action<A: Action>(
23019        &mut self,
23020        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23021    ) -> Subscription {
23022        let id = self.next_editor_action_id.post_inc();
23023        let listener = Arc::new(listener);
23024        self.editor_actions.borrow_mut().insert(
23025            id,
23026            Box::new(move |_, window, _| {
23027                let listener = listener.clone();
23028                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23029                    let action = action.downcast_ref().unwrap();
23030                    if phase == DispatchPhase::Bubble {
23031                        listener(action, window, cx)
23032                    }
23033                })
23034            }),
23035        );
23036
23037        let editor_actions = self.editor_actions.clone();
23038        Subscription::new(move || {
23039            editor_actions.borrow_mut().remove(&id);
23040        })
23041    }
23042
23043    pub fn file_header_size(&self) -> u32 {
23044        FILE_HEADER_HEIGHT
23045    }
23046
23047    pub fn restore(
23048        &mut self,
23049        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23050        window: &mut Window,
23051        cx: &mut Context<Self>,
23052    ) {
23053        self.buffer().update(cx, |multi_buffer, cx| {
23054            for (buffer_id, changes) in revert_changes {
23055                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23056                    buffer.update(cx, |buffer, cx| {
23057                        buffer.edit(
23058                            changes
23059                                .into_iter()
23060                                .map(|(range, text)| (range, text.to_string())),
23061                            None,
23062                            cx,
23063                        );
23064                    });
23065                }
23066            }
23067        });
23068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23069            selections.refresh()
23070        });
23071    }
23072
23073    pub fn to_pixel_point(
23074        &mut self,
23075        source: multi_buffer::Anchor,
23076        editor_snapshot: &EditorSnapshot,
23077        window: &mut Window,
23078        cx: &App,
23079    ) -> Option<gpui::Point<Pixels>> {
23080        let source_point = source.to_display_point(editor_snapshot);
23081        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23082    }
23083
23084    pub fn display_to_pixel_point(
23085        &mut self,
23086        source: DisplayPoint,
23087        editor_snapshot: &EditorSnapshot,
23088        window: &mut Window,
23089        cx: &App,
23090    ) -> Option<gpui::Point<Pixels>> {
23091        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23092        let text_layout_details = self.text_layout_details(window);
23093        let scroll_top = text_layout_details
23094            .scroll_anchor
23095            .scroll_position(editor_snapshot)
23096            .y;
23097
23098        if source.row().as_f64() < scroll_top.floor() {
23099            return None;
23100        }
23101        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23102        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23103        Some(gpui::Point::new(source_x, source_y))
23104    }
23105
23106    pub fn has_visible_completions_menu(&self) -> bool {
23107        !self.edit_prediction_preview_is_active()
23108            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23109                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23110            })
23111    }
23112
23113    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23114        if self.mode.is_minimap() {
23115            return;
23116        }
23117        self.addons
23118            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23119    }
23120
23121    pub fn unregister_addon<T: Addon>(&mut self) {
23122        self.addons.remove(&std::any::TypeId::of::<T>());
23123    }
23124
23125    pub fn addon<T: Addon>(&self) -> Option<&T> {
23126        let type_id = std::any::TypeId::of::<T>();
23127        self.addons
23128            .get(&type_id)
23129            .and_then(|item| item.to_any().downcast_ref::<T>())
23130    }
23131
23132    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23133        let type_id = std::any::TypeId::of::<T>();
23134        self.addons
23135            .get_mut(&type_id)
23136            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23137    }
23138
23139    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23140        let text_layout_details = self.text_layout_details(window);
23141        let style = &text_layout_details.editor_style;
23142        let font_id = window.text_system().resolve_font(&style.text.font());
23143        let font_size = style.text.font_size.to_pixels(window.rem_size());
23144        let line_height = style.text.line_height_in_pixels(window.rem_size());
23145        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23146        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23147
23148        CharacterDimensions {
23149            em_width,
23150            em_advance,
23151            line_height,
23152        }
23153    }
23154
23155    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23156        self.load_diff_task.clone()
23157    }
23158
23159    fn read_metadata_from_db(
23160        &mut self,
23161        item_id: u64,
23162        workspace_id: WorkspaceId,
23163        window: &mut Window,
23164        cx: &mut Context<Editor>,
23165    ) {
23166        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23167            && !self.mode.is_minimap()
23168            && WorkspaceSettings::get(None, cx).restore_on_startup
23169                != RestoreOnStartupBehavior::EmptyTab
23170        {
23171            let buffer_snapshot = OnceCell::new();
23172
23173            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23174                && !folds.is_empty()
23175            {
23176                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23177                self.fold_ranges(
23178                    folds
23179                        .into_iter()
23180                        .map(|(start, end)| {
23181                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23182                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23183                        })
23184                        .collect(),
23185                    false,
23186                    window,
23187                    cx,
23188                );
23189            }
23190
23191            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23192                && !selections.is_empty()
23193            {
23194                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23195                // skip adding the initial selection to selection history
23196                self.selection_history.mode = SelectionHistoryMode::Skipping;
23197                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23198                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23199                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23200                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23201                    }));
23202                });
23203                self.selection_history.mode = SelectionHistoryMode::Normal;
23204            };
23205        }
23206
23207        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23208    }
23209
23210    fn update_lsp_data(
23211        &mut self,
23212        for_buffer: Option<BufferId>,
23213        window: &mut Window,
23214        cx: &mut Context<'_, Self>,
23215    ) {
23216        self.pull_diagnostics(for_buffer, window, cx);
23217        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23218    }
23219
23220    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23221        if self.ignore_lsp_data() {
23222            return;
23223        }
23224        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23225            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23226        }
23227    }
23228
23229    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23230        if self.ignore_lsp_data() {
23231            return;
23232        }
23233
23234        if !self.registered_buffers.contains_key(&buffer_id)
23235            && let Some(project) = self.project.as_ref()
23236        {
23237            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23238                project.update(cx, |project, cx| {
23239                    self.registered_buffers.insert(
23240                        buffer_id,
23241                        project.register_buffer_with_language_servers(&buffer, cx),
23242                    );
23243                });
23244            } else {
23245                self.registered_buffers.remove(&buffer_id);
23246            }
23247        }
23248    }
23249
23250    fn ignore_lsp_data(&self) -> bool {
23251        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23252        // skip any LSP updates for it.
23253        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23254    }
23255
23256    fn create_style(&self, cx: &App) -> EditorStyle {
23257        let settings = ThemeSettings::get_global(cx);
23258
23259        let mut text_style = match self.mode {
23260            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23261                color: cx.theme().colors().editor_foreground,
23262                font_family: settings.ui_font.family.clone(),
23263                font_features: settings.ui_font.features.clone(),
23264                font_fallbacks: settings.ui_font.fallbacks.clone(),
23265                font_size: rems(0.875).into(),
23266                font_weight: settings.ui_font.weight,
23267                line_height: relative(settings.buffer_line_height.value()),
23268                ..Default::default()
23269            },
23270            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23271                color: cx.theme().colors().editor_foreground,
23272                font_family: settings.buffer_font.family.clone(),
23273                font_features: settings.buffer_font.features.clone(),
23274                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23275                font_size: settings.buffer_font_size(cx).into(),
23276                font_weight: settings.buffer_font.weight,
23277                line_height: relative(settings.buffer_line_height.value()),
23278                ..Default::default()
23279            },
23280        };
23281        if let Some(text_style_refinement) = &self.text_style_refinement {
23282            text_style.refine(text_style_refinement)
23283        }
23284
23285        let background = match self.mode {
23286            EditorMode::SingleLine => cx.theme().system().transparent,
23287            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23288            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23289            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23290        };
23291
23292        EditorStyle {
23293            background,
23294            border: cx.theme().colors().border,
23295            local_player: cx.theme().players().local(),
23296            text: text_style,
23297            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23298            syntax: cx.theme().syntax().clone(),
23299            status: cx.theme().status().clone(),
23300            inlay_hints_style: make_inlay_hints_style(cx),
23301            edit_prediction_styles: make_suggestion_styles(cx),
23302            unnecessary_code_fade: settings.unnecessary_code_fade,
23303            show_underlines: self.diagnostics_enabled(),
23304        }
23305    }
23306}
23307
23308fn edit_for_markdown_paste<'a>(
23309    buffer: &MultiBufferSnapshot,
23310    range: Range<MultiBufferOffset>,
23311    to_insert: &'a str,
23312    url: Option<url::Url>,
23313) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23314    if url.is_none() {
23315        return (range, Cow::Borrowed(to_insert));
23316    };
23317
23318    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23319
23320    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23321        Cow::Borrowed(to_insert)
23322    } else {
23323        Cow::Owned(format!("[{old_text}]({to_insert})"))
23324    };
23325    (range, new_text)
23326}
23327
23328fn process_completion_for_edit(
23329    completion: &Completion,
23330    intent: CompletionIntent,
23331    buffer: &Entity<Buffer>,
23332    cursor_position: &text::Anchor,
23333    cx: &mut Context<Editor>,
23334) -> CompletionEdit {
23335    let buffer = buffer.read(cx);
23336    let buffer_snapshot = buffer.snapshot();
23337    let (snippet, new_text) = if completion.is_snippet() {
23338        let mut snippet_source = completion.new_text.clone();
23339        // Workaround for typescript language server issues so that methods don't expand within
23340        // strings and functions with type expressions. The previous point is used because the query
23341        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23342        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23343        let previous_point = if previous_point.column > 0 {
23344            cursor_position.to_previous_offset(&buffer_snapshot)
23345        } else {
23346            cursor_position.to_offset(&buffer_snapshot)
23347        };
23348        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23349            && scope.prefers_label_for_snippet_in_completion()
23350            && let Some(label) = completion.label()
23351            && matches!(
23352                completion.kind(),
23353                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23354            )
23355        {
23356            snippet_source = label;
23357        }
23358        match Snippet::parse(&snippet_source).log_err() {
23359            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23360            None => (None, completion.new_text.clone()),
23361        }
23362    } else {
23363        (None, completion.new_text.clone())
23364    };
23365
23366    let mut range_to_replace = {
23367        let replace_range = &completion.replace_range;
23368        if let CompletionSource::Lsp {
23369            insert_range: Some(insert_range),
23370            ..
23371        } = &completion.source
23372        {
23373            debug_assert_eq!(
23374                insert_range.start, replace_range.start,
23375                "insert_range and replace_range should start at the same position"
23376            );
23377            debug_assert!(
23378                insert_range
23379                    .start
23380                    .cmp(cursor_position, &buffer_snapshot)
23381                    .is_le(),
23382                "insert_range should start before or at cursor position"
23383            );
23384            debug_assert!(
23385                replace_range
23386                    .start
23387                    .cmp(cursor_position, &buffer_snapshot)
23388                    .is_le(),
23389                "replace_range should start before or at cursor position"
23390            );
23391
23392            let should_replace = match intent {
23393                CompletionIntent::CompleteWithInsert => false,
23394                CompletionIntent::CompleteWithReplace => true,
23395                CompletionIntent::Complete | CompletionIntent::Compose => {
23396                    let insert_mode =
23397                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23398                            .completions
23399                            .lsp_insert_mode;
23400                    match insert_mode {
23401                        LspInsertMode::Insert => false,
23402                        LspInsertMode::Replace => true,
23403                        LspInsertMode::ReplaceSubsequence => {
23404                            let mut text_to_replace = buffer.chars_for_range(
23405                                buffer.anchor_before(replace_range.start)
23406                                    ..buffer.anchor_after(replace_range.end),
23407                            );
23408                            let mut current_needle = text_to_replace.next();
23409                            for haystack_ch in completion.label.text.chars() {
23410                                if let Some(needle_ch) = current_needle
23411                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23412                                {
23413                                    current_needle = text_to_replace.next();
23414                                }
23415                            }
23416                            current_needle.is_none()
23417                        }
23418                        LspInsertMode::ReplaceSuffix => {
23419                            if replace_range
23420                                .end
23421                                .cmp(cursor_position, &buffer_snapshot)
23422                                .is_gt()
23423                            {
23424                                let range_after_cursor = *cursor_position..replace_range.end;
23425                                let text_after_cursor = buffer
23426                                    .text_for_range(
23427                                        buffer.anchor_before(range_after_cursor.start)
23428                                            ..buffer.anchor_after(range_after_cursor.end),
23429                                    )
23430                                    .collect::<String>()
23431                                    .to_ascii_lowercase();
23432                                completion
23433                                    .label
23434                                    .text
23435                                    .to_ascii_lowercase()
23436                                    .ends_with(&text_after_cursor)
23437                            } else {
23438                                true
23439                            }
23440                        }
23441                    }
23442                }
23443            };
23444
23445            if should_replace {
23446                replace_range.clone()
23447            } else {
23448                insert_range.clone()
23449            }
23450        } else {
23451            replace_range.clone()
23452        }
23453    };
23454
23455    if range_to_replace
23456        .end
23457        .cmp(cursor_position, &buffer_snapshot)
23458        .is_lt()
23459    {
23460        range_to_replace.end = *cursor_position;
23461    }
23462
23463    let replace_range = range_to_replace.to_offset(buffer);
23464    CompletionEdit {
23465        new_text,
23466        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23467        snippet,
23468    }
23469}
23470
23471struct CompletionEdit {
23472    new_text: String,
23473    replace_range: Range<BufferOffset>,
23474    snippet: Option<Snippet>,
23475}
23476
23477fn insert_extra_newline_brackets(
23478    buffer: &MultiBufferSnapshot,
23479    range: Range<MultiBufferOffset>,
23480    language: &language::LanguageScope,
23481) -> bool {
23482    let leading_whitespace_len = buffer
23483        .reversed_chars_at(range.start)
23484        .take_while(|c| c.is_whitespace() && *c != '\n')
23485        .map(|c| c.len_utf8())
23486        .sum::<usize>();
23487    let trailing_whitespace_len = buffer
23488        .chars_at(range.end)
23489        .take_while(|c| c.is_whitespace() && *c != '\n')
23490        .map(|c| c.len_utf8())
23491        .sum::<usize>();
23492    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23493
23494    language.brackets().any(|(pair, enabled)| {
23495        let pair_start = pair.start.trim_end();
23496        let pair_end = pair.end.trim_start();
23497
23498        enabled
23499            && pair.newline
23500            && buffer.contains_str_at(range.end, pair_end)
23501            && buffer.contains_str_at(
23502                range.start.saturating_sub_usize(pair_start.len()),
23503                pair_start,
23504            )
23505    })
23506}
23507
23508fn insert_extra_newline_tree_sitter(
23509    buffer: &MultiBufferSnapshot,
23510    range: Range<MultiBufferOffset>,
23511) -> bool {
23512    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23513        [(buffer, range, _)] => (*buffer, range.clone()),
23514        _ => return false,
23515    };
23516    let pair = {
23517        let mut result: Option<BracketMatch<usize>> = None;
23518
23519        for pair in buffer
23520            .all_bracket_ranges(range.start.0..range.end.0)
23521            .filter(move |pair| {
23522                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23523            })
23524        {
23525            let len = pair.close_range.end - pair.open_range.start;
23526
23527            if let Some(existing) = &result {
23528                let existing_len = existing.close_range.end - existing.open_range.start;
23529                if len > existing_len {
23530                    continue;
23531                }
23532            }
23533
23534            result = Some(pair);
23535        }
23536
23537        result
23538    };
23539    let Some(pair) = pair else {
23540        return false;
23541    };
23542    pair.newline_only
23543        && buffer
23544            .chars_for_range(pair.open_range.end..range.start.0)
23545            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23546            .all(|c| c.is_whitespace() && c != '\n')
23547}
23548
23549fn update_uncommitted_diff_for_buffer(
23550    editor: Entity<Editor>,
23551    project: &Entity<Project>,
23552    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23553    buffer: Entity<MultiBuffer>,
23554    cx: &mut App,
23555) -> Task<()> {
23556    let mut tasks = Vec::new();
23557    project.update(cx, |project, cx| {
23558        for buffer in buffers {
23559            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23560                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23561            }
23562        }
23563    });
23564    cx.spawn(async move |cx| {
23565        let diffs = future::join_all(tasks).await;
23566        if editor
23567            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23568            .unwrap_or(false)
23569        {
23570            return;
23571        }
23572
23573        buffer
23574            .update(cx, |buffer, cx| {
23575                for diff in diffs.into_iter().flatten() {
23576                    buffer.add_diff(diff, cx);
23577                }
23578            })
23579            .ok();
23580    })
23581}
23582
23583fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23584    let tab_size = tab_size.get() as usize;
23585    let mut width = offset;
23586
23587    for ch in text.chars() {
23588        width += if ch == '\t' {
23589            tab_size - (width % tab_size)
23590        } else {
23591            1
23592        };
23593    }
23594
23595    width - offset
23596}
23597
23598#[cfg(test)]
23599mod tests {
23600    use super::*;
23601
23602    #[test]
23603    fn test_string_size_with_expanded_tabs() {
23604        let nz = |val| NonZeroU32::new(val).unwrap();
23605        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23606        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23607        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23608        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23609        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23610        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23611        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23612        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23613    }
23614}
23615
23616/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23617struct WordBreakingTokenizer<'a> {
23618    input: &'a str,
23619}
23620
23621impl<'a> WordBreakingTokenizer<'a> {
23622    fn new(input: &'a str) -> Self {
23623        Self { input }
23624    }
23625}
23626
23627fn is_char_ideographic(ch: char) -> bool {
23628    use unicode_script::Script::*;
23629    use unicode_script::UnicodeScript;
23630    matches!(ch.script(), Han | Tangut | Yi)
23631}
23632
23633fn is_grapheme_ideographic(text: &str) -> bool {
23634    text.chars().any(is_char_ideographic)
23635}
23636
23637fn is_grapheme_whitespace(text: &str) -> bool {
23638    text.chars().any(|x| x.is_whitespace())
23639}
23640
23641fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23642    text.chars()
23643        .next()
23644        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23645}
23646
23647#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23648enum WordBreakToken<'a> {
23649    Word { token: &'a str, grapheme_len: usize },
23650    InlineWhitespace { token: &'a str, grapheme_len: usize },
23651    Newline,
23652}
23653
23654impl<'a> Iterator for WordBreakingTokenizer<'a> {
23655    /// Yields a span, the count of graphemes in the token, and whether it was
23656    /// whitespace. Note that it also breaks at word boundaries.
23657    type Item = WordBreakToken<'a>;
23658
23659    fn next(&mut self) -> Option<Self::Item> {
23660        use unicode_segmentation::UnicodeSegmentation;
23661        if self.input.is_empty() {
23662            return None;
23663        }
23664
23665        let mut iter = self.input.graphemes(true).peekable();
23666        let mut offset = 0;
23667        let mut grapheme_len = 0;
23668        if let Some(first_grapheme) = iter.next() {
23669            let is_newline = first_grapheme == "\n";
23670            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23671            offset += first_grapheme.len();
23672            grapheme_len += 1;
23673            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23674                if let Some(grapheme) = iter.peek().copied()
23675                    && should_stay_with_preceding_ideograph(grapheme)
23676                {
23677                    offset += grapheme.len();
23678                    grapheme_len += 1;
23679                }
23680            } else {
23681                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23682                let mut next_word_bound = words.peek().copied();
23683                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23684                    next_word_bound = words.next();
23685                }
23686                while let Some(grapheme) = iter.peek().copied() {
23687                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23688                        break;
23689                    };
23690                    if is_grapheme_whitespace(grapheme) != is_whitespace
23691                        || (grapheme == "\n") != is_newline
23692                    {
23693                        break;
23694                    };
23695                    offset += grapheme.len();
23696                    grapheme_len += 1;
23697                    iter.next();
23698                }
23699            }
23700            let token = &self.input[..offset];
23701            self.input = &self.input[offset..];
23702            if token == "\n" {
23703                Some(WordBreakToken::Newline)
23704            } else if is_whitespace {
23705                Some(WordBreakToken::InlineWhitespace {
23706                    token,
23707                    grapheme_len,
23708                })
23709            } else {
23710                Some(WordBreakToken::Word {
23711                    token,
23712                    grapheme_len,
23713                })
23714            }
23715        } else {
23716            None
23717        }
23718    }
23719}
23720
23721#[test]
23722fn test_word_breaking_tokenizer() {
23723    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23724        ("", &[]),
23725        ("  ", &[whitespace("  ", 2)]),
23726        ("Ʒ", &[word("Ʒ", 1)]),
23727        ("Ǽ", &[word("Ǽ", 1)]),
23728        ("", &[word("", 1)]),
23729        ("⋑⋑", &[word("⋑⋑", 2)]),
23730        (
23731            "原理,进而",
23732            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23733        ),
23734        (
23735            "hello world",
23736            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23737        ),
23738        (
23739            "hello, world",
23740            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23741        ),
23742        (
23743            "  hello world",
23744            &[
23745                whitespace("  ", 2),
23746                word("hello", 5),
23747                whitespace(" ", 1),
23748                word("world", 5),
23749            ],
23750        ),
23751        (
23752            "这是什么 \n 钢笔",
23753            &[
23754                word("", 1),
23755                word("", 1),
23756                word("", 1),
23757                word("", 1),
23758                whitespace(" ", 1),
23759                newline(),
23760                whitespace(" ", 1),
23761                word("", 1),
23762                word("", 1),
23763            ],
23764        ),
23765        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23766    ];
23767
23768    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23769        WordBreakToken::Word {
23770            token,
23771            grapheme_len,
23772        }
23773    }
23774
23775    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23776        WordBreakToken::InlineWhitespace {
23777            token,
23778            grapheme_len,
23779        }
23780    }
23781
23782    fn newline() -> WordBreakToken<'static> {
23783        WordBreakToken::Newline
23784    }
23785
23786    for (input, result) in tests {
23787        assert_eq!(
23788            WordBreakingTokenizer::new(input)
23789                .collect::<Vec<_>>()
23790                .as_slice(),
23791            *result,
23792        );
23793    }
23794}
23795
23796fn wrap_with_prefix(
23797    first_line_prefix: String,
23798    subsequent_lines_prefix: String,
23799    unwrapped_text: String,
23800    wrap_column: usize,
23801    tab_size: NonZeroU32,
23802    preserve_existing_whitespace: bool,
23803) -> String {
23804    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23805    let subsequent_lines_prefix_len =
23806        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23807    let mut wrapped_text = String::new();
23808    let mut current_line = first_line_prefix;
23809    let mut is_first_line = true;
23810
23811    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23812    let mut current_line_len = first_line_prefix_len;
23813    let mut in_whitespace = false;
23814    for token in tokenizer {
23815        let have_preceding_whitespace = in_whitespace;
23816        match token {
23817            WordBreakToken::Word {
23818                token,
23819                grapheme_len,
23820            } => {
23821                in_whitespace = false;
23822                let current_prefix_len = if is_first_line {
23823                    first_line_prefix_len
23824                } else {
23825                    subsequent_lines_prefix_len
23826                };
23827                if current_line_len + grapheme_len > wrap_column
23828                    && current_line_len != current_prefix_len
23829                {
23830                    wrapped_text.push_str(current_line.trim_end());
23831                    wrapped_text.push('\n');
23832                    is_first_line = false;
23833                    current_line = subsequent_lines_prefix.clone();
23834                    current_line_len = subsequent_lines_prefix_len;
23835                }
23836                current_line.push_str(token);
23837                current_line_len += grapheme_len;
23838            }
23839            WordBreakToken::InlineWhitespace {
23840                mut token,
23841                mut grapheme_len,
23842            } => {
23843                in_whitespace = true;
23844                if have_preceding_whitespace && !preserve_existing_whitespace {
23845                    continue;
23846                }
23847                if !preserve_existing_whitespace {
23848                    // Keep a single whitespace grapheme as-is
23849                    if let Some(first) =
23850                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23851                    {
23852                        token = first;
23853                    } else {
23854                        token = " ";
23855                    }
23856                    grapheme_len = 1;
23857                }
23858                let current_prefix_len = if is_first_line {
23859                    first_line_prefix_len
23860                } else {
23861                    subsequent_lines_prefix_len
23862                };
23863                if current_line_len + grapheme_len > wrap_column {
23864                    wrapped_text.push_str(current_line.trim_end());
23865                    wrapped_text.push('\n');
23866                    is_first_line = false;
23867                    current_line = subsequent_lines_prefix.clone();
23868                    current_line_len = subsequent_lines_prefix_len;
23869                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23870                    current_line.push_str(token);
23871                    current_line_len += grapheme_len;
23872                }
23873            }
23874            WordBreakToken::Newline => {
23875                in_whitespace = true;
23876                let current_prefix_len = if is_first_line {
23877                    first_line_prefix_len
23878                } else {
23879                    subsequent_lines_prefix_len
23880                };
23881                if preserve_existing_whitespace {
23882                    wrapped_text.push_str(current_line.trim_end());
23883                    wrapped_text.push('\n');
23884                    is_first_line = false;
23885                    current_line = subsequent_lines_prefix.clone();
23886                    current_line_len = subsequent_lines_prefix_len;
23887                } else if have_preceding_whitespace {
23888                    continue;
23889                } else if current_line_len + 1 > wrap_column
23890                    && current_line_len != current_prefix_len
23891                {
23892                    wrapped_text.push_str(current_line.trim_end());
23893                    wrapped_text.push('\n');
23894                    is_first_line = false;
23895                    current_line = subsequent_lines_prefix.clone();
23896                    current_line_len = subsequent_lines_prefix_len;
23897                } else if current_line_len != current_prefix_len {
23898                    current_line.push(' ');
23899                    current_line_len += 1;
23900                }
23901            }
23902        }
23903    }
23904
23905    if !current_line.is_empty() {
23906        wrapped_text.push_str(&current_line);
23907    }
23908    wrapped_text
23909}
23910
23911#[test]
23912fn test_wrap_with_prefix() {
23913    assert_eq!(
23914        wrap_with_prefix(
23915            "# ".to_string(),
23916            "# ".to_string(),
23917            "abcdefg".to_string(),
23918            4,
23919            NonZeroU32::new(4).unwrap(),
23920            false,
23921        ),
23922        "# abcdefg"
23923    );
23924    assert_eq!(
23925        wrap_with_prefix(
23926            "".to_string(),
23927            "".to_string(),
23928            "\thello world".to_string(),
23929            8,
23930            NonZeroU32::new(4).unwrap(),
23931            false,
23932        ),
23933        "hello\nworld"
23934    );
23935    assert_eq!(
23936        wrap_with_prefix(
23937            "// ".to_string(),
23938            "// ".to_string(),
23939            "xx \nyy zz aa bb cc".to_string(),
23940            12,
23941            NonZeroU32::new(4).unwrap(),
23942            false,
23943        ),
23944        "// xx yy zz\n// aa bb cc"
23945    );
23946    assert_eq!(
23947        wrap_with_prefix(
23948            String::new(),
23949            String::new(),
23950            "这是什么 \n 钢笔".to_string(),
23951            3,
23952            NonZeroU32::new(4).unwrap(),
23953            false,
23954        ),
23955        "这是什\n么 钢\n"
23956    );
23957    assert_eq!(
23958        wrap_with_prefix(
23959            String::new(),
23960            String::new(),
23961            format!("foo{}bar", '\u{2009}'), // thin space
23962            80,
23963            NonZeroU32::new(4).unwrap(),
23964            false,
23965        ),
23966        format!("foo{}bar", '\u{2009}')
23967    );
23968}
23969
23970pub trait CollaborationHub {
23971    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23972    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23973    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23974}
23975
23976impl CollaborationHub for Entity<Project> {
23977    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23978        self.read(cx).collaborators()
23979    }
23980
23981    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23982        self.read(cx).user_store().read(cx).participant_indices()
23983    }
23984
23985    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23986        let this = self.read(cx);
23987        let user_ids = this.collaborators().values().map(|c| c.user_id);
23988        this.user_store().read(cx).participant_names(user_ids, cx)
23989    }
23990}
23991
23992pub trait SemanticsProvider {
23993    fn hover(
23994        &self,
23995        buffer: &Entity<Buffer>,
23996        position: text::Anchor,
23997        cx: &mut App,
23998    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23999
24000    fn inline_values(
24001        &self,
24002        buffer_handle: Entity<Buffer>,
24003        range: Range<text::Anchor>,
24004        cx: &mut App,
24005    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24006
24007    fn applicable_inlay_chunks(
24008        &self,
24009        buffer: &Entity<Buffer>,
24010        ranges: &[Range<text::Anchor>],
24011        cx: &mut App,
24012    ) -> Vec<Range<BufferRow>>;
24013
24014    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24015
24016    fn inlay_hints(
24017        &self,
24018        invalidate: InvalidationStrategy,
24019        buffer: Entity<Buffer>,
24020        ranges: Vec<Range<text::Anchor>>,
24021        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24022        cx: &mut App,
24023    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24024
24025    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24026
24027    fn document_highlights(
24028        &self,
24029        buffer: &Entity<Buffer>,
24030        position: text::Anchor,
24031        cx: &mut App,
24032    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24033
24034    fn definitions(
24035        &self,
24036        buffer: &Entity<Buffer>,
24037        position: text::Anchor,
24038        kind: GotoDefinitionKind,
24039        cx: &mut App,
24040    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24041
24042    fn range_for_rename(
24043        &self,
24044        buffer: &Entity<Buffer>,
24045        position: text::Anchor,
24046        cx: &mut App,
24047    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24048
24049    fn perform_rename(
24050        &self,
24051        buffer: &Entity<Buffer>,
24052        position: text::Anchor,
24053        new_name: String,
24054        cx: &mut App,
24055    ) -> Option<Task<Result<ProjectTransaction>>>;
24056}
24057
24058pub trait CompletionProvider {
24059    fn completions(
24060        &self,
24061        excerpt_id: ExcerptId,
24062        buffer: &Entity<Buffer>,
24063        buffer_position: text::Anchor,
24064        trigger: CompletionContext,
24065        window: &mut Window,
24066        cx: &mut Context<Editor>,
24067    ) -> Task<Result<Vec<CompletionResponse>>>;
24068
24069    fn resolve_completions(
24070        &self,
24071        _buffer: Entity<Buffer>,
24072        _completion_indices: Vec<usize>,
24073        _completions: Rc<RefCell<Box<[Completion]>>>,
24074        _cx: &mut Context<Editor>,
24075    ) -> Task<Result<bool>> {
24076        Task::ready(Ok(false))
24077    }
24078
24079    fn apply_additional_edits_for_completion(
24080        &self,
24081        _buffer: Entity<Buffer>,
24082        _completions: Rc<RefCell<Box<[Completion]>>>,
24083        _completion_index: usize,
24084        _push_to_history: bool,
24085        _cx: &mut Context<Editor>,
24086    ) -> Task<Result<Option<language::Transaction>>> {
24087        Task::ready(Ok(None))
24088    }
24089
24090    fn is_completion_trigger(
24091        &self,
24092        buffer: &Entity<Buffer>,
24093        position: language::Anchor,
24094        text: &str,
24095        trigger_in_words: bool,
24096        cx: &mut Context<Editor>,
24097    ) -> bool;
24098
24099    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24100
24101    fn sort_completions(&self) -> bool {
24102        true
24103    }
24104
24105    fn filter_completions(&self) -> bool {
24106        true
24107    }
24108
24109    fn show_snippets(&self) -> bool {
24110        false
24111    }
24112}
24113
24114pub trait CodeActionProvider {
24115    fn id(&self) -> Arc<str>;
24116
24117    fn code_actions(
24118        &self,
24119        buffer: &Entity<Buffer>,
24120        range: Range<text::Anchor>,
24121        window: &mut Window,
24122        cx: &mut App,
24123    ) -> Task<Result<Vec<CodeAction>>>;
24124
24125    fn apply_code_action(
24126        &self,
24127        buffer_handle: Entity<Buffer>,
24128        action: CodeAction,
24129        excerpt_id: ExcerptId,
24130        push_to_history: bool,
24131        window: &mut Window,
24132        cx: &mut App,
24133    ) -> Task<Result<ProjectTransaction>>;
24134}
24135
24136impl CodeActionProvider for Entity<Project> {
24137    fn id(&self) -> Arc<str> {
24138        "project".into()
24139    }
24140
24141    fn code_actions(
24142        &self,
24143        buffer: &Entity<Buffer>,
24144        range: Range<text::Anchor>,
24145        _window: &mut Window,
24146        cx: &mut App,
24147    ) -> Task<Result<Vec<CodeAction>>> {
24148        self.update(cx, |project, cx| {
24149            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24150            let code_actions = project.code_actions(buffer, range, None, cx);
24151            cx.background_spawn(async move {
24152                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24153                Ok(code_lens_actions
24154                    .context("code lens fetch")?
24155                    .into_iter()
24156                    .flatten()
24157                    .chain(
24158                        code_actions
24159                            .context("code action fetch")?
24160                            .into_iter()
24161                            .flatten(),
24162                    )
24163                    .collect())
24164            })
24165        })
24166    }
24167
24168    fn apply_code_action(
24169        &self,
24170        buffer_handle: Entity<Buffer>,
24171        action: CodeAction,
24172        _excerpt_id: ExcerptId,
24173        push_to_history: bool,
24174        _window: &mut Window,
24175        cx: &mut App,
24176    ) -> Task<Result<ProjectTransaction>> {
24177        self.update(cx, |project, cx| {
24178            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24179        })
24180    }
24181}
24182
24183fn snippet_completions(
24184    project: &Project,
24185    buffer: &Entity<Buffer>,
24186    buffer_anchor: text::Anchor,
24187    classifier: CharClassifier,
24188    cx: &mut App,
24189) -> Task<Result<CompletionResponse>> {
24190    let languages = buffer.read(cx).languages_at(buffer_anchor);
24191    let snippet_store = project.snippets().read(cx);
24192
24193    let scopes: Vec<_> = languages
24194        .iter()
24195        .filter_map(|language| {
24196            let language_name = language.lsp_id();
24197            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24198
24199            if snippets.is_empty() {
24200                None
24201            } else {
24202                Some((language.default_scope(), snippets))
24203            }
24204        })
24205        .collect();
24206
24207    if scopes.is_empty() {
24208        return Task::ready(Ok(CompletionResponse {
24209            completions: vec![],
24210            display_options: CompletionDisplayOptions::default(),
24211            is_incomplete: false,
24212        }));
24213    }
24214
24215    let snapshot = buffer.read(cx).text_snapshot();
24216    let executor = cx.background_executor().clone();
24217
24218    cx.background_spawn(async move {
24219        let is_word_char = |c| classifier.is_word(c);
24220
24221        let mut is_incomplete = false;
24222        let mut completions: Vec<Completion> = Vec::new();
24223
24224        const MAX_PREFIX_LEN: usize = 128;
24225        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24226        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24227        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24228
24229        let max_buffer_window: String = snapshot
24230            .text_for_range(window_start..buffer_offset)
24231            .collect();
24232
24233        if max_buffer_window.is_empty() {
24234            return Ok(CompletionResponse {
24235                completions: vec![],
24236                display_options: CompletionDisplayOptions::default(),
24237                is_incomplete: true,
24238            });
24239        }
24240
24241        for (_scope, snippets) in scopes.into_iter() {
24242            // Sort snippets by word count to match longer snippet prefixes first.
24243            let mut sorted_snippet_candidates = snippets
24244                .iter()
24245                .enumerate()
24246                .flat_map(|(snippet_ix, snippet)| {
24247                    snippet
24248                        .prefix
24249                        .iter()
24250                        .enumerate()
24251                        .map(move |(prefix_ix, prefix)| {
24252                            let word_count =
24253                                snippet_candidate_suffixes(prefix, is_word_char).count();
24254                            ((snippet_ix, prefix_ix), prefix, word_count)
24255                        })
24256                })
24257                .collect_vec();
24258            sorted_snippet_candidates
24259                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24260
24261            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24262
24263            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24264                .take(
24265                    sorted_snippet_candidates
24266                        .first()
24267                        .map(|(_, _, word_count)| *word_count)
24268                        .unwrap_or_default(),
24269                )
24270                .collect_vec();
24271
24272            const MAX_RESULTS: usize = 100;
24273            // Each match also remembers how many characters from the buffer it consumed
24274            let mut matches: Vec<(StringMatch, usize)> = vec![];
24275
24276            let mut snippet_list_cutoff_index = 0;
24277            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24278                let word_count = buffer_index + 1;
24279                // Increase `snippet_list_cutoff_index` until we have all of the
24280                // snippets with sufficiently many words.
24281                while sorted_snippet_candidates
24282                    .get(snippet_list_cutoff_index)
24283                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24284                        *snippet_word_count >= word_count
24285                    })
24286                {
24287                    snippet_list_cutoff_index += 1;
24288                }
24289
24290                // Take only the candidates with at least `word_count` many words
24291                let snippet_candidates_at_word_len =
24292                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24293
24294                let candidates = snippet_candidates_at_word_len
24295                    .iter()
24296                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24297                    .enumerate() // index in `sorted_snippet_candidates`
24298                    // First char must match
24299                    .filter(|(_ix, prefix)| {
24300                        itertools::equal(
24301                            prefix
24302                                .chars()
24303                                .next()
24304                                .into_iter()
24305                                .flat_map(|c| c.to_lowercase()),
24306                            buffer_window
24307                                .chars()
24308                                .next()
24309                                .into_iter()
24310                                .flat_map(|c| c.to_lowercase()),
24311                        )
24312                    })
24313                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24314                    .collect::<Vec<StringMatchCandidate>>();
24315
24316                matches.extend(
24317                    fuzzy::match_strings(
24318                        &candidates,
24319                        &buffer_window,
24320                        buffer_window.chars().any(|c| c.is_uppercase()),
24321                        true,
24322                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24323                        &Default::default(),
24324                        executor.clone(),
24325                    )
24326                    .await
24327                    .into_iter()
24328                    .map(|string_match| (string_match, buffer_window.len())),
24329                );
24330
24331                if matches.len() >= MAX_RESULTS {
24332                    break;
24333                }
24334            }
24335
24336            let to_lsp = |point: &text::Anchor| {
24337                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24338                point_to_lsp(end)
24339            };
24340            let lsp_end = to_lsp(&buffer_anchor);
24341
24342            if matches.len() >= MAX_RESULTS {
24343                is_incomplete = true;
24344            }
24345
24346            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24347                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24348                    sorted_snippet_candidates[string_match.candidate_id];
24349                let snippet = &snippets[snippet_index];
24350                let start = buffer_offset - buffer_window_len;
24351                let start = snapshot.anchor_before(start);
24352                let range = start..buffer_anchor;
24353                let lsp_start = to_lsp(&start);
24354                let lsp_range = lsp::Range {
24355                    start: lsp_start,
24356                    end: lsp_end,
24357                };
24358                Completion {
24359                    replace_range: range,
24360                    new_text: snippet.body.clone(),
24361                    source: CompletionSource::Lsp {
24362                        insert_range: None,
24363                        server_id: LanguageServerId(usize::MAX),
24364                        resolved: true,
24365                        lsp_completion: Box::new(lsp::CompletionItem {
24366                            label: snippet.prefix.first().unwrap().clone(),
24367                            kind: Some(CompletionItemKind::SNIPPET),
24368                            label_details: snippet.description.as_ref().map(|description| {
24369                                lsp::CompletionItemLabelDetails {
24370                                    detail: Some(description.clone()),
24371                                    description: None,
24372                                }
24373                            }),
24374                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24375                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24376                                lsp::InsertReplaceEdit {
24377                                    new_text: snippet.body.clone(),
24378                                    insert: lsp_range,
24379                                    replace: lsp_range,
24380                                },
24381                            )),
24382                            filter_text: Some(snippet.body.clone()),
24383                            sort_text: Some(char::MAX.to_string()),
24384                            ..lsp::CompletionItem::default()
24385                        }),
24386                        lsp_defaults: None,
24387                    },
24388                    label: CodeLabel {
24389                        text: matching_prefix.clone(),
24390                        runs: Vec::new(),
24391                        filter_range: 0..matching_prefix.len(),
24392                    },
24393                    icon_path: None,
24394                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24395                        single_line: snippet.name.clone().into(),
24396                        plain_text: snippet
24397                            .description
24398                            .clone()
24399                            .map(|description| description.into()),
24400                    }),
24401                    insert_text_mode: None,
24402                    confirm: None,
24403                    match_start: Some(start),
24404                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24405                }
24406            }));
24407        }
24408
24409        Ok(CompletionResponse {
24410            completions,
24411            display_options: CompletionDisplayOptions::default(),
24412            is_incomplete,
24413        })
24414    })
24415}
24416
24417impl CompletionProvider for Entity<Project> {
24418    fn completions(
24419        &self,
24420        _excerpt_id: ExcerptId,
24421        buffer: &Entity<Buffer>,
24422        buffer_position: text::Anchor,
24423        options: CompletionContext,
24424        _window: &mut Window,
24425        cx: &mut Context<Editor>,
24426    ) -> Task<Result<Vec<CompletionResponse>>> {
24427        self.update(cx, |project, cx| {
24428            let task = project.completions(buffer, buffer_position, options, cx);
24429            cx.background_spawn(task)
24430        })
24431    }
24432
24433    fn resolve_completions(
24434        &self,
24435        buffer: Entity<Buffer>,
24436        completion_indices: Vec<usize>,
24437        completions: Rc<RefCell<Box<[Completion]>>>,
24438        cx: &mut Context<Editor>,
24439    ) -> Task<Result<bool>> {
24440        self.update(cx, |project, cx| {
24441            project.lsp_store().update(cx, |lsp_store, cx| {
24442                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24443            })
24444        })
24445    }
24446
24447    fn apply_additional_edits_for_completion(
24448        &self,
24449        buffer: Entity<Buffer>,
24450        completions: Rc<RefCell<Box<[Completion]>>>,
24451        completion_index: usize,
24452        push_to_history: bool,
24453        cx: &mut Context<Editor>,
24454    ) -> Task<Result<Option<language::Transaction>>> {
24455        self.update(cx, |project, cx| {
24456            project.lsp_store().update(cx, |lsp_store, cx| {
24457                lsp_store.apply_additional_edits_for_completion(
24458                    buffer,
24459                    completions,
24460                    completion_index,
24461                    push_to_history,
24462                    cx,
24463                )
24464            })
24465        })
24466    }
24467
24468    fn is_completion_trigger(
24469        &self,
24470        buffer: &Entity<Buffer>,
24471        position: language::Anchor,
24472        text: &str,
24473        trigger_in_words: bool,
24474        cx: &mut Context<Editor>,
24475    ) -> bool {
24476        let mut chars = text.chars();
24477        let char = if let Some(char) = chars.next() {
24478            char
24479        } else {
24480            return false;
24481        };
24482        if chars.next().is_some() {
24483            return false;
24484        }
24485
24486        let buffer = buffer.read(cx);
24487        let snapshot = buffer.snapshot();
24488        let classifier = snapshot
24489            .char_classifier_at(position)
24490            .scope_context(Some(CharScopeContext::Completion));
24491        if trigger_in_words && classifier.is_word(char) {
24492            return true;
24493        }
24494
24495        buffer.completion_triggers().contains(text)
24496    }
24497
24498    fn show_snippets(&self) -> bool {
24499        true
24500    }
24501}
24502
24503impl SemanticsProvider for Entity<Project> {
24504    fn hover(
24505        &self,
24506        buffer: &Entity<Buffer>,
24507        position: text::Anchor,
24508        cx: &mut App,
24509    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24510        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24511    }
24512
24513    fn document_highlights(
24514        &self,
24515        buffer: &Entity<Buffer>,
24516        position: text::Anchor,
24517        cx: &mut App,
24518    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24519        Some(self.update(cx, |project, cx| {
24520            project.document_highlights(buffer, position, cx)
24521        }))
24522    }
24523
24524    fn definitions(
24525        &self,
24526        buffer: &Entity<Buffer>,
24527        position: text::Anchor,
24528        kind: GotoDefinitionKind,
24529        cx: &mut App,
24530    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24531        Some(self.update(cx, |project, cx| match kind {
24532            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24533            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24534            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24535            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24536        }))
24537    }
24538
24539    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24540        self.update(cx, |project, cx| {
24541            if project
24542                .active_debug_session(cx)
24543                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24544            {
24545                return true;
24546            }
24547
24548            buffer.update(cx, |buffer, cx| {
24549                project.any_language_server_supports_inlay_hints(buffer, cx)
24550            })
24551        })
24552    }
24553
24554    fn inline_values(
24555        &self,
24556        buffer_handle: Entity<Buffer>,
24557        range: Range<text::Anchor>,
24558        cx: &mut App,
24559    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24560        self.update(cx, |project, cx| {
24561            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24562
24563            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24564        })
24565    }
24566
24567    fn applicable_inlay_chunks(
24568        &self,
24569        buffer: &Entity<Buffer>,
24570        ranges: &[Range<text::Anchor>],
24571        cx: &mut App,
24572    ) -> Vec<Range<BufferRow>> {
24573        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24574            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24575        })
24576    }
24577
24578    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24579        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24580            lsp_store.invalidate_inlay_hints(for_buffers)
24581        });
24582    }
24583
24584    fn inlay_hints(
24585        &self,
24586        invalidate: InvalidationStrategy,
24587        buffer: Entity<Buffer>,
24588        ranges: Vec<Range<text::Anchor>>,
24589        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24590        cx: &mut App,
24591    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24592        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24593            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24594        }))
24595    }
24596
24597    fn range_for_rename(
24598        &self,
24599        buffer: &Entity<Buffer>,
24600        position: text::Anchor,
24601        cx: &mut App,
24602    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24603        Some(self.update(cx, |project, cx| {
24604            let buffer = buffer.clone();
24605            let task = project.prepare_rename(buffer.clone(), position, cx);
24606            cx.spawn(async move |_, cx| {
24607                Ok(match task.await? {
24608                    PrepareRenameResponse::Success(range) => Some(range),
24609                    PrepareRenameResponse::InvalidPosition => None,
24610                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24611                        // Fallback on using TreeSitter info to determine identifier range
24612                        buffer.read_with(cx, |buffer, _| {
24613                            let snapshot = buffer.snapshot();
24614                            let (range, kind) = snapshot.surrounding_word(position, None);
24615                            if kind != Some(CharKind::Word) {
24616                                return None;
24617                            }
24618                            Some(
24619                                snapshot.anchor_before(range.start)
24620                                    ..snapshot.anchor_after(range.end),
24621                            )
24622                        })?
24623                    }
24624                })
24625            })
24626        }))
24627    }
24628
24629    fn perform_rename(
24630        &self,
24631        buffer: &Entity<Buffer>,
24632        position: text::Anchor,
24633        new_name: String,
24634        cx: &mut App,
24635    ) -> Option<Task<Result<ProjectTransaction>>> {
24636        Some(self.update(cx, |project, cx| {
24637            project.perform_rename(buffer.clone(), position, new_name, cx)
24638        }))
24639    }
24640}
24641
24642fn consume_contiguous_rows(
24643    contiguous_row_selections: &mut Vec<Selection<Point>>,
24644    selection: &Selection<Point>,
24645    display_map: &DisplaySnapshot,
24646    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24647) -> (MultiBufferRow, MultiBufferRow) {
24648    contiguous_row_selections.push(selection.clone());
24649    let start_row = starting_row(selection, display_map);
24650    let mut end_row = ending_row(selection, display_map);
24651
24652    while let Some(next_selection) = selections.peek() {
24653        if next_selection.start.row <= end_row.0 {
24654            end_row = ending_row(next_selection, display_map);
24655            contiguous_row_selections.push(selections.next().unwrap().clone());
24656        } else {
24657            break;
24658        }
24659    }
24660    (start_row, end_row)
24661}
24662
24663fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24664    if selection.start.column > 0 {
24665        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24666    } else {
24667        MultiBufferRow(selection.start.row)
24668    }
24669}
24670
24671fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24672    if next_selection.end.column > 0 || next_selection.is_empty() {
24673        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24674    } else {
24675        MultiBufferRow(next_selection.end.row)
24676    }
24677}
24678
24679impl EditorSnapshot {
24680    pub fn remote_selections_in_range<'a>(
24681        &'a self,
24682        range: &'a Range<Anchor>,
24683        collaboration_hub: &dyn CollaborationHub,
24684        cx: &'a App,
24685    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24686        let participant_names = collaboration_hub.user_names(cx);
24687        let participant_indices = collaboration_hub.user_participant_indices(cx);
24688        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24689        let collaborators_by_replica_id = collaborators_by_peer_id
24690            .values()
24691            .map(|collaborator| (collaborator.replica_id, collaborator))
24692            .collect::<HashMap<_, _>>();
24693        self.buffer_snapshot()
24694            .selections_in_range(range, false)
24695            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24696                if replica_id == ReplicaId::AGENT {
24697                    Some(RemoteSelection {
24698                        replica_id,
24699                        selection,
24700                        cursor_shape,
24701                        line_mode,
24702                        collaborator_id: CollaboratorId::Agent,
24703                        user_name: Some("Agent".into()),
24704                        color: cx.theme().players().agent(),
24705                    })
24706                } else {
24707                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24708                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24709                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24710                    Some(RemoteSelection {
24711                        replica_id,
24712                        selection,
24713                        cursor_shape,
24714                        line_mode,
24715                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24716                        user_name,
24717                        color: if let Some(index) = participant_index {
24718                            cx.theme().players().color_for_participant(index.0)
24719                        } else {
24720                            cx.theme().players().absent()
24721                        },
24722                    })
24723                }
24724            })
24725    }
24726
24727    pub fn hunks_for_ranges(
24728        &self,
24729        ranges: impl IntoIterator<Item = Range<Point>>,
24730    ) -> Vec<MultiBufferDiffHunk> {
24731        let mut hunks = Vec::new();
24732        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24733            HashMap::default();
24734        for query_range in ranges {
24735            let query_rows =
24736                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24737            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24738                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24739            ) {
24740                // Include deleted hunks that are adjacent to the query range, because
24741                // otherwise they would be missed.
24742                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24743                if hunk.status().is_deleted() {
24744                    intersects_range |= hunk.row_range.start == query_rows.end;
24745                    intersects_range |= hunk.row_range.end == query_rows.start;
24746                }
24747                if intersects_range {
24748                    if !processed_buffer_rows
24749                        .entry(hunk.buffer_id)
24750                        .or_default()
24751                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24752                    {
24753                        continue;
24754                    }
24755                    hunks.push(hunk);
24756                }
24757            }
24758        }
24759
24760        hunks
24761    }
24762
24763    fn display_diff_hunks_for_rows<'a>(
24764        &'a self,
24765        display_rows: Range<DisplayRow>,
24766        folded_buffers: &'a HashSet<BufferId>,
24767    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24768        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24769        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24770
24771        self.buffer_snapshot()
24772            .diff_hunks_in_range(buffer_start..buffer_end)
24773            .filter_map(|hunk| {
24774                if folded_buffers.contains(&hunk.buffer_id) {
24775                    return None;
24776                }
24777
24778                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24779                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24780
24781                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24782                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24783
24784                let display_hunk = if hunk_display_start.column() != 0 {
24785                    DisplayDiffHunk::Folded {
24786                        display_row: hunk_display_start.row(),
24787                    }
24788                } else {
24789                    let mut end_row = hunk_display_end.row();
24790                    if hunk_display_end.column() > 0 {
24791                        end_row.0 += 1;
24792                    }
24793                    let is_created_file = hunk.is_created_file();
24794
24795                    DisplayDiffHunk::Unfolded {
24796                        status: hunk.status(),
24797                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24798                            ..hunk.diff_base_byte_range.end.0,
24799                        word_diffs: hunk.word_diffs,
24800                        display_row_range: hunk_display_start.row()..end_row,
24801                        multi_buffer_range: Anchor::range_in_buffer(
24802                            hunk.excerpt_id,
24803                            hunk.buffer_range,
24804                        ),
24805                        is_created_file,
24806                    }
24807                };
24808
24809                Some(display_hunk)
24810            })
24811    }
24812
24813    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24814        self.display_snapshot
24815            .buffer_snapshot()
24816            .language_at(position)
24817    }
24818
24819    pub fn is_focused(&self) -> bool {
24820        self.is_focused
24821    }
24822
24823    pub fn placeholder_text(&self) -> Option<String> {
24824        self.placeholder_display_snapshot
24825            .as_ref()
24826            .map(|display_map| display_map.text())
24827    }
24828
24829    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24830        self.scroll_anchor.scroll_position(&self.display_snapshot)
24831    }
24832
24833    pub fn gutter_dimensions(
24834        &self,
24835        font_id: FontId,
24836        font_size: Pixels,
24837        style: &EditorStyle,
24838        window: &mut Window,
24839        cx: &App,
24840    ) -> GutterDimensions {
24841        if self.show_gutter
24842            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24843            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24844        {
24845            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24846                matches!(
24847                    ProjectSettings::get_global(cx).git.git_gutter,
24848                    GitGutterSetting::TrackedFiles
24849                )
24850            });
24851            let gutter_settings = EditorSettings::get_global(cx).gutter;
24852            let show_line_numbers = self
24853                .show_line_numbers
24854                .unwrap_or(gutter_settings.line_numbers);
24855            let line_gutter_width = if show_line_numbers {
24856                // Avoid flicker-like gutter resizes when the line number gains another digit by
24857                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24858                let min_width_for_number_on_gutter =
24859                    ch_advance * gutter_settings.min_line_number_digits as f32;
24860                self.max_line_number_width(style, window)
24861                    .max(min_width_for_number_on_gutter)
24862            } else {
24863                0.0.into()
24864            };
24865
24866            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24867            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24868
24869            let git_blame_entries_width =
24870                self.git_blame_gutter_max_author_length
24871                    .map(|max_author_length| {
24872                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24873                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24874
24875                        /// The number of characters to dedicate to gaps and margins.
24876                        const SPACING_WIDTH: usize = 4;
24877
24878                        let max_char_count = max_author_length.min(renderer.max_author_length())
24879                            + ::git::SHORT_SHA_LENGTH
24880                            + MAX_RELATIVE_TIMESTAMP.len()
24881                            + SPACING_WIDTH;
24882
24883                        ch_advance * max_char_count
24884                    });
24885
24886            let is_singleton = self.buffer_snapshot().is_singleton();
24887
24888            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24889            left_padding += if !is_singleton {
24890                ch_width * 4.0
24891            } else if show_runnables || show_breakpoints {
24892                ch_width * 3.0
24893            } else if show_git_gutter && show_line_numbers {
24894                ch_width * 2.0
24895            } else if show_git_gutter || show_line_numbers {
24896                ch_width
24897            } else {
24898                px(0.)
24899            };
24900
24901            let shows_folds = is_singleton && gutter_settings.folds;
24902
24903            let right_padding = if shows_folds && show_line_numbers {
24904                ch_width * 4.0
24905            } else if shows_folds || (!is_singleton && show_line_numbers) {
24906                ch_width * 3.0
24907            } else if show_line_numbers {
24908                ch_width
24909            } else {
24910                px(0.)
24911            };
24912
24913            GutterDimensions {
24914                left_padding,
24915                right_padding,
24916                width: line_gutter_width + left_padding + right_padding,
24917                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24918                git_blame_entries_width,
24919            }
24920        } else if self.offset_content {
24921            GutterDimensions::default_with_margin(font_id, font_size, cx)
24922        } else {
24923            GutterDimensions::default()
24924        }
24925    }
24926
24927    pub fn render_crease_toggle(
24928        &self,
24929        buffer_row: MultiBufferRow,
24930        row_contains_cursor: bool,
24931        editor: Entity<Editor>,
24932        window: &mut Window,
24933        cx: &mut App,
24934    ) -> Option<AnyElement> {
24935        let folded = self.is_line_folded(buffer_row);
24936        let mut is_foldable = false;
24937
24938        if let Some(crease) = self
24939            .crease_snapshot
24940            .query_row(buffer_row, self.buffer_snapshot())
24941        {
24942            is_foldable = true;
24943            match crease {
24944                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24945                    if let Some(render_toggle) = render_toggle {
24946                        let toggle_callback =
24947                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24948                                if folded {
24949                                    editor.update(cx, |editor, cx| {
24950                                        editor.fold_at(buffer_row, window, cx)
24951                                    });
24952                                } else {
24953                                    editor.update(cx, |editor, cx| {
24954                                        editor.unfold_at(buffer_row, window, cx)
24955                                    });
24956                                }
24957                            });
24958                        return Some((render_toggle)(
24959                            buffer_row,
24960                            folded,
24961                            toggle_callback,
24962                            window,
24963                            cx,
24964                        ));
24965                    }
24966                }
24967            }
24968        }
24969
24970        is_foldable |= self.starts_indent(buffer_row);
24971
24972        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24973            Some(
24974                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24975                    .toggle_state(folded)
24976                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24977                        if folded {
24978                            this.unfold_at(buffer_row, window, cx);
24979                        } else {
24980                            this.fold_at(buffer_row, window, cx);
24981                        }
24982                    }))
24983                    .into_any_element(),
24984            )
24985        } else {
24986            None
24987        }
24988    }
24989
24990    pub fn render_crease_trailer(
24991        &self,
24992        buffer_row: MultiBufferRow,
24993        window: &mut Window,
24994        cx: &mut App,
24995    ) -> Option<AnyElement> {
24996        let folded = self.is_line_folded(buffer_row);
24997        if let Crease::Inline { render_trailer, .. } = self
24998            .crease_snapshot
24999            .query_row(buffer_row, self.buffer_snapshot())?
25000        {
25001            let render_trailer = render_trailer.as_ref()?;
25002            Some(render_trailer(buffer_row, folded, window, cx))
25003        } else {
25004            None
25005        }
25006    }
25007
25008    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25009        let digit_count = self.widest_line_number().ilog10() + 1;
25010        column_pixels(style, digit_count as usize, window)
25011    }
25012}
25013
25014pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25015    let font_size = style.text.font_size.to_pixels(window.rem_size());
25016    let layout = window.text_system().shape_line(
25017        SharedString::from(" ".repeat(column)),
25018        font_size,
25019        &[TextRun {
25020            len: column,
25021            font: style.text.font(),
25022            color: Hsla::default(),
25023            ..Default::default()
25024        }],
25025        None,
25026    );
25027
25028    layout.width
25029}
25030
25031impl Deref for EditorSnapshot {
25032    type Target = DisplaySnapshot;
25033
25034    fn deref(&self) -> &Self::Target {
25035        &self.display_snapshot
25036    }
25037}
25038
25039#[derive(Clone, Debug, PartialEq, Eq)]
25040pub enum EditorEvent {
25041    InputIgnored {
25042        text: Arc<str>,
25043    },
25044    InputHandled {
25045        utf16_range_to_replace: Option<Range<isize>>,
25046        text: Arc<str>,
25047    },
25048    ExcerptsAdded {
25049        buffer: Entity<Buffer>,
25050        predecessor: ExcerptId,
25051        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25052    },
25053    ExcerptsRemoved {
25054        ids: Vec<ExcerptId>,
25055        removed_buffer_ids: Vec<BufferId>,
25056    },
25057    BufferFoldToggled {
25058        ids: Vec<ExcerptId>,
25059        folded: bool,
25060    },
25061    ExcerptsEdited {
25062        ids: Vec<ExcerptId>,
25063    },
25064    ExcerptsExpanded {
25065        ids: Vec<ExcerptId>,
25066    },
25067    BufferEdited,
25068    Edited {
25069        transaction_id: clock::Lamport,
25070    },
25071    Reparsed(BufferId),
25072    Focused,
25073    FocusedIn,
25074    Blurred,
25075    DirtyChanged,
25076    Saved,
25077    TitleChanged,
25078    SelectionsChanged {
25079        local: bool,
25080    },
25081    ScrollPositionChanged {
25082        local: bool,
25083        autoscroll: bool,
25084    },
25085    TransactionUndone {
25086        transaction_id: clock::Lamport,
25087    },
25088    TransactionBegun {
25089        transaction_id: clock::Lamport,
25090    },
25091    CursorShapeChanged,
25092    BreadcrumbsChanged,
25093    PushedToNavHistory {
25094        anchor: Anchor,
25095        is_deactivate: bool,
25096    },
25097}
25098
25099impl EventEmitter<EditorEvent> for Editor {}
25100
25101impl Focusable for Editor {
25102    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25103        self.focus_handle.clone()
25104    }
25105}
25106
25107impl Render for Editor {
25108    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25109        EditorElement::new(&cx.entity(), self.create_style(cx))
25110    }
25111}
25112
25113impl EntityInputHandler for Editor {
25114    fn text_for_range(
25115        &mut self,
25116        range_utf16: Range<usize>,
25117        adjusted_range: &mut Option<Range<usize>>,
25118        _: &mut Window,
25119        cx: &mut Context<Self>,
25120    ) -> Option<String> {
25121        let snapshot = self.buffer.read(cx).read(cx);
25122        let start = snapshot.clip_offset_utf16(
25123            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25124            Bias::Left,
25125        );
25126        let end = snapshot.clip_offset_utf16(
25127            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25128            Bias::Right,
25129        );
25130        if (start.0.0..end.0.0) != range_utf16 {
25131            adjusted_range.replace(start.0.0..end.0.0);
25132        }
25133        Some(snapshot.text_for_range(start..end).collect())
25134    }
25135
25136    fn selected_text_range(
25137        &mut self,
25138        ignore_disabled_input: bool,
25139        _: &mut Window,
25140        cx: &mut Context<Self>,
25141    ) -> Option<UTF16Selection> {
25142        // Prevent the IME menu from appearing when holding down an alphabetic key
25143        // while input is disabled.
25144        if !ignore_disabled_input && !self.input_enabled {
25145            return None;
25146        }
25147
25148        let selection = self
25149            .selections
25150            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25151        let range = selection.range();
25152
25153        Some(UTF16Selection {
25154            range: range.start.0.0..range.end.0.0,
25155            reversed: selection.reversed,
25156        })
25157    }
25158
25159    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25160        let snapshot = self.buffer.read(cx).read(cx);
25161        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25162        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25163    }
25164
25165    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25166        self.clear_highlights::<InputComposition>(cx);
25167        self.ime_transaction.take();
25168    }
25169
25170    fn replace_text_in_range(
25171        &mut self,
25172        range_utf16: Option<Range<usize>>,
25173        text: &str,
25174        window: &mut Window,
25175        cx: &mut Context<Self>,
25176    ) {
25177        if !self.input_enabled {
25178            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25179            return;
25180        }
25181
25182        self.transact(window, cx, |this, window, cx| {
25183            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25184                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25185                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25186                Some(this.selection_replacement_ranges(range_utf16, cx))
25187            } else {
25188                this.marked_text_ranges(cx)
25189            };
25190
25191            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25192                let newest_selection_id = this.selections.newest_anchor().id;
25193                this.selections
25194                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25195                    .iter()
25196                    .zip(ranges_to_replace.iter())
25197                    .find_map(|(selection, range)| {
25198                        if selection.id == newest_selection_id {
25199                            Some(
25200                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25201                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25202                            )
25203                        } else {
25204                            None
25205                        }
25206                    })
25207            });
25208
25209            cx.emit(EditorEvent::InputHandled {
25210                utf16_range_to_replace: range_to_replace,
25211                text: text.into(),
25212            });
25213
25214            if let Some(new_selected_ranges) = new_selected_ranges {
25215                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25216                    selections.select_ranges(new_selected_ranges)
25217                });
25218                this.backspace(&Default::default(), window, cx);
25219            }
25220
25221            this.handle_input(text, window, cx);
25222        });
25223
25224        if let Some(transaction) = self.ime_transaction {
25225            self.buffer.update(cx, |buffer, cx| {
25226                buffer.group_until_transaction(transaction, cx);
25227            });
25228        }
25229
25230        self.unmark_text(window, cx);
25231    }
25232
25233    fn replace_and_mark_text_in_range(
25234        &mut self,
25235        range_utf16: Option<Range<usize>>,
25236        text: &str,
25237        new_selected_range_utf16: Option<Range<usize>>,
25238        window: &mut Window,
25239        cx: &mut Context<Self>,
25240    ) {
25241        if !self.input_enabled {
25242            return;
25243        }
25244
25245        let transaction = self.transact(window, cx, |this, window, cx| {
25246            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25247                let snapshot = this.buffer.read(cx).read(cx);
25248                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25249                    for marked_range in &mut marked_ranges {
25250                        marked_range.end = marked_range.start + relative_range_utf16.end;
25251                        marked_range.start += relative_range_utf16.start;
25252                        marked_range.start =
25253                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25254                        marked_range.end =
25255                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25256                    }
25257                }
25258                Some(marked_ranges)
25259            } else if let Some(range_utf16) = range_utf16 {
25260                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25261                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25262                Some(this.selection_replacement_ranges(range_utf16, cx))
25263            } else {
25264                None
25265            };
25266
25267            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25268                let newest_selection_id = this.selections.newest_anchor().id;
25269                this.selections
25270                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25271                    .iter()
25272                    .zip(ranges_to_replace.iter())
25273                    .find_map(|(selection, range)| {
25274                        if selection.id == newest_selection_id {
25275                            Some(
25276                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25277                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25278                            )
25279                        } else {
25280                            None
25281                        }
25282                    })
25283            });
25284
25285            cx.emit(EditorEvent::InputHandled {
25286                utf16_range_to_replace: range_to_replace,
25287                text: text.into(),
25288            });
25289
25290            if let Some(ranges) = ranges_to_replace {
25291                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25292                    s.select_ranges(ranges)
25293                });
25294            }
25295
25296            let marked_ranges = {
25297                let snapshot = this.buffer.read(cx).read(cx);
25298                this.selections
25299                    .disjoint_anchors_arc()
25300                    .iter()
25301                    .map(|selection| {
25302                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25303                    })
25304                    .collect::<Vec<_>>()
25305            };
25306
25307            if text.is_empty() {
25308                this.unmark_text(window, cx);
25309            } else {
25310                this.highlight_text::<InputComposition>(
25311                    marked_ranges.clone(),
25312                    HighlightStyle {
25313                        underline: Some(UnderlineStyle {
25314                            thickness: px(1.),
25315                            color: None,
25316                            wavy: false,
25317                        }),
25318                        ..Default::default()
25319                    },
25320                    cx,
25321                );
25322            }
25323
25324            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25325            let use_autoclose = this.use_autoclose;
25326            let use_auto_surround = this.use_auto_surround;
25327            this.set_use_autoclose(false);
25328            this.set_use_auto_surround(false);
25329            this.handle_input(text, window, cx);
25330            this.set_use_autoclose(use_autoclose);
25331            this.set_use_auto_surround(use_auto_surround);
25332
25333            if let Some(new_selected_range) = new_selected_range_utf16 {
25334                let snapshot = this.buffer.read(cx).read(cx);
25335                let new_selected_ranges = marked_ranges
25336                    .into_iter()
25337                    .map(|marked_range| {
25338                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25339                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25340                            insertion_start.0 + new_selected_range.start,
25341                        ));
25342                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25343                            insertion_start.0 + new_selected_range.end,
25344                        ));
25345                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25346                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25347                    })
25348                    .collect::<Vec<_>>();
25349
25350                drop(snapshot);
25351                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25352                    selections.select_ranges(new_selected_ranges)
25353                });
25354            }
25355        });
25356
25357        self.ime_transaction = self.ime_transaction.or(transaction);
25358        if let Some(transaction) = self.ime_transaction {
25359            self.buffer.update(cx, |buffer, cx| {
25360                buffer.group_until_transaction(transaction, cx);
25361            });
25362        }
25363
25364        if self.text_highlights::<InputComposition>(cx).is_none() {
25365            self.ime_transaction.take();
25366        }
25367    }
25368
25369    fn bounds_for_range(
25370        &mut self,
25371        range_utf16: Range<usize>,
25372        element_bounds: gpui::Bounds<Pixels>,
25373        window: &mut Window,
25374        cx: &mut Context<Self>,
25375    ) -> Option<gpui::Bounds<Pixels>> {
25376        let text_layout_details = self.text_layout_details(window);
25377        let CharacterDimensions {
25378            em_width,
25379            em_advance,
25380            line_height,
25381        } = self.character_dimensions(window);
25382
25383        let snapshot = self.snapshot(window, cx);
25384        let scroll_position = snapshot.scroll_position();
25385        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25386
25387        let start =
25388            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25389        let x = Pixels::from(
25390            ScrollOffset::from(
25391                snapshot.x_for_display_point(start, &text_layout_details)
25392                    + self.gutter_dimensions.full_width(),
25393            ) - scroll_left,
25394        );
25395        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25396
25397        Some(Bounds {
25398            origin: element_bounds.origin + point(x, y),
25399            size: size(em_width, line_height),
25400        })
25401    }
25402
25403    fn character_index_for_point(
25404        &mut self,
25405        point: gpui::Point<Pixels>,
25406        _window: &mut Window,
25407        _cx: &mut Context<Self>,
25408    ) -> Option<usize> {
25409        let position_map = self.last_position_map.as_ref()?;
25410        if !position_map.text_hitbox.contains(&point) {
25411            return None;
25412        }
25413        let display_point = position_map.point_for_position(point).previous_valid;
25414        let anchor = position_map
25415            .snapshot
25416            .display_point_to_anchor(display_point, Bias::Left);
25417        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25418        Some(utf16_offset.0.0)
25419    }
25420
25421    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25422        self.input_enabled
25423    }
25424}
25425
25426trait SelectionExt {
25427    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25428    fn spanned_rows(
25429        &self,
25430        include_end_if_at_line_start: bool,
25431        map: &DisplaySnapshot,
25432    ) -> Range<MultiBufferRow>;
25433}
25434
25435impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25436    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25437        let start = self
25438            .start
25439            .to_point(map.buffer_snapshot())
25440            .to_display_point(map);
25441        let end = self
25442            .end
25443            .to_point(map.buffer_snapshot())
25444            .to_display_point(map);
25445        if self.reversed {
25446            end..start
25447        } else {
25448            start..end
25449        }
25450    }
25451
25452    fn spanned_rows(
25453        &self,
25454        include_end_if_at_line_start: bool,
25455        map: &DisplaySnapshot,
25456    ) -> Range<MultiBufferRow> {
25457        let start = self.start.to_point(map.buffer_snapshot());
25458        let mut end = self.end.to_point(map.buffer_snapshot());
25459        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25460            end.row -= 1;
25461        }
25462
25463        let buffer_start = map.prev_line_boundary(start).0;
25464        let buffer_end = map.next_line_boundary(end).0;
25465        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25466    }
25467}
25468
25469impl<T: InvalidationRegion> InvalidationStack<T> {
25470    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25471    where
25472        S: Clone + ToOffset,
25473    {
25474        while let Some(region) = self.last() {
25475            let all_selections_inside_invalidation_ranges =
25476                if selections.len() == region.ranges().len() {
25477                    selections
25478                        .iter()
25479                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25480                        .all(|(selection, invalidation_range)| {
25481                            let head = selection.head().to_offset(buffer);
25482                            invalidation_range.start <= head && invalidation_range.end >= head
25483                        })
25484                } else {
25485                    false
25486                };
25487
25488            if all_selections_inside_invalidation_ranges {
25489                break;
25490            } else {
25491                self.pop();
25492            }
25493        }
25494    }
25495}
25496
25497impl<T> Default for InvalidationStack<T> {
25498    fn default() -> Self {
25499        Self(Default::default())
25500    }
25501}
25502
25503impl<T> Deref for InvalidationStack<T> {
25504    type Target = Vec<T>;
25505
25506    fn deref(&self) -> &Self::Target {
25507        &self.0
25508    }
25509}
25510
25511impl<T> DerefMut for InvalidationStack<T> {
25512    fn deref_mut(&mut self) -> &mut Self::Target {
25513        &mut self.0
25514    }
25515}
25516
25517impl InvalidationRegion for SnippetState {
25518    fn ranges(&self) -> &[Range<Anchor>] {
25519        &self.ranges[self.active_index]
25520    }
25521}
25522
25523fn edit_prediction_edit_text(
25524    current_snapshot: &BufferSnapshot,
25525    edits: &[(Range<Anchor>, impl AsRef<str>)],
25526    edit_preview: &EditPreview,
25527    include_deletions: bool,
25528    cx: &App,
25529) -> HighlightedText {
25530    let edits = edits
25531        .iter()
25532        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25533        .collect::<Vec<_>>();
25534
25535    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25536}
25537
25538fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25539    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25540    // Just show the raw edit text with basic styling
25541    let mut text = String::new();
25542    let mut highlights = Vec::new();
25543
25544    let insertion_highlight_style = HighlightStyle {
25545        color: Some(cx.theme().colors().text),
25546        ..Default::default()
25547    };
25548
25549    for (_, edit_text) in edits {
25550        let start_offset = text.len();
25551        text.push_str(edit_text);
25552        let end_offset = text.len();
25553
25554        if start_offset < end_offset {
25555            highlights.push((start_offset..end_offset, insertion_highlight_style));
25556        }
25557    }
25558
25559    HighlightedText {
25560        text: text.into(),
25561        highlights,
25562    }
25563}
25564
25565pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25566    match severity {
25567        lsp::DiagnosticSeverity::ERROR => colors.error,
25568        lsp::DiagnosticSeverity::WARNING => colors.warning,
25569        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25570        lsp::DiagnosticSeverity::HINT => colors.info,
25571        _ => colors.ignored,
25572    }
25573}
25574
25575pub fn styled_runs_for_code_label<'a>(
25576    label: &'a CodeLabel,
25577    syntax_theme: &'a theme::SyntaxTheme,
25578    local_player: &'a theme::PlayerColor,
25579) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25580    let fade_out = HighlightStyle {
25581        fade_out: Some(0.35),
25582        ..Default::default()
25583    };
25584
25585    let mut prev_end = label.filter_range.end;
25586    label
25587        .runs
25588        .iter()
25589        .enumerate()
25590        .flat_map(move |(ix, (range, highlight_id))| {
25591            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25592                HighlightStyle {
25593                    color: Some(local_player.cursor),
25594                    ..Default::default()
25595                }
25596            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25597                HighlightStyle {
25598                    background_color: Some(local_player.selection),
25599                    ..Default::default()
25600                }
25601            } else if let Some(style) = highlight_id.style(syntax_theme) {
25602                style
25603            } else {
25604                return Default::default();
25605            };
25606            let muted_style = style.highlight(fade_out);
25607
25608            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25609            if range.start >= label.filter_range.end {
25610                if range.start > prev_end {
25611                    runs.push((prev_end..range.start, fade_out));
25612                }
25613                runs.push((range.clone(), muted_style));
25614            } else if range.end <= label.filter_range.end {
25615                runs.push((range.clone(), style));
25616            } else {
25617                runs.push((range.start..label.filter_range.end, style));
25618                runs.push((label.filter_range.end..range.end, muted_style));
25619            }
25620            prev_end = cmp::max(prev_end, range.end);
25621
25622            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25623                runs.push((prev_end..label.text.len(), fade_out));
25624            }
25625
25626            runs
25627        })
25628}
25629
25630pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25631    let mut prev_index = 0;
25632    let mut prev_codepoint: Option<char> = None;
25633    text.char_indices()
25634        .chain([(text.len(), '\0')])
25635        .filter_map(move |(index, codepoint)| {
25636            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25637            let is_boundary = index == text.len()
25638                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25639                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25640            if is_boundary {
25641                let chunk = &text[prev_index..index];
25642                prev_index = index;
25643                Some(chunk)
25644            } else {
25645                None
25646            }
25647        })
25648}
25649
25650/// Given a string of text immediately before the cursor, iterates over possible
25651/// strings a snippet could match to. More precisely: returns an iterator over
25652/// suffixes of `text` created by splitting at word boundaries (before & after
25653/// every non-word character).
25654///
25655/// Shorter suffixes are returned first.
25656pub(crate) fn snippet_candidate_suffixes(
25657    text: &str,
25658    is_word_char: impl Fn(char) -> bool,
25659) -> impl std::iter::Iterator<Item = &str> {
25660    let mut prev_index = text.len();
25661    let mut prev_codepoint = None;
25662    text.char_indices()
25663        .rev()
25664        .chain([(0, '\0')])
25665        .filter_map(move |(index, codepoint)| {
25666            let prev_index = std::mem::replace(&mut prev_index, index);
25667            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25668            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25669                None
25670            } else {
25671                let chunk = &text[prev_index..]; // go to end of string
25672                Some(chunk)
25673            }
25674        })
25675}
25676
25677pub trait RangeToAnchorExt: Sized {
25678    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25679
25680    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25681        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25682        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25683    }
25684}
25685
25686impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25687    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25688        let start_offset = self.start.to_offset(snapshot);
25689        let end_offset = self.end.to_offset(snapshot);
25690        if start_offset == end_offset {
25691            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25692        } else {
25693            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25694        }
25695    }
25696}
25697
25698pub trait RowExt {
25699    fn as_f64(&self) -> f64;
25700
25701    fn next_row(&self) -> Self;
25702
25703    fn previous_row(&self) -> Self;
25704
25705    fn minus(&self, other: Self) -> u32;
25706}
25707
25708impl RowExt for DisplayRow {
25709    fn as_f64(&self) -> f64 {
25710        self.0 as _
25711    }
25712
25713    fn next_row(&self) -> Self {
25714        Self(self.0 + 1)
25715    }
25716
25717    fn previous_row(&self) -> Self {
25718        Self(self.0.saturating_sub(1))
25719    }
25720
25721    fn minus(&self, other: Self) -> u32 {
25722        self.0 - other.0
25723    }
25724}
25725
25726impl RowExt for MultiBufferRow {
25727    fn as_f64(&self) -> f64 {
25728        self.0 as _
25729    }
25730
25731    fn next_row(&self) -> Self {
25732        Self(self.0 + 1)
25733    }
25734
25735    fn previous_row(&self) -> Self {
25736        Self(self.0.saturating_sub(1))
25737    }
25738
25739    fn minus(&self, other: Self) -> u32 {
25740        self.0 - other.0
25741    }
25742}
25743
25744trait RowRangeExt {
25745    type Row;
25746
25747    fn len(&self) -> usize;
25748
25749    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25750}
25751
25752impl RowRangeExt for Range<MultiBufferRow> {
25753    type Row = MultiBufferRow;
25754
25755    fn len(&self) -> usize {
25756        (self.end.0 - self.start.0) as usize
25757    }
25758
25759    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25760        (self.start.0..self.end.0).map(MultiBufferRow)
25761    }
25762}
25763
25764impl RowRangeExt for Range<DisplayRow> {
25765    type Row = DisplayRow;
25766
25767    fn len(&self) -> usize {
25768        (self.end.0 - self.start.0) as usize
25769    }
25770
25771    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25772        (self.start.0..self.end.0).map(DisplayRow)
25773    }
25774}
25775
25776/// If select range has more than one line, we
25777/// just point the cursor to range.start.
25778fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25779    if range.start.row == range.end.row {
25780        range
25781    } else {
25782        range.start..range.start
25783    }
25784}
25785pub struct KillRing(ClipboardItem);
25786impl Global for KillRing {}
25787
25788const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25789
25790enum BreakpointPromptEditAction {
25791    Log,
25792    Condition,
25793    HitCondition,
25794}
25795
25796struct BreakpointPromptEditor {
25797    pub(crate) prompt: Entity<Editor>,
25798    editor: WeakEntity<Editor>,
25799    breakpoint_anchor: Anchor,
25800    breakpoint: Breakpoint,
25801    edit_action: BreakpointPromptEditAction,
25802    block_ids: HashSet<CustomBlockId>,
25803    editor_margins: Arc<Mutex<EditorMargins>>,
25804    _subscriptions: Vec<Subscription>,
25805}
25806
25807impl BreakpointPromptEditor {
25808    const MAX_LINES: u8 = 4;
25809
25810    fn new(
25811        editor: WeakEntity<Editor>,
25812        breakpoint_anchor: Anchor,
25813        breakpoint: Breakpoint,
25814        edit_action: BreakpointPromptEditAction,
25815        window: &mut Window,
25816        cx: &mut Context<Self>,
25817    ) -> Self {
25818        let base_text = match edit_action {
25819            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25820            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25821            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25822        }
25823        .map(|msg| msg.to_string())
25824        .unwrap_or_default();
25825
25826        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25827        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25828
25829        let prompt = cx.new(|cx| {
25830            let mut prompt = Editor::new(
25831                EditorMode::AutoHeight {
25832                    min_lines: 1,
25833                    max_lines: Some(Self::MAX_LINES as usize),
25834                },
25835                buffer,
25836                None,
25837                window,
25838                cx,
25839            );
25840            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25841            prompt.set_show_cursor_when_unfocused(false, cx);
25842            prompt.set_placeholder_text(
25843                match edit_action {
25844                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25845                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25846                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25847                },
25848                window,
25849                cx,
25850            );
25851
25852            prompt
25853        });
25854
25855        Self {
25856            prompt,
25857            editor,
25858            breakpoint_anchor,
25859            breakpoint,
25860            edit_action,
25861            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25862            block_ids: Default::default(),
25863            _subscriptions: vec![],
25864        }
25865    }
25866
25867    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25868        self.block_ids.extend(block_ids)
25869    }
25870
25871    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25872        if let Some(editor) = self.editor.upgrade() {
25873            let message = self
25874                .prompt
25875                .read(cx)
25876                .buffer
25877                .read(cx)
25878                .as_singleton()
25879                .expect("A multi buffer in breakpoint prompt isn't possible")
25880                .read(cx)
25881                .as_rope()
25882                .to_string();
25883
25884            editor.update(cx, |editor, cx| {
25885                editor.edit_breakpoint_at_anchor(
25886                    self.breakpoint_anchor,
25887                    self.breakpoint.clone(),
25888                    match self.edit_action {
25889                        BreakpointPromptEditAction::Log => {
25890                            BreakpointEditAction::EditLogMessage(message.into())
25891                        }
25892                        BreakpointPromptEditAction::Condition => {
25893                            BreakpointEditAction::EditCondition(message.into())
25894                        }
25895                        BreakpointPromptEditAction::HitCondition => {
25896                            BreakpointEditAction::EditHitCondition(message.into())
25897                        }
25898                    },
25899                    cx,
25900                );
25901
25902                editor.remove_blocks(self.block_ids.clone(), None, cx);
25903                cx.focus_self(window);
25904            });
25905        }
25906    }
25907
25908    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25909        self.editor
25910            .update(cx, |editor, cx| {
25911                editor.remove_blocks(self.block_ids.clone(), None, cx);
25912                window.focus(&editor.focus_handle);
25913            })
25914            .log_err();
25915    }
25916
25917    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25918        let settings = ThemeSettings::get_global(cx);
25919        let text_style = TextStyle {
25920            color: if self.prompt.read(cx).read_only(cx) {
25921                cx.theme().colors().text_disabled
25922            } else {
25923                cx.theme().colors().text
25924            },
25925            font_family: settings.buffer_font.family.clone(),
25926            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25927            font_size: settings.buffer_font_size(cx).into(),
25928            font_weight: settings.buffer_font.weight,
25929            line_height: relative(settings.buffer_line_height.value()),
25930            ..Default::default()
25931        };
25932        EditorElement::new(
25933            &self.prompt,
25934            EditorStyle {
25935                background: cx.theme().colors().editor_background,
25936                local_player: cx.theme().players().local(),
25937                text: text_style,
25938                ..Default::default()
25939            },
25940        )
25941    }
25942}
25943
25944impl Render for BreakpointPromptEditor {
25945    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25946        let editor_margins = *self.editor_margins.lock();
25947        let gutter_dimensions = editor_margins.gutter;
25948        h_flex()
25949            .key_context("Editor")
25950            .bg(cx.theme().colors().editor_background)
25951            .border_y_1()
25952            .border_color(cx.theme().status().info_border)
25953            .size_full()
25954            .py(window.line_height() / 2.5)
25955            .on_action(cx.listener(Self::confirm))
25956            .on_action(cx.listener(Self::cancel))
25957            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25958            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25959    }
25960}
25961
25962impl Focusable for BreakpointPromptEditor {
25963    fn focus_handle(&self, cx: &App) -> FocusHandle {
25964        self.prompt.focus_handle(cx)
25965    }
25966}
25967
25968fn all_edits_insertions_or_deletions(
25969    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25970    snapshot: &MultiBufferSnapshot,
25971) -> bool {
25972    let mut all_insertions = true;
25973    let mut all_deletions = true;
25974
25975    for (range, new_text) in edits.iter() {
25976        let range_is_empty = range.to_offset(snapshot).is_empty();
25977        let text_is_empty = new_text.is_empty();
25978
25979        if range_is_empty != text_is_empty {
25980            if range_is_empty {
25981                all_deletions = false;
25982            } else {
25983                all_insertions = false;
25984            }
25985        } else {
25986            return false;
25987        }
25988
25989        if !all_insertions && !all_deletions {
25990            return false;
25991        }
25992    }
25993    all_insertions || all_deletions
25994}
25995
25996struct MissingEditPredictionKeybindingTooltip;
25997
25998impl Render for MissingEditPredictionKeybindingTooltip {
25999    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26000        ui::tooltip_container(cx, |container, cx| {
26001            container
26002                .flex_shrink_0()
26003                .max_w_80()
26004                .min_h(rems_from_px(124.))
26005                .justify_between()
26006                .child(
26007                    v_flex()
26008                        .flex_1()
26009                        .text_ui_sm(cx)
26010                        .child(Label::new("Conflict with Accept Keybinding"))
26011                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26012                )
26013                .child(
26014                    h_flex()
26015                        .pb_1()
26016                        .gap_1()
26017                        .items_end()
26018                        .w_full()
26019                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26020                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26021                        }))
26022                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26023                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26024                        })),
26025                )
26026        })
26027    }
26028}
26029
26030#[derive(Debug, Clone, Copy, PartialEq)]
26031pub struct LineHighlight {
26032    pub background: Background,
26033    pub border: Option<gpui::Hsla>,
26034    pub include_gutter: bool,
26035    pub type_id: Option<TypeId>,
26036}
26037
26038struct LineManipulationResult {
26039    pub new_text: String,
26040    pub line_count_before: usize,
26041    pub line_count_after: usize,
26042}
26043
26044fn render_diff_hunk_controls(
26045    row: u32,
26046    status: &DiffHunkStatus,
26047    hunk_range: Range<Anchor>,
26048    is_created_file: bool,
26049    line_height: Pixels,
26050    editor: &Entity<Editor>,
26051    _window: &mut Window,
26052    cx: &mut App,
26053) -> AnyElement {
26054    h_flex()
26055        .h(line_height)
26056        .mr_1()
26057        .gap_1()
26058        .px_0p5()
26059        .pb_1()
26060        .border_x_1()
26061        .border_b_1()
26062        .border_color(cx.theme().colors().border_variant)
26063        .rounded_b_lg()
26064        .bg(cx.theme().colors().editor_background)
26065        .gap_1()
26066        .block_mouse_except_scroll()
26067        .shadow_md()
26068        .child(if status.has_secondary_hunk() {
26069            Button::new(("stage", row as u64), "Stage")
26070                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26071                .tooltip({
26072                    let focus_handle = editor.focus_handle(cx);
26073                    move |_window, cx| {
26074                        Tooltip::for_action_in(
26075                            "Stage Hunk",
26076                            &::git::ToggleStaged,
26077                            &focus_handle,
26078                            cx,
26079                        )
26080                    }
26081                })
26082                .on_click({
26083                    let editor = editor.clone();
26084                    move |_event, _window, cx| {
26085                        editor.update(cx, |editor, cx| {
26086                            editor.stage_or_unstage_diff_hunks(
26087                                true,
26088                                vec![hunk_range.start..hunk_range.start],
26089                                cx,
26090                            );
26091                        });
26092                    }
26093                })
26094        } else {
26095            Button::new(("unstage", row as u64), "Unstage")
26096                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26097                .tooltip({
26098                    let focus_handle = editor.focus_handle(cx);
26099                    move |_window, cx| {
26100                        Tooltip::for_action_in(
26101                            "Unstage Hunk",
26102                            &::git::ToggleStaged,
26103                            &focus_handle,
26104                            cx,
26105                        )
26106                    }
26107                })
26108                .on_click({
26109                    let editor = editor.clone();
26110                    move |_event, _window, cx| {
26111                        editor.update(cx, |editor, cx| {
26112                            editor.stage_or_unstage_diff_hunks(
26113                                false,
26114                                vec![hunk_range.start..hunk_range.start],
26115                                cx,
26116                            );
26117                        });
26118                    }
26119                })
26120        })
26121        .child(
26122            Button::new(("restore", row as u64), "Restore")
26123                .tooltip({
26124                    let focus_handle = editor.focus_handle(cx);
26125                    move |_window, cx| {
26126                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26127                    }
26128                })
26129                .on_click({
26130                    let editor = editor.clone();
26131                    move |_event, window, cx| {
26132                        editor.update(cx, |editor, cx| {
26133                            let snapshot = editor.snapshot(window, cx);
26134                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26135                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26136                        });
26137                    }
26138                })
26139                .disabled(is_created_file),
26140        )
26141        .when(
26142            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26143            |el| {
26144                el.child(
26145                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26146                        .shape(IconButtonShape::Square)
26147                        .icon_size(IconSize::Small)
26148                        // .disabled(!has_multiple_hunks)
26149                        .tooltip({
26150                            let focus_handle = editor.focus_handle(cx);
26151                            move |_window, cx| {
26152                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26153                            }
26154                        })
26155                        .on_click({
26156                            let editor = editor.clone();
26157                            move |_event, window, cx| {
26158                                editor.update(cx, |editor, cx| {
26159                                    let snapshot = editor.snapshot(window, cx);
26160                                    let position =
26161                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26162                                    editor.go_to_hunk_before_or_after_position(
26163                                        &snapshot,
26164                                        position,
26165                                        Direction::Next,
26166                                        window,
26167                                        cx,
26168                                    );
26169                                    editor.expand_selected_diff_hunks(cx);
26170                                });
26171                            }
26172                        }),
26173                )
26174                .child(
26175                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26176                        .shape(IconButtonShape::Square)
26177                        .icon_size(IconSize::Small)
26178                        // .disabled(!has_multiple_hunks)
26179                        .tooltip({
26180                            let focus_handle = editor.focus_handle(cx);
26181                            move |_window, cx| {
26182                                Tooltip::for_action_in(
26183                                    "Previous Hunk",
26184                                    &GoToPreviousHunk,
26185                                    &focus_handle,
26186                                    cx,
26187                                )
26188                            }
26189                        })
26190                        .on_click({
26191                            let editor = editor.clone();
26192                            move |_event, window, cx| {
26193                                editor.update(cx, |editor, cx| {
26194                                    let snapshot = editor.snapshot(window, cx);
26195                                    let point =
26196                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26197                                    editor.go_to_hunk_before_or_after_position(
26198                                        &snapshot,
26199                                        point,
26200                                        Direction::Prev,
26201                                        window,
26202                                        cx,
26203                                    );
26204                                    editor.expand_selected_diff_hunks(cx);
26205                                });
26206                            }
26207                        }),
26208                )
26209            },
26210        )
26211        .into_any_element()
26212}
26213
26214pub fn multibuffer_context_lines(cx: &App) -> u32 {
26215    EditorSettings::try_get(cx)
26216        .map(|settings| settings.excerpt_context_lines)
26217        .unwrap_or(2)
26218        .min(32)
26219}