editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction_types::Direction;
   55pub use editor_settings::{
   56    CompletionDetailAlignment, CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings,
   57    HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61    render_breadcrumb_text,
   62};
   63pub use git::blame::BlameRenderer;
   64pub use hover_popover::hover_markdown_style;
   65pub use inlays::Inlay;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   71    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   72    ToPoint,
   73};
   74pub use split::SplittableEditor;
   75pub use text::Bias;
   76
   77use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   78use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   79use anyhow::{Context as _, Result, anyhow, bail};
   80use blink_manager::BlinkManager;
   81use buffer_diff::DiffHunkStatus;
   82use client::{Collaborator, ParticipantIndex, parse_zed_link};
   83use clock::ReplicaId;
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   89use convert_case::{Case, Casing};
   90use dap::TelemetrySpawnLocation;
   91use display_map::*;
   92use edit_prediction_types::{
   93    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   94    SuggestionDisplayType,
   95};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  111    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  112    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  113    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  114    size,
  115};
  116use hover_links::{HoverLink, HoveredLinkState, find_file};
  117use hover_popover::{HoverState, hide_hover};
  118use indent_guides::ActiveIndentGuidesState;
  119use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  120use itertools::{Either, Itertools};
  121use language::{
  122    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  123    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  124    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  125    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  126    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  127    TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145};
  146use parking_lot::Mutex;
  147use persistence::DB;
  148use project::{
  149    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  150    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  151    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  152    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::{
  154        breakpoint_store::{
  155            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  156            BreakpointStore, BreakpointStoreEvent,
  157        },
  158        session::{Session, SessionEvent},
  159    },
  160    git_store::GitStoreEvent,
  161    lsp_store::{
  162        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  163        OpenLspBufferHandle,
  164    },
  165    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  166};
  167use rand::seq::SliceRandom;
  168use regex::Regex;
  169use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  170use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  171use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  172use serde::{Deserialize, Serialize};
  173use settings::{
  174    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  175    update_settings_file,
  176};
  177use smallvec::{SmallVec, smallvec};
  178use snippet::Snippet;
  179use std::{
  180    any::{Any, TypeId},
  181    borrow::Cow,
  182    cell::{OnceCell, RefCell},
  183    cmp::{self, Ordering, Reverse},
  184    collections::hash_map,
  185    iter::{self, Peekable},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    sync::Arc,
  192    time::{Duration, Instant},
  193};
  194use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  196use theme::{
  197    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    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::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::{CollapseDirection, SearchEvent},
  212};
  213
  214use crate::{
  215    code_context_menus::CompletionsMenuSource,
  216    editor_settings::MultiCursorModifier,
  217    hover_links::{find_url, find_url_from_range},
  218    inlays::{
  219        InlineValueCache,
  220        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  221    },
  222    scroll::{ScrollOffset, ScrollPixelOffset},
  223    selections_collection::resolve_selections_wrapping_blocks,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260enum ReportEditorEvent {
  261    Saved { auto_saved: bool },
  262    EditorOpened,
  263    Closed,
  264}
  265
  266impl ReportEditorEvent {
  267    pub fn event_type(&self) -> &'static str {
  268        match self {
  269            Self::Saved { .. } => "Editor Saved",
  270            Self::EditorOpened => "Editor Opened",
  271            Self::Closed => "Editor Closed",
  272        }
  273    }
  274}
  275
  276pub enum ActiveDebugLine {}
  277pub enum DebugStackFrameLine {}
  278enum DocumentHighlightRead {}
  279enum DocumentHighlightWrite {}
  280enum InputComposition {}
  281pub enum PendingInput {}
  282enum SelectedTextHighlight {}
  283
  284pub enum ConflictsOuter {}
  285pub enum ConflictsOurs {}
  286pub enum ConflictsTheirs {}
  287pub enum ConflictsOursMarker {}
  288pub enum ConflictsTheirsMarker {}
  289
  290pub struct HunkAddedColor;
  291pub struct HunkRemovedColor;
  292
  293#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  294pub enum Navigated {
  295    Yes,
  296    No,
  297}
  298
  299impl Navigated {
  300    pub fn from_bool(yes: bool) -> Navigated {
  301        if yes { Navigated::Yes } else { Navigated::No }
  302    }
  303}
  304
  305#[derive(Debug, Clone, PartialEq, Eq)]
  306enum DisplayDiffHunk {
  307    Folded {
  308        display_row: DisplayRow,
  309    },
  310    Unfolded {
  311        is_created_file: bool,
  312        diff_base_byte_range: Range<usize>,
  313        display_row_range: Range<DisplayRow>,
  314        multi_buffer_range: Range<Anchor>,
  315        status: DiffHunkStatus,
  316        word_diffs: Vec<Range<MultiBufferOffset>>,
  317    },
  318}
  319
  320pub enum HideMouseCursorOrigin {
  321    TypingAction,
  322    MovementAction,
  323}
  324
  325pub fn init(cx: &mut App) {
  326    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  327
  328    workspace::register_project_item::<Editor>(cx);
  329    workspace::FollowableViewRegistry::register::<Editor>(cx);
  330    workspace::register_serializable_item::<Editor>(cx);
  331
  332    cx.observe_new(
  333        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  334            workspace.register_action(Editor::new_file);
  335            workspace.register_action(Editor::new_file_split);
  336            workspace.register_action(Editor::new_file_vertical);
  337            workspace.register_action(Editor::new_file_horizontal);
  338            workspace.register_action(Editor::cancel_language_server_work);
  339            workspace.register_action(Editor::toggle_focus);
  340        },
  341    )
  342    .detach();
  343
  344    cx.on_action(move |_: &workspace::NewFile, cx| {
  345        let app_state = workspace::AppState::global(cx);
  346        if let Some(app_state) = app_state.upgrade() {
  347            workspace::open_new(
  348                Default::default(),
  349                app_state,
  350                cx,
  351                |workspace, window, cx| {
  352                    Editor::new_file(workspace, &Default::default(), window, cx)
  353                },
  354            )
  355            .detach();
  356        }
  357    })
  358    .on_action(move |_: &workspace::NewWindow, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    cx.activate(true);
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373}
  374
  375pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  376    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  377}
  378
  379pub trait DiagnosticRenderer {
  380    fn render_group(
  381        &self,
  382        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  383        buffer_id: BufferId,
  384        snapshot: EditorSnapshot,
  385        editor: WeakEntity<Editor>,
  386        language_registry: Option<Arc<LanguageRegistry>>,
  387        cx: &mut App,
  388    ) -> Vec<BlockProperties<Anchor>>;
  389
  390    fn render_hover(
  391        &self,
  392        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  393        range: Range<Point>,
  394        buffer_id: BufferId,
  395        language_registry: Option<Arc<LanguageRegistry>>,
  396        cx: &mut App,
  397    ) -> Option<Entity<markdown::Markdown>>;
  398
  399    fn open_link(
  400        &self,
  401        editor: &mut Editor,
  402        link: SharedString,
  403        window: &mut Window,
  404        cx: &mut Context<Editor>,
  405    );
  406}
  407
  408pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  409
  410impl GlobalDiagnosticRenderer {
  411    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  412        cx.try_global::<Self>().map(|g| g.0.clone())
  413    }
  414}
  415
  416impl gpui::Global for GlobalDiagnosticRenderer {}
  417pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  418    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  419}
  420
  421pub struct SearchWithinRange;
  422
  423trait InvalidationRegion {
  424    fn ranges(&self) -> &[Range<Anchor>];
  425}
  426
  427#[derive(Clone, Debug, PartialEq)]
  428pub enum SelectPhase {
  429    Begin {
  430        position: DisplayPoint,
  431        add: bool,
  432        click_count: usize,
  433    },
  434    BeginColumnar {
  435        position: DisplayPoint,
  436        reset: bool,
  437        mode: ColumnarMode,
  438        goal_column: u32,
  439    },
  440    Extend {
  441        position: DisplayPoint,
  442        click_count: usize,
  443    },
  444    Update {
  445        position: DisplayPoint,
  446        goal_column: u32,
  447        scroll_delta: gpui::Point<f32>,
  448    },
  449    End,
  450}
  451
  452#[derive(Clone, Debug, PartialEq)]
  453pub enum ColumnarMode {
  454    FromMouse,
  455    FromSelection,
  456}
  457
  458#[derive(Clone, Debug)]
  459pub enum SelectMode {
  460    Character,
  461    Word(Range<Anchor>),
  462    Line(Range<Anchor>),
  463    All,
  464}
  465
  466#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  467pub enum SizingBehavior {
  468    /// The editor will layout itself using `size_full` and will include the vertical
  469    /// scroll margin as requested by user settings.
  470    #[default]
  471    Default,
  472    /// The editor will layout itself using `size_full`, but will not have any
  473    /// vertical overscroll.
  474    ExcludeOverscrollMargin,
  475    /// The editor will request a vertical size according to its content and will be
  476    /// layouted without a vertical scroll margin.
  477    SizeByContent,
  478}
  479
  480#[derive(Clone, PartialEq, Eq, Debug)]
  481pub enum EditorMode {
  482    SingleLine,
  483    AutoHeight {
  484        min_lines: usize,
  485        max_lines: Option<usize>,
  486    },
  487    Full {
  488        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  489        scale_ui_elements_with_buffer_font_size: bool,
  490        /// When set to `true`, the editor will render a background for the active line.
  491        show_active_line_background: bool,
  492        /// Determines the sizing behavior for this editor
  493        sizing_behavior: SizingBehavior,
  494    },
  495    Minimap {
  496        parent: WeakEntity<Editor>,
  497    },
  498}
  499
  500impl EditorMode {
  501    pub fn full() -> Self {
  502        Self::Full {
  503            scale_ui_elements_with_buffer_font_size: true,
  504            show_active_line_background: true,
  505            sizing_behavior: SizingBehavior::Default,
  506        }
  507    }
  508
  509    #[inline]
  510    pub fn is_full(&self) -> bool {
  511        matches!(self, Self::Full { .. })
  512    }
  513
  514    #[inline]
  515    pub fn is_single_line(&self) -> bool {
  516        matches!(self, Self::SingleLine { .. })
  517    }
  518
  519    #[inline]
  520    fn is_minimap(&self) -> bool {
  521        matches!(self, Self::Minimap { .. })
  522    }
  523}
  524
  525#[derive(Copy, Clone, Debug)]
  526pub enum SoftWrap {
  527    /// Prefer not to wrap at all.
  528    ///
  529    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  530    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  531    GitDiff,
  532    /// Prefer a single line generally, unless an overly long line is encountered.
  533    None,
  534    /// Soft wrap lines that exceed the editor width.
  535    EditorWidth,
  536    /// Soft wrap lines at the preferred line length.
  537    Column(u32),
  538    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  539    Bounded(u32),
  540}
  541
  542#[derive(Clone)]
  543pub struct EditorStyle {
  544    pub background: Hsla,
  545    pub border: Hsla,
  546    pub local_player: PlayerColor,
  547    pub text: TextStyle,
  548    pub scrollbar_width: Pixels,
  549    pub syntax: Arc<SyntaxTheme>,
  550    pub status: StatusColors,
  551    pub inlay_hints_style: HighlightStyle,
  552    pub edit_prediction_styles: EditPredictionStyles,
  553    pub unnecessary_code_fade: f32,
  554    pub show_underlines: bool,
  555}
  556
  557impl Default for EditorStyle {
  558    fn default() -> Self {
  559        Self {
  560            background: Hsla::default(),
  561            border: Hsla::default(),
  562            local_player: PlayerColor::default(),
  563            text: TextStyle::default(),
  564            scrollbar_width: Pixels::default(),
  565            syntax: Default::default(),
  566            // HACK: Status colors don't have a real default.
  567            // We should look into removing the status colors from the editor
  568            // style and retrieve them directly from the theme.
  569            status: StatusColors::dark(),
  570            inlay_hints_style: HighlightStyle::default(),
  571            edit_prediction_styles: EditPredictionStyles {
  572                insertion: HighlightStyle::default(),
  573                whitespace: HighlightStyle::default(),
  574            },
  575            unnecessary_code_fade: Default::default(),
  576            show_underlines: true,
  577        }
  578    }
  579}
  580
  581pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  582    let show_background = language_settings::language_settings(None, None, cx)
  583        .inlay_hints
  584        .show_background;
  585
  586    let mut style = cx.theme().syntax().get("hint");
  587
  588    if style.color.is_none() {
  589        style.color = Some(cx.theme().status().hint);
  590    }
  591
  592    if !show_background {
  593        style.background_color = None;
  594        return style;
  595    }
  596
  597    if style.background_color.is_none() {
  598        style.background_color = Some(cx.theme().status().hint_background);
  599    }
  600
  601    style
  602}
  603
  604pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  605    EditPredictionStyles {
  606        insertion: HighlightStyle {
  607            color: Some(cx.theme().status().predictive),
  608            ..HighlightStyle::default()
  609        },
  610        whitespace: HighlightStyle {
  611            background_color: Some(cx.theme().status().created_background),
  612            ..HighlightStyle::default()
  613        },
  614    }
  615}
  616
  617type CompletionId = usize;
  618
  619pub(crate) enum EditDisplayMode {
  620    TabAccept,
  621    DiffPopover,
  622    Inline,
  623}
  624
  625enum EditPrediction {
  626    Edit {
  627        edits: Vec<(Range<Anchor>, Arc<str>)>,
  628        edit_preview: Option<EditPreview>,
  629        display_mode: EditDisplayMode,
  630        snapshot: BufferSnapshot,
  631    },
  632    /// Move to a specific location in the active editor
  633    MoveWithin {
  634        target: Anchor,
  635        snapshot: BufferSnapshot,
  636    },
  637    /// Move to a specific location in a different editor (not the active one)
  638    MoveOutside {
  639        target: language::Anchor,
  640        snapshot: BufferSnapshot,
  641    },
  642}
  643
  644struct EditPredictionState {
  645    inlay_ids: Vec<InlayId>,
  646    completion: EditPrediction,
  647    completion_id: Option<SharedString>,
  648    invalidation_range: Option<Range<Anchor>>,
  649}
  650
  651enum EditPredictionSettings {
  652    Disabled,
  653    Enabled {
  654        show_in_menu: bool,
  655        preview_requires_modifier: bool,
  656    },
  657}
  658
  659enum EditPredictionHighlight {}
  660
  661#[derive(Debug, Clone)]
  662struct InlineDiagnostic {
  663    message: SharedString,
  664    group_id: usize,
  665    is_primary: bool,
  666    start: Point,
  667    severity: lsp::DiagnosticSeverity,
  668}
  669
  670pub enum MenuEditPredictionsPolicy {
  671    Never,
  672    ByProvider,
  673}
  674
  675pub enum EditPredictionPreview {
  676    /// Modifier is not pressed
  677    Inactive { released_too_fast: bool },
  678    /// Modifier pressed
  679    Active {
  680        since: Instant,
  681        previous_scroll_position: Option<ScrollAnchor>,
  682    },
  683}
  684
  685impl EditPredictionPreview {
  686    pub fn released_too_fast(&self) -> bool {
  687        match self {
  688            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  689            EditPredictionPreview::Active { .. } => false,
  690        }
  691    }
  692
  693    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  694        if let EditPredictionPreview::Active {
  695            previous_scroll_position,
  696            ..
  697        } = self
  698        {
  699            *previous_scroll_position = scroll_position;
  700        }
  701    }
  702}
  703
  704pub struct ContextMenuOptions {
  705    pub min_entries_visible: usize,
  706    pub max_entries_visible: usize,
  707    pub placement: Option<ContextMenuPlacement>,
  708}
  709
  710#[derive(Debug, Clone, PartialEq, Eq)]
  711pub enum ContextMenuPlacement {
  712    Above,
  713    Below,
  714}
  715
  716#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  717struct EditorActionId(usize);
  718
  719impl EditorActionId {
  720    pub fn post_inc(&mut self) -> Self {
  721        let answer = self.0;
  722
  723        *self = Self(answer + 1);
  724
  725        Self(answer)
  726    }
  727}
  728
  729// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  730// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  731
  732type BackgroundHighlight = (
  733    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  734    Arc<[Range<Anchor>]>,
  735);
  736type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  737
  738#[derive(Default)]
  739struct ScrollbarMarkerState {
  740    scrollbar_size: Size<Pixels>,
  741    dirty: bool,
  742    markers: Arc<[PaintQuad]>,
  743    pending_refresh: Option<Task<Result<()>>>,
  744}
  745
  746impl ScrollbarMarkerState {
  747    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  748        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  749    }
  750}
  751
  752#[derive(Clone, Copy, PartialEq, Eq)]
  753pub enum MinimapVisibility {
  754    Disabled,
  755    Enabled {
  756        /// The configuration currently present in the users settings.
  757        setting_configuration: bool,
  758        /// Whether to override the currently set visibility from the users setting.
  759        toggle_override: bool,
  760    },
  761}
  762
  763impl MinimapVisibility {
  764    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  765        if mode.is_full() {
  766            Self::Enabled {
  767                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  768                toggle_override: false,
  769            }
  770        } else {
  771            Self::Disabled
  772        }
  773    }
  774
  775    fn hidden(&self) -> Self {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => Self::Enabled {
  781                setting_configuration,
  782                toggle_override: setting_configuration,
  783            },
  784            Self::Disabled => Self::Disabled,
  785        }
  786    }
  787
  788    fn disabled(&self) -> bool {
  789        matches!(*self, Self::Disabled)
  790    }
  791
  792    fn settings_visibility(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                ..
  797            } => setting_configuration,
  798            _ => false,
  799        }
  800    }
  801
  802    fn visible(&self) -> bool {
  803        match *self {
  804            Self::Enabled {
  805                setting_configuration,
  806                toggle_override,
  807            } => setting_configuration ^ toggle_override,
  808            _ => false,
  809        }
  810    }
  811
  812    fn toggle_visibility(&self) -> Self {
  813        match *self {
  814            Self::Enabled {
  815                toggle_override,
  816                setting_configuration,
  817            } => Self::Enabled {
  818                setting_configuration,
  819                toggle_override: !toggle_override,
  820            },
  821            Self::Disabled => Self::Disabled,
  822        }
  823    }
  824}
  825
  826#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  827pub enum BufferSerialization {
  828    All,
  829    NonDirtyBuffers,
  830}
  831
  832impl BufferSerialization {
  833    fn new(restore_unsaved_buffers: bool) -> Self {
  834        if restore_unsaved_buffers {
  835            Self::All
  836        } else {
  837            Self::NonDirtyBuffers
  838        }
  839    }
  840}
  841
  842#[derive(Clone, Debug)]
  843struct RunnableTasks {
  844    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  845    offset: multi_buffer::Anchor,
  846    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  847    column: u32,
  848    // Values of all named captures, including those starting with '_'
  849    extra_variables: HashMap<String, String>,
  850    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  851    context_range: Range<BufferOffset>,
  852}
  853
  854impl RunnableTasks {
  855    fn resolve<'a>(
  856        &'a self,
  857        cx: &'a task::TaskContext,
  858    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  859        self.templates.iter().filter_map(|(kind, template)| {
  860            template
  861                .resolve_task(&kind.to_id_base(), cx)
  862                .map(|task| (kind.clone(), task))
  863        })
  864    }
  865}
  866
  867#[derive(Clone)]
  868pub struct ResolvedTasks {
  869    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  870    position: Anchor,
  871}
  872
  873/// Addons allow storing per-editor state in other crates (e.g. Vim)
  874pub trait Addon: 'static {
  875    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  876
  877    fn render_buffer_header_controls(
  878        &self,
  879        _: &ExcerptInfo,
  880        _: &Window,
  881        _: &App,
  882    ) -> Option<AnyElement> {
  883        None
  884    }
  885
  886    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  887        None
  888    }
  889
  890    fn to_any(&self) -> &dyn std::any::Any;
  891
  892    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  893        None
  894    }
  895}
  896
  897struct ChangeLocation {
  898    current: Option<Vec<Anchor>>,
  899    original: Vec<Anchor>,
  900}
  901impl ChangeLocation {
  902    fn locations(&self) -> &[Anchor] {
  903        self.current.as_ref().unwrap_or(&self.original)
  904    }
  905}
  906
  907/// A set of caret positions, registered when the editor was edited.
  908pub struct ChangeList {
  909    changes: Vec<ChangeLocation>,
  910    /// Currently "selected" change.
  911    position: Option<usize>,
  912}
  913
  914impl ChangeList {
  915    pub fn new() -> Self {
  916        Self {
  917            changes: Vec::new(),
  918            position: None,
  919        }
  920    }
  921
  922    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  923    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  924    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  925        if self.changes.is_empty() {
  926            return None;
  927        }
  928
  929        let prev = self.position.unwrap_or(self.changes.len());
  930        let next = if direction == Direction::Prev {
  931            prev.saturating_sub(count)
  932        } else {
  933            (prev + count).min(self.changes.len() - 1)
  934        };
  935        self.position = Some(next);
  936        self.changes.get(next).map(|change| change.locations())
  937    }
  938
  939    /// Adds a new change to the list, resetting the change list position.
  940    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  941        self.position.take();
  942        if let Some(last) = self.changes.last_mut()
  943            && group
  944        {
  945            last.current = Some(new_positions)
  946        } else {
  947            self.changes.push(ChangeLocation {
  948                original: new_positions,
  949                current: None,
  950            });
  951        }
  952    }
  953
  954    pub fn last(&self) -> Option<&[Anchor]> {
  955        self.changes.last().map(|change| change.locations())
  956    }
  957
  958    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  959        self.changes.last().map(|change| change.original.as_slice())
  960    }
  961
  962    pub fn invert_last_group(&mut self) {
  963        if let Some(last) = self.changes.last_mut()
  964            && let Some(current) = last.current.as_mut()
  965        {
  966            mem::swap(&mut last.original, current);
  967        }
  968    }
  969}
  970
  971#[derive(Clone)]
  972struct InlineBlamePopoverState {
  973    scroll_handle: ScrollHandle,
  974    commit_message: Option<ParsedCommitMessage>,
  975    markdown: Entity<Markdown>,
  976}
  977
  978struct InlineBlamePopover {
  979    position: gpui::Point<Pixels>,
  980    hide_task: Option<Task<()>>,
  981    popover_bounds: Option<Bounds<Pixels>>,
  982    popover_state: InlineBlamePopoverState,
  983    keyboard_grace: bool,
  984}
  985
  986enum SelectionDragState {
  987    /// State when no drag related activity is detected.
  988    None,
  989    /// State when the mouse is down on a selection that is about to be dragged.
  990    ReadyToDrag {
  991        selection: Selection<Anchor>,
  992        click_position: gpui::Point<Pixels>,
  993        mouse_down_time: Instant,
  994    },
  995    /// State when the mouse is dragging the selection in the editor.
  996    Dragging {
  997        selection: Selection<Anchor>,
  998        drop_cursor: Selection<Anchor>,
  999        hide_drop_cursor: bool,
 1000    },
 1001}
 1002
 1003enum ColumnarSelectionState {
 1004    FromMouse {
 1005        selection_tail: Anchor,
 1006        display_point: Option<DisplayPoint>,
 1007    },
 1008    FromSelection {
 1009        selection_tail: Anchor,
 1010    },
 1011}
 1012
 1013/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1014/// a breakpoint on them.
 1015#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1016struct PhantomBreakpointIndicator {
 1017    display_row: DisplayRow,
 1018    /// There's a small debounce between hovering over the line and showing the indicator.
 1019    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1020    is_active: bool,
 1021    collides_with_existing_breakpoint: bool,
 1022}
 1023
 1024/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1025/// in diff view mode.
 1026#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1027pub(crate) struct PhantomDiffReviewIndicator {
 1028    pub display_row: DisplayRow,
 1029    /// There's a small debounce between hovering over the line and showing the indicator.
 1030    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1031    pub is_active: bool,
 1032}
 1033
 1034/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1035///
 1036/// See the [module level documentation](self) for more information.
 1037pub struct Editor {
 1038    focus_handle: FocusHandle,
 1039    last_focused_descendant: Option<WeakFocusHandle>,
 1040    /// The text buffer being edited
 1041    buffer: Entity<MultiBuffer>,
 1042    /// Map of how text in the buffer should be displayed.
 1043    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1044    pub display_map: Entity<DisplayMap>,
 1045    placeholder_display_map: Option<Entity<DisplayMap>>,
 1046    pub selections: SelectionsCollection,
 1047    pub scroll_manager: ScrollManager,
 1048    /// When inline assist editors are linked, they all render cursors because
 1049    /// typing enters text into each of them, even the ones that aren't focused.
 1050    pub(crate) show_cursor_when_unfocused: bool,
 1051    columnar_selection_state: Option<ColumnarSelectionState>,
 1052    add_selections_state: Option<AddSelectionsState>,
 1053    select_next_state: Option<SelectNextState>,
 1054    select_prev_state: Option<SelectNextState>,
 1055    selection_history: SelectionHistory,
 1056    defer_selection_effects: bool,
 1057    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1058    autoclose_regions: Vec<AutocloseRegion>,
 1059    snippet_stack: InvalidationStack<SnippetState>,
 1060    select_syntax_node_history: SelectSyntaxNodeHistory,
 1061    ime_transaction: Option<TransactionId>,
 1062    pub diagnostics_max_severity: DiagnosticSeverity,
 1063    active_diagnostics: ActiveDiagnostic,
 1064    show_inline_diagnostics: bool,
 1065    inline_diagnostics_update: Task<()>,
 1066    inline_diagnostics_enabled: bool,
 1067    diagnostics_enabled: bool,
 1068    word_completions_enabled: bool,
 1069    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1070    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1071    hard_wrap: Option<usize>,
 1072    project: Option<Entity<Project>>,
 1073    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1074    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1075    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1076    blink_manager: Entity<BlinkManager>,
 1077    show_cursor_names: bool,
 1078    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1079    pub show_local_selections: bool,
 1080    mode: EditorMode,
 1081    show_breadcrumbs: bool,
 1082    show_gutter: bool,
 1083    show_scrollbars: ScrollbarAxes,
 1084    minimap_visibility: MinimapVisibility,
 1085    offset_content: bool,
 1086    disable_expand_excerpt_buttons: bool,
 1087    delegate_expand_excerpts: bool,
 1088    show_line_numbers: Option<bool>,
 1089    use_relative_line_numbers: Option<bool>,
 1090    show_git_diff_gutter: Option<bool>,
 1091    show_code_actions: Option<bool>,
 1092    show_runnables: Option<bool>,
 1093    show_breakpoints: Option<bool>,
 1094    show_diff_review_button: bool,
 1095    show_wrap_guides: Option<bool>,
 1096    show_indent_guides: Option<bool>,
 1097    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1098    highlight_order: usize,
 1099    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1100    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1101    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1102    scrollbar_marker_state: ScrollbarMarkerState,
 1103    active_indent_guides_state: ActiveIndentGuidesState,
 1104    nav_history: Option<ItemNavHistory>,
 1105    context_menu: RefCell<Option<CodeContextMenu>>,
 1106    context_menu_options: Option<ContextMenuOptions>,
 1107    mouse_context_menu: Option<MouseContextMenu>,
 1108    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1109    inline_blame_popover: Option<InlineBlamePopover>,
 1110    inline_blame_popover_show_task: Option<Task<()>>,
 1111    signature_help_state: SignatureHelpState,
 1112    auto_signature_help: Option<bool>,
 1113    find_all_references_task_sources: Vec<Anchor>,
 1114    next_completion_id: CompletionId,
 1115    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1116    code_actions_task: Option<Task<Result<()>>>,
 1117    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1118    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1119    document_highlights_task: Option<Task<()>>,
 1120    linked_editing_range_task: Option<Task<Option<()>>>,
 1121    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1122    pending_rename: Option<RenameState>,
 1123    searchable: bool,
 1124    cursor_shape: CursorShape,
 1125    /// Whether the cursor is offset one character to the left when something is
 1126    /// selected (needed for vim visual mode)
 1127    cursor_offset_on_selection: bool,
 1128    current_line_highlight: Option<CurrentLineHighlight>,
 1129    pub collapse_matches: bool,
 1130    autoindent_mode: Option<AutoindentMode>,
 1131    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1132    input_enabled: bool,
 1133    use_modal_editing: bool,
 1134    read_only: bool,
 1135    leader_id: Option<CollaboratorId>,
 1136    remote_id: Option<ViewId>,
 1137    pub hover_state: HoverState,
 1138    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1139    prev_pressure_stage: Option<PressureStage>,
 1140    gutter_hovered: bool,
 1141    hovered_link_state: Option<HoveredLinkState>,
 1142    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1143    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1144    active_edit_prediction: Option<EditPredictionState>,
 1145    /// Used to prevent flickering as the user types while the menu is open
 1146    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1147    edit_prediction_settings: EditPredictionSettings,
 1148    edit_predictions_hidden_for_vim_mode: bool,
 1149    show_edit_predictions_override: Option<bool>,
 1150    show_completions_on_input_override: Option<bool>,
 1151    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1152    edit_prediction_preview: EditPredictionPreview,
 1153    edit_prediction_indent_conflict: bool,
 1154    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1155    next_inlay_id: usize,
 1156    next_color_inlay_id: usize,
 1157    _subscriptions: Vec<Subscription>,
 1158    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1159    gutter_dimensions: GutterDimensions,
 1160    style: Option<EditorStyle>,
 1161    text_style_refinement: Option<TextStyleRefinement>,
 1162    next_editor_action_id: EditorActionId,
 1163    editor_actions: Rc<
 1164        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1165    >,
 1166    use_autoclose: bool,
 1167    use_auto_surround: bool,
 1168    auto_replace_emoji_shortcode: bool,
 1169    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1170    show_git_blame_gutter: bool,
 1171    show_git_blame_inline: bool,
 1172    show_git_blame_inline_delay_task: Option<Task<()>>,
 1173    git_blame_inline_enabled: bool,
 1174    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1175    buffer_serialization: Option<BufferSerialization>,
 1176    show_selection_menu: Option<bool>,
 1177    blame: Option<Entity<GitBlame>>,
 1178    blame_subscription: Option<Subscription>,
 1179    custom_context_menu: Option<
 1180        Box<
 1181            dyn 'static
 1182                + Fn(
 1183                    &mut Self,
 1184                    DisplayPoint,
 1185                    &mut Window,
 1186                    &mut Context<Self>,
 1187                ) -> Option<Entity<ui::ContextMenu>>,
 1188        >,
 1189    >,
 1190    last_bounds: Option<Bounds<Pixels>>,
 1191    last_position_map: Option<Rc<PositionMap>>,
 1192    expect_bounds_change: Option<Bounds<Pixels>>,
 1193    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1194    tasks_update_task: Option<Task<()>>,
 1195    breakpoint_store: Option<Entity<BreakpointStore>>,
 1196    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1197    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1198    hovered_diff_hunk_row: Option<DisplayRow>,
 1199    pull_diagnostics_task: Task<()>,
 1200    pull_diagnostics_background_task: Task<()>,
 1201    in_project_search: bool,
 1202    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1203    breadcrumb_header: Option<String>,
 1204    focused_block: Option<FocusedBlock>,
 1205    next_scroll_position: NextScrollCursorCenterTopBottom,
 1206    addons: HashMap<TypeId, Box<dyn Addon>>,
 1207    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1208    load_diff_task: Option<Shared<Task<()>>>,
 1209    /// Whether we are temporarily displaying a diff other than git's
 1210    temporary_diff_override: bool,
 1211    selection_mark_mode: bool,
 1212    toggle_fold_multiple_buffers: Task<()>,
 1213    _scroll_cursor_center_top_bottom_task: Task<()>,
 1214    serialize_selections: Task<()>,
 1215    serialize_folds: Task<()>,
 1216    mouse_cursor_hidden: bool,
 1217    minimap: Option<Entity<Self>>,
 1218    hide_mouse_mode: HideMouseMode,
 1219    pub change_list: ChangeList,
 1220    inline_value_cache: InlineValueCache,
 1221    number_deleted_lines: bool,
 1222
 1223    selection_drag_state: SelectionDragState,
 1224    colors: Option<LspColorData>,
 1225    post_scroll_update: Task<()>,
 1226    refresh_colors_task: Task<()>,
 1227    inlay_hints: Option<LspInlayHintData>,
 1228    folding_newlines: Task<()>,
 1229    select_next_is_case_sensitive: Option<bool>,
 1230    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1231    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1232    accent_data: Option<AccentData>,
 1233    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1234}
 1235
 1236#[derive(Debug, PartialEq)]
 1237struct AccentData {
 1238    colors: AccentColors,
 1239    overrides: Vec<SharedString>,
 1240}
 1241
 1242fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1243    if debounce_ms > 0 {
 1244        Some(Duration::from_millis(debounce_ms))
 1245    } else {
 1246        None
 1247    }
 1248}
 1249
 1250#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1251enum NextScrollCursorCenterTopBottom {
 1252    #[default]
 1253    Center,
 1254    Top,
 1255    Bottom,
 1256}
 1257
 1258impl NextScrollCursorCenterTopBottom {
 1259    fn next(&self) -> Self {
 1260        match self {
 1261            Self::Center => Self::Top,
 1262            Self::Top => Self::Bottom,
 1263            Self::Bottom => Self::Center,
 1264        }
 1265    }
 1266}
 1267
 1268#[derive(Clone)]
 1269pub struct EditorSnapshot {
 1270    pub mode: EditorMode,
 1271    show_gutter: bool,
 1272    offset_content: bool,
 1273    show_line_numbers: Option<bool>,
 1274    number_deleted_lines: bool,
 1275    show_git_diff_gutter: Option<bool>,
 1276    show_code_actions: Option<bool>,
 1277    show_runnables: Option<bool>,
 1278    show_breakpoints: Option<bool>,
 1279    git_blame_gutter_max_author_length: Option<usize>,
 1280    pub display_snapshot: DisplaySnapshot,
 1281    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1282    is_focused: bool,
 1283    scroll_anchor: ScrollAnchor,
 1284    ongoing_scroll: OngoingScroll,
 1285    current_line_highlight: CurrentLineHighlight,
 1286    gutter_hovered: bool,
 1287}
 1288
 1289#[derive(Default, Debug, Clone, Copy)]
 1290pub struct GutterDimensions {
 1291    pub left_padding: Pixels,
 1292    pub right_padding: Pixels,
 1293    pub width: Pixels,
 1294    pub margin: Pixels,
 1295    pub git_blame_entries_width: Option<Pixels>,
 1296}
 1297
 1298impl GutterDimensions {
 1299    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1300        Self {
 1301            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1302            ..Default::default()
 1303        }
 1304    }
 1305
 1306    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1307        -cx.text_system().descent(font_id, font_size)
 1308    }
 1309    /// The full width of the space taken up by the gutter.
 1310    pub fn full_width(&self) -> Pixels {
 1311        self.margin + self.width
 1312    }
 1313
 1314    /// The width of the space reserved for the fold indicators,
 1315    /// use alongside 'justify_end' and `gutter_width` to
 1316    /// right align content with the line numbers
 1317    pub fn fold_area_width(&self) -> Pixels {
 1318        self.margin + self.right_padding
 1319    }
 1320}
 1321
 1322struct CharacterDimensions {
 1323    em_width: Pixels,
 1324    em_advance: Pixels,
 1325    line_height: Pixels,
 1326}
 1327
 1328#[derive(Debug)]
 1329pub struct RemoteSelection {
 1330    pub replica_id: ReplicaId,
 1331    pub selection: Selection<Anchor>,
 1332    pub cursor_shape: CursorShape,
 1333    pub collaborator_id: CollaboratorId,
 1334    pub line_mode: bool,
 1335    pub user_name: Option<SharedString>,
 1336    pub color: PlayerColor,
 1337}
 1338
 1339#[derive(Clone, Debug)]
 1340struct SelectionHistoryEntry {
 1341    selections: Arc<[Selection<Anchor>]>,
 1342    select_next_state: Option<SelectNextState>,
 1343    select_prev_state: Option<SelectNextState>,
 1344    add_selections_state: Option<AddSelectionsState>,
 1345}
 1346
 1347#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1348enum SelectionHistoryMode {
 1349    #[default]
 1350    Normal,
 1351    Undoing,
 1352    Redoing,
 1353    Skipping,
 1354}
 1355
 1356#[derive(Clone, PartialEq, Eq, Hash)]
 1357struct HoveredCursor {
 1358    replica_id: ReplicaId,
 1359    selection_id: usize,
 1360}
 1361
 1362#[derive(Debug)]
 1363/// SelectionEffects controls the side-effects of updating the selection.
 1364///
 1365/// The default behaviour does "what you mostly want":
 1366/// - it pushes to the nav history if the cursor moved by >10 lines
 1367/// - it re-triggers completion requests
 1368/// - it scrolls to fit
 1369///
 1370/// You might want to modify these behaviours. For example when doing a "jump"
 1371/// like go to definition, we always want to add to nav history; but when scrolling
 1372/// in vim mode we never do.
 1373///
 1374/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1375/// move.
 1376#[derive(Clone)]
 1377pub struct SelectionEffects {
 1378    nav_history: Option<bool>,
 1379    completions: bool,
 1380    scroll: Option<Autoscroll>,
 1381}
 1382
 1383impl Default for SelectionEffects {
 1384    fn default() -> Self {
 1385        Self {
 1386            nav_history: None,
 1387            completions: true,
 1388            scroll: Some(Autoscroll::fit()),
 1389        }
 1390    }
 1391}
 1392impl SelectionEffects {
 1393    pub fn scroll(scroll: Autoscroll) -> Self {
 1394        Self {
 1395            scroll: Some(scroll),
 1396            ..Default::default()
 1397        }
 1398    }
 1399
 1400    pub fn no_scroll() -> Self {
 1401        Self {
 1402            scroll: None,
 1403            ..Default::default()
 1404        }
 1405    }
 1406
 1407    pub fn completions(self, completions: bool) -> Self {
 1408        Self {
 1409            completions,
 1410            ..self
 1411        }
 1412    }
 1413
 1414    pub fn nav_history(self, nav_history: bool) -> Self {
 1415        Self {
 1416            nav_history: Some(nav_history),
 1417            ..self
 1418        }
 1419    }
 1420}
 1421
 1422struct DeferredSelectionEffectsState {
 1423    changed: bool,
 1424    effects: SelectionEffects,
 1425    old_cursor_position: Anchor,
 1426    history_entry: SelectionHistoryEntry,
 1427}
 1428
 1429#[derive(Default)]
 1430struct SelectionHistory {
 1431    #[allow(clippy::type_complexity)]
 1432    selections_by_transaction:
 1433        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1434    mode: SelectionHistoryMode,
 1435    undo_stack: VecDeque<SelectionHistoryEntry>,
 1436    redo_stack: VecDeque<SelectionHistoryEntry>,
 1437}
 1438
 1439impl SelectionHistory {
 1440    #[track_caller]
 1441    fn insert_transaction(
 1442        &mut self,
 1443        transaction_id: TransactionId,
 1444        selections: Arc<[Selection<Anchor>]>,
 1445    ) {
 1446        if selections.is_empty() {
 1447            log::error!(
 1448                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1449                std::panic::Location::caller()
 1450            );
 1451            return;
 1452        }
 1453        self.selections_by_transaction
 1454            .insert(transaction_id, (selections, None));
 1455    }
 1456
 1457    #[allow(clippy::type_complexity)]
 1458    fn transaction(
 1459        &self,
 1460        transaction_id: TransactionId,
 1461    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1462        self.selections_by_transaction.get(&transaction_id)
 1463    }
 1464
 1465    #[allow(clippy::type_complexity)]
 1466    fn transaction_mut(
 1467        &mut self,
 1468        transaction_id: TransactionId,
 1469    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1470        self.selections_by_transaction.get_mut(&transaction_id)
 1471    }
 1472
 1473    fn push(&mut self, entry: SelectionHistoryEntry) {
 1474        if !entry.selections.is_empty() {
 1475            match self.mode {
 1476                SelectionHistoryMode::Normal => {
 1477                    self.push_undo(entry);
 1478                    self.redo_stack.clear();
 1479                }
 1480                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1481                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1482                SelectionHistoryMode::Skipping => {}
 1483            }
 1484        }
 1485    }
 1486
 1487    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1488        if self
 1489            .undo_stack
 1490            .back()
 1491            .is_none_or(|e| e.selections != entry.selections)
 1492        {
 1493            self.undo_stack.push_back(entry);
 1494            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1495                self.undo_stack.pop_front();
 1496            }
 1497        }
 1498    }
 1499
 1500    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1501        if self
 1502            .redo_stack
 1503            .back()
 1504            .is_none_or(|e| e.selections != entry.selections)
 1505        {
 1506            self.redo_stack.push_back(entry);
 1507            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1508                self.redo_stack.pop_front();
 1509            }
 1510        }
 1511    }
 1512}
 1513
 1514#[derive(Clone, Copy)]
 1515pub struct RowHighlightOptions {
 1516    pub autoscroll: bool,
 1517    pub include_gutter: bool,
 1518}
 1519
 1520impl Default for RowHighlightOptions {
 1521    fn default() -> Self {
 1522        Self {
 1523            autoscroll: Default::default(),
 1524            include_gutter: true,
 1525        }
 1526    }
 1527}
 1528
 1529struct RowHighlight {
 1530    index: usize,
 1531    range: Range<Anchor>,
 1532    color: Hsla,
 1533    options: RowHighlightOptions,
 1534    type_id: TypeId,
 1535}
 1536
 1537#[derive(Clone, Debug)]
 1538struct AddSelectionsState {
 1539    groups: Vec<AddSelectionsGroup>,
 1540}
 1541
 1542#[derive(Clone, Debug)]
 1543struct AddSelectionsGroup {
 1544    above: bool,
 1545    stack: Vec<usize>,
 1546}
 1547
 1548#[derive(Clone)]
 1549struct SelectNextState {
 1550    query: AhoCorasick,
 1551    wordwise: bool,
 1552    done: bool,
 1553}
 1554
 1555impl std::fmt::Debug for SelectNextState {
 1556    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1557        f.debug_struct(std::any::type_name::<Self>())
 1558            .field("wordwise", &self.wordwise)
 1559            .field("done", &self.done)
 1560            .finish()
 1561    }
 1562}
 1563
 1564#[derive(Debug)]
 1565struct AutocloseRegion {
 1566    selection_id: usize,
 1567    range: Range<Anchor>,
 1568    pair: BracketPair,
 1569}
 1570
 1571#[derive(Debug)]
 1572struct SnippetState {
 1573    ranges: Vec<Vec<Range<Anchor>>>,
 1574    active_index: usize,
 1575    choices: Vec<Option<Vec<String>>>,
 1576}
 1577
 1578#[doc(hidden)]
 1579pub struct RenameState {
 1580    pub range: Range<Anchor>,
 1581    pub old_name: Arc<str>,
 1582    pub editor: Entity<Editor>,
 1583    block_id: CustomBlockId,
 1584}
 1585
 1586struct InvalidationStack<T>(Vec<T>);
 1587
 1588struct RegisteredEditPredictionDelegate {
 1589    provider: Arc<dyn EditPredictionDelegateHandle>,
 1590    _subscription: Subscription,
 1591}
 1592
 1593#[derive(Debug, PartialEq, Eq)]
 1594pub struct ActiveDiagnosticGroup {
 1595    pub active_range: Range<Anchor>,
 1596    pub active_message: String,
 1597    pub group_id: usize,
 1598    pub blocks: HashSet<CustomBlockId>,
 1599}
 1600
 1601#[derive(Debug, PartialEq, Eq)]
 1602
 1603pub(crate) enum ActiveDiagnostic {
 1604    None,
 1605    All,
 1606    Group(ActiveDiagnosticGroup),
 1607}
 1608
 1609#[derive(Serialize, Deserialize, Clone, Debug)]
 1610pub struct ClipboardSelection {
 1611    /// The number of bytes in this selection.
 1612    pub len: usize,
 1613    /// Whether this was a full-line selection.
 1614    pub is_entire_line: bool,
 1615    /// The indentation of the first line when this content was originally copied.
 1616    pub first_line_indent: u32,
 1617    #[serde(default)]
 1618    pub file_path: Option<PathBuf>,
 1619    #[serde(default)]
 1620    pub line_range: Option<RangeInclusive<u32>>,
 1621}
 1622
 1623impl ClipboardSelection {
 1624    pub fn for_buffer(
 1625        len: usize,
 1626        is_entire_line: bool,
 1627        range: Range<Point>,
 1628        buffer: &MultiBufferSnapshot,
 1629        project: Option<&Entity<Project>>,
 1630        cx: &App,
 1631    ) -> Self {
 1632        let first_line_indent = buffer
 1633            .indent_size_for_line(MultiBufferRow(range.start.row))
 1634            .len;
 1635
 1636        let file_path = util::maybe!({
 1637            let project = project?.read(cx);
 1638            let file = buffer.file_at(range.start)?;
 1639            let project_path = ProjectPath {
 1640                worktree_id: file.worktree_id(cx),
 1641                path: file.path().clone(),
 1642            };
 1643            project.absolute_path(&project_path, cx)
 1644        });
 1645
 1646        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1647
 1648        Self {
 1649            len,
 1650            is_entire_line,
 1651            first_line_indent,
 1652            file_path,
 1653            line_range,
 1654        }
 1655    }
 1656}
 1657
 1658// selections, scroll behavior, was newest selection reversed
 1659type SelectSyntaxNodeHistoryState = (
 1660    Box<[Selection<MultiBufferOffset>]>,
 1661    SelectSyntaxNodeScrollBehavior,
 1662    bool,
 1663);
 1664
 1665#[derive(Default)]
 1666struct SelectSyntaxNodeHistory {
 1667    stack: Vec<SelectSyntaxNodeHistoryState>,
 1668    // disable temporarily to allow changing selections without losing the stack
 1669    pub disable_clearing: bool,
 1670}
 1671
 1672impl SelectSyntaxNodeHistory {
 1673    pub fn try_clear(&mut self) {
 1674        if !self.disable_clearing {
 1675            self.stack.clear();
 1676        }
 1677    }
 1678
 1679    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1680        self.stack.push(selection);
 1681    }
 1682
 1683    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1684        self.stack.pop()
 1685    }
 1686}
 1687
 1688enum SelectSyntaxNodeScrollBehavior {
 1689    CursorTop,
 1690    FitSelection,
 1691    CursorBottom,
 1692}
 1693
 1694#[derive(Debug)]
 1695pub(crate) struct NavigationData {
 1696    cursor_anchor: Anchor,
 1697    cursor_position: Point,
 1698    scroll_anchor: ScrollAnchor,
 1699    scroll_top_row: u32,
 1700}
 1701
 1702#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1703pub enum GotoDefinitionKind {
 1704    Symbol,
 1705    Declaration,
 1706    Type,
 1707    Implementation,
 1708}
 1709
 1710pub enum FormatTarget {
 1711    Buffers(HashSet<Entity<Buffer>>),
 1712    Ranges(Vec<Range<MultiBufferPoint>>),
 1713}
 1714
 1715pub(crate) struct FocusedBlock {
 1716    id: BlockId,
 1717    focus_handle: WeakFocusHandle,
 1718}
 1719
 1720#[derive(Clone, Debug)]
 1721enum JumpData {
 1722    MultiBufferRow {
 1723        row: MultiBufferRow,
 1724        line_offset_from_top: u32,
 1725    },
 1726    MultiBufferPoint {
 1727        excerpt_id: ExcerptId,
 1728        position: Point,
 1729        anchor: text::Anchor,
 1730        line_offset_from_top: u32,
 1731    },
 1732}
 1733
 1734pub enum MultibufferSelectionMode {
 1735    First,
 1736    All,
 1737}
 1738
 1739#[derive(Clone, Copy, Debug, Default)]
 1740pub struct RewrapOptions {
 1741    pub override_language_settings: bool,
 1742    pub preserve_existing_whitespace: bool,
 1743}
 1744
 1745impl Editor {
 1746    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1747        let buffer = cx.new(|cx| Buffer::local("", cx));
 1748        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1749        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1750    }
 1751
 1752    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1753        let buffer = cx.new(|cx| Buffer::local("", cx));
 1754        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1755        Self::new(EditorMode::full(), buffer, None, window, cx)
 1756    }
 1757
 1758    pub fn auto_height(
 1759        min_lines: usize,
 1760        max_lines: usize,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        let buffer = cx.new(|cx| Buffer::local("", cx));
 1765        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1766        Self::new(
 1767            EditorMode::AutoHeight {
 1768                min_lines,
 1769                max_lines: Some(max_lines),
 1770            },
 1771            buffer,
 1772            None,
 1773            window,
 1774            cx,
 1775        )
 1776    }
 1777
 1778    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1779    /// The editor grows as tall as needed to fit its content.
 1780    pub fn auto_height_unbounded(
 1781        min_lines: usize,
 1782        window: &mut Window,
 1783        cx: &mut Context<Self>,
 1784    ) -> Self {
 1785        let buffer = cx.new(|cx| Buffer::local("", cx));
 1786        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1787        Self::new(
 1788            EditorMode::AutoHeight {
 1789                min_lines,
 1790                max_lines: None,
 1791            },
 1792            buffer,
 1793            None,
 1794            window,
 1795            cx,
 1796        )
 1797    }
 1798
 1799    pub fn for_buffer(
 1800        buffer: Entity<Buffer>,
 1801        project: Option<Entity<Project>>,
 1802        window: &mut Window,
 1803        cx: &mut Context<Self>,
 1804    ) -> Self {
 1805        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1806        Self::new(EditorMode::full(), buffer, project, window, cx)
 1807    }
 1808
 1809    pub fn for_multibuffer(
 1810        buffer: Entity<MultiBuffer>,
 1811        project: Option<Entity<Project>>,
 1812        window: &mut Window,
 1813        cx: &mut Context<Self>,
 1814    ) -> Self {
 1815        Self::new(EditorMode::full(), buffer, project, window, cx)
 1816    }
 1817
 1818    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1819        let mut clone = Self::new(
 1820            self.mode.clone(),
 1821            self.buffer.clone(),
 1822            self.project.clone(),
 1823            window,
 1824            cx,
 1825        );
 1826        self.display_map.update(cx, |display_map, cx| {
 1827            let snapshot = display_map.snapshot(cx);
 1828            clone.display_map.update(cx, |display_map, cx| {
 1829                display_map.set_state(&snapshot, cx);
 1830            });
 1831        });
 1832        clone.folds_did_change(cx);
 1833        clone.selections.clone_state(&self.selections);
 1834        clone.scroll_manager.clone_state(&self.scroll_manager);
 1835        clone.searchable = self.searchable;
 1836        clone.read_only = self.read_only;
 1837        clone
 1838    }
 1839
 1840    pub fn new(
 1841        mode: EditorMode,
 1842        buffer: Entity<MultiBuffer>,
 1843        project: Option<Entity<Project>>,
 1844        window: &mut Window,
 1845        cx: &mut Context<Self>,
 1846    ) -> Self {
 1847        Editor::new_internal(mode, buffer, project, None, window, cx)
 1848    }
 1849
 1850    pub fn sticky_headers(
 1851        &self,
 1852        style: &EditorStyle,
 1853        cx: &App,
 1854    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1855        let multi_buffer = self.buffer().read(cx);
 1856        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1857        let multi_buffer_visible_start = self
 1858            .scroll_manager
 1859            .anchor()
 1860            .anchor
 1861            .to_point(&multi_buffer_snapshot);
 1862        let max_row = multi_buffer_snapshot.max_point().row;
 1863
 1864        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1865        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1866
 1867        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1868            let outline_items = buffer
 1869                .outline_items_containing(
 1870                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1871                    true,
 1872                    Some(style.syntax.as_ref()),
 1873                )
 1874                .into_iter()
 1875                .map(|outline_item| OutlineItem {
 1876                    depth: outline_item.depth,
 1877                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1878                    source_range_for_text: Anchor::range_in_buffer(
 1879                        *excerpt_id,
 1880                        outline_item.source_range_for_text,
 1881                    ),
 1882                    text: outline_item.text,
 1883                    highlight_ranges: outline_item.highlight_ranges,
 1884                    name_ranges: outline_item.name_ranges,
 1885                    body_range: outline_item
 1886                        .body_range
 1887                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1888                    annotation_range: outline_item
 1889                        .annotation_range
 1890                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1891                });
 1892            return Some(outline_items.collect());
 1893        }
 1894
 1895        None
 1896    }
 1897
 1898    fn new_internal(
 1899        mode: EditorMode,
 1900        multi_buffer: Entity<MultiBuffer>,
 1901        project: Option<Entity<Project>>,
 1902        display_map: Option<Entity<DisplayMap>>,
 1903        window: &mut Window,
 1904        cx: &mut Context<Self>,
 1905    ) -> Self {
 1906        debug_assert!(
 1907            display_map.is_none() || mode.is_minimap(),
 1908            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1909        );
 1910
 1911        let full_mode = mode.is_full();
 1912        let is_minimap = mode.is_minimap();
 1913        let diagnostics_max_severity = if full_mode {
 1914            EditorSettings::get_global(cx)
 1915                .diagnostics_max_severity
 1916                .unwrap_or(DiagnosticSeverity::Hint)
 1917        } else {
 1918            DiagnosticSeverity::Off
 1919        };
 1920        let style = window.text_style();
 1921        let font_size = style.font_size.to_pixels(window.rem_size());
 1922        let editor = cx.entity().downgrade();
 1923        let fold_placeholder = FoldPlaceholder {
 1924            constrain_width: false,
 1925            render: Arc::new(move |fold_id, fold_range, cx| {
 1926                let editor = editor.clone();
 1927                div()
 1928                    .id(fold_id)
 1929                    .bg(cx.theme().colors().ghost_element_background)
 1930                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1931                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1932                    .rounded_xs()
 1933                    .size_full()
 1934                    .cursor_pointer()
 1935                    .child("")
 1936                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1937                    .on_click(move |_, _window, cx| {
 1938                        editor
 1939                            .update(cx, |editor, cx| {
 1940                                editor.unfold_ranges(
 1941                                    &[fold_range.start..fold_range.end],
 1942                                    true,
 1943                                    false,
 1944                                    cx,
 1945                                );
 1946                                cx.stop_propagation();
 1947                            })
 1948                            .ok();
 1949                    })
 1950                    .into_any()
 1951            }),
 1952            merge_adjacent: true,
 1953            ..FoldPlaceholder::default()
 1954        };
 1955        let display_map = display_map.unwrap_or_else(|| {
 1956            cx.new(|cx| {
 1957                DisplayMap::new(
 1958                    multi_buffer.clone(),
 1959                    style.font(),
 1960                    font_size,
 1961                    None,
 1962                    FILE_HEADER_HEIGHT,
 1963                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1964                    fold_placeholder,
 1965                    diagnostics_max_severity,
 1966                    cx,
 1967                )
 1968            })
 1969        });
 1970
 1971        let selections = SelectionsCollection::new();
 1972
 1973        let blink_manager = cx.new(|cx| {
 1974            let mut blink_manager = BlinkManager::new(
 1975                CURSOR_BLINK_INTERVAL,
 1976                |cx| EditorSettings::get_global(cx).cursor_blink,
 1977                cx,
 1978            );
 1979            if is_minimap {
 1980                blink_manager.disable(cx);
 1981            }
 1982            blink_manager
 1983        });
 1984
 1985        let soft_wrap_mode_override =
 1986            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1987
 1988        let mut project_subscriptions = Vec::new();
 1989        if full_mode && let Some(project) = project.as_ref() {
 1990            project_subscriptions.push(cx.subscribe_in(
 1991                project,
 1992                window,
 1993                |editor, _, event, window, cx| match event {
 1994                    project::Event::RefreshCodeLens => {
 1995                        // we always query lens with actions, without storing them, always refreshing them
 1996                    }
 1997                    project::Event::RefreshInlayHints {
 1998                        server_id,
 1999                        request_id,
 2000                    } => {
 2001                        editor.refresh_inlay_hints(
 2002                            InlayHintRefreshReason::RefreshRequested {
 2003                                server_id: *server_id,
 2004                                request_id: *request_id,
 2005                            },
 2006                            cx,
 2007                        );
 2008                    }
 2009                    project::Event::LanguageServerRemoved(..) => {
 2010                        if editor.tasks_update_task.is_none() {
 2011                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2012                        }
 2013                        editor.registered_buffers.clear();
 2014                        editor.register_visible_buffers(cx);
 2015                    }
 2016                    project::Event::LanguageServerAdded(..) => {
 2017                        if editor.tasks_update_task.is_none() {
 2018                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2019                        }
 2020                    }
 2021                    project::Event::SnippetEdit(id, snippet_edits) => {
 2022                        // todo(lw): Non singletons
 2023                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2024                            let snapshot = buffer.read(cx).snapshot();
 2025                            let focus_handle = editor.focus_handle(cx);
 2026                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2027                                for (range, snippet) in snippet_edits {
 2028                                    let buffer_range =
 2029                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2030                                    editor
 2031                                        .insert_snippet(
 2032                                            &[MultiBufferOffset(buffer_range.start)
 2033                                                ..MultiBufferOffset(buffer_range.end)],
 2034                                            snippet.clone(),
 2035                                            window,
 2036                                            cx,
 2037                                        )
 2038                                        .ok();
 2039                                }
 2040                            }
 2041                        }
 2042                    }
 2043                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2044                        let buffer_id = *buffer_id;
 2045                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2046                            editor.register_buffer(buffer_id, cx);
 2047                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2048                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2049                            refresh_linked_ranges(editor, window, cx);
 2050                            editor.refresh_code_actions(window, cx);
 2051                            editor.refresh_document_highlights(cx);
 2052                        }
 2053                    }
 2054
 2055                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2056                        let Some(workspace) = editor.workspace() else {
 2057                            return;
 2058                        };
 2059                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2060                        else {
 2061                            return;
 2062                        };
 2063
 2064                        if active_editor.entity_id() == cx.entity_id() {
 2065                            let entity_id = cx.entity_id();
 2066                            workspace.update(cx, |this, cx| {
 2067                                this.panes_mut()
 2068                                    .iter_mut()
 2069                                    .filter(|pane| pane.entity_id() != entity_id)
 2070                                    .for_each(|p| {
 2071                                        p.update(cx, |pane, _| {
 2072                                            pane.nav_history_mut().rename_item(
 2073                                                entity_id,
 2074                                                project_path.clone(),
 2075                                                abs_path.clone().into(),
 2076                                            );
 2077                                        })
 2078                                    });
 2079                            });
 2080
 2081                            Self::open_transaction_for_hidden_buffers(
 2082                                workspace,
 2083                                transaction.clone(),
 2084                                "Rename".to_string(),
 2085                                window,
 2086                                cx,
 2087                            );
 2088                        }
 2089                    }
 2090
 2091                    project::Event::WorkspaceEditApplied(transaction) => {
 2092                        let Some(workspace) = editor.workspace() else {
 2093                            return;
 2094                        };
 2095                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2096                        else {
 2097                            return;
 2098                        };
 2099
 2100                        if active_editor.entity_id() == cx.entity_id() {
 2101                            Self::open_transaction_for_hidden_buffers(
 2102                                workspace,
 2103                                transaction.clone(),
 2104                                "LSP Edit".to_string(),
 2105                                window,
 2106                                cx,
 2107                            );
 2108                        }
 2109                    }
 2110
 2111                    _ => {}
 2112                },
 2113            ));
 2114            if let Some(task_inventory) = project
 2115                .read(cx)
 2116                .task_store()
 2117                .read(cx)
 2118                .task_inventory()
 2119                .cloned()
 2120            {
 2121                project_subscriptions.push(cx.observe_in(
 2122                    &task_inventory,
 2123                    window,
 2124                    |editor, _, window, cx| {
 2125                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2126                    },
 2127                ));
 2128            };
 2129
 2130            project_subscriptions.push(cx.subscribe_in(
 2131                &project.read(cx).breakpoint_store(),
 2132                window,
 2133                |editor, _, event, window, cx| match event {
 2134                    BreakpointStoreEvent::ClearDebugLines => {
 2135                        editor.clear_row_highlights::<ActiveDebugLine>();
 2136                        editor.refresh_inline_values(cx);
 2137                    }
 2138                    BreakpointStoreEvent::SetDebugLine => {
 2139                        if editor.go_to_active_debug_line(window, cx) {
 2140                            cx.stop_propagation();
 2141                        }
 2142
 2143                        editor.refresh_inline_values(cx);
 2144                    }
 2145                    _ => {}
 2146                },
 2147            ));
 2148            let git_store = project.read(cx).git_store().clone();
 2149            let project = project.clone();
 2150            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2151                if let GitStoreEvent::RepositoryAdded = event {
 2152                    this.load_diff_task = Some(
 2153                        update_uncommitted_diff_for_buffer(
 2154                            cx.entity(),
 2155                            &project,
 2156                            this.buffer.read(cx).all_buffers(),
 2157                            this.buffer.clone(),
 2158                            cx,
 2159                        )
 2160                        .shared(),
 2161                    );
 2162                }
 2163            }));
 2164        }
 2165
 2166        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2167
 2168        let inlay_hint_settings =
 2169            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2170        let focus_handle = cx.focus_handle();
 2171        if !is_minimap {
 2172            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2173                .detach();
 2174            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2175                .detach();
 2176            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2177                .detach();
 2178            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2179                .detach();
 2180            cx.observe_pending_input(window, Self::observe_pending_input)
 2181                .detach();
 2182        }
 2183
 2184        let show_indent_guides =
 2185            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2186                Some(false)
 2187            } else {
 2188                None
 2189            };
 2190
 2191        let breakpoint_store = match (&mode, project.as_ref()) {
 2192            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2193            _ => None,
 2194        };
 2195
 2196        let mut code_action_providers = Vec::new();
 2197        let mut load_uncommitted_diff = None;
 2198        if let Some(project) = project.clone() {
 2199            load_uncommitted_diff = Some(
 2200                update_uncommitted_diff_for_buffer(
 2201                    cx.entity(),
 2202                    &project,
 2203                    multi_buffer.read(cx).all_buffers(),
 2204                    multi_buffer.clone(),
 2205                    cx,
 2206                )
 2207                .shared(),
 2208            );
 2209            code_action_providers.push(Rc::new(project) as Rc<_>);
 2210        }
 2211
 2212        let mut editor = Self {
 2213            focus_handle,
 2214            show_cursor_when_unfocused: false,
 2215            last_focused_descendant: None,
 2216            buffer: multi_buffer.clone(),
 2217            display_map: display_map.clone(),
 2218            placeholder_display_map: None,
 2219            selections,
 2220            scroll_manager: ScrollManager::new(cx),
 2221            columnar_selection_state: None,
 2222            add_selections_state: None,
 2223            select_next_state: None,
 2224            select_prev_state: None,
 2225            selection_history: SelectionHistory::default(),
 2226            defer_selection_effects: false,
 2227            deferred_selection_effects_state: None,
 2228            autoclose_regions: Vec::new(),
 2229            snippet_stack: InvalidationStack::default(),
 2230            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2231            ime_transaction: None,
 2232            active_diagnostics: ActiveDiagnostic::None,
 2233            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2234            inline_diagnostics_update: Task::ready(()),
 2235            inline_diagnostics: Vec::new(),
 2236            soft_wrap_mode_override,
 2237            diagnostics_max_severity,
 2238            hard_wrap: None,
 2239            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2240            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2241            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2242            project,
 2243            blink_manager: blink_manager.clone(),
 2244            show_local_selections: true,
 2245            show_scrollbars: ScrollbarAxes {
 2246                horizontal: full_mode,
 2247                vertical: full_mode,
 2248            },
 2249            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2250            offset_content: !matches!(mode, EditorMode::SingleLine),
 2251            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2252            show_gutter: full_mode,
 2253            show_line_numbers: (!full_mode).then_some(false),
 2254            use_relative_line_numbers: None,
 2255            disable_expand_excerpt_buttons: !full_mode,
 2256            delegate_expand_excerpts: false,
 2257            show_git_diff_gutter: None,
 2258            show_code_actions: None,
 2259            show_runnables: None,
 2260            show_breakpoints: None,
 2261            show_diff_review_button: false,
 2262            show_wrap_guides: None,
 2263            show_indent_guides,
 2264            buffers_with_disabled_indent_guides: HashSet::default(),
 2265            highlight_order: 0,
 2266            highlighted_rows: HashMap::default(),
 2267            background_highlights: HashMap::default(),
 2268            gutter_highlights: HashMap::default(),
 2269            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2270            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2271            nav_history: None,
 2272            context_menu: RefCell::new(None),
 2273            context_menu_options: None,
 2274            mouse_context_menu: None,
 2275            completion_tasks: Vec::new(),
 2276            inline_blame_popover: None,
 2277            inline_blame_popover_show_task: None,
 2278            signature_help_state: SignatureHelpState::default(),
 2279            auto_signature_help: None,
 2280            find_all_references_task_sources: Vec::new(),
 2281            next_completion_id: 0,
 2282            next_inlay_id: 0,
 2283            code_action_providers,
 2284            available_code_actions: None,
 2285            code_actions_task: None,
 2286            quick_selection_highlight_task: None,
 2287            debounced_selection_highlight_task: None,
 2288            document_highlights_task: None,
 2289            linked_editing_range_task: None,
 2290            pending_rename: None,
 2291            searchable: !is_minimap,
 2292            cursor_shape: EditorSettings::get_global(cx)
 2293                .cursor_shape
 2294                .unwrap_or_default(),
 2295            cursor_offset_on_selection: false,
 2296            current_line_highlight: None,
 2297            autoindent_mode: Some(AutoindentMode::EachLine),
 2298            collapse_matches: false,
 2299            workspace: None,
 2300            input_enabled: !is_minimap,
 2301            use_modal_editing: full_mode,
 2302            read_only: is_minimap,
 2303            use_autoclose: true,
 2304            use_auto_surround: true,
 2305            auto_replace_emoji_shortcode: false,
 2306            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2307            leader_id: None,
 2308            remote_id: None,
 2309            hover_state: HoverState::default(),
 2310            pending_mouse_down: None,
 2311            prev_pressure_stage: None,
 2312            hovered_link_state: None,
 2313            edit_prediction_provider: None,
 2314            active_edit_prediction: None,
 2315            stale_edit_prediction_in_menu: None,
 2316            edit_prediction_preview: EditPredictionPreview::Inactive {
 2317                released_too_fast: false,
 2318            },
 2319            inline_diagnostics_enabled: full_mode,
 2320            diagnostics_enabled: full_mode,
 2321            word_completions_enabled: full_mode,
 2322            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2323            gutter_hovered: false,
 2324            pixel_position_of_newest_cursor: None,
 2325            last_bounds: None,
 2326            last_position_map: None,
 2327            expect_bounds_change: None,
 2328            gutter_dimensions: GutterDimensions::default(),
 2329            style: None,
 2330            show_cursor_names: false,
 2331            hovered_cursors: HashMap::default(),
 2332            next_editor_action_id: EditorActionId::default(),
 2333            editor_actions: Rc::default(),
 2334            edit_predictions_hidden_for_vim_mode: false,
 2335            show_edit_predictions_override: None,
 2336            show_completions_on_input_override: None,
 2337            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2338            edit_prediction_settings: EditPredictionSettings::Disabled,
 2339            edit_prediction_indent_conflict: false,
 2340            edit_prediction_requires_modifier_in_indent_conflict: true,
 2341            custom_context_menu: None,
 2342            show_git_blame_gutter: false,
 2343            show_git_blame_inline: false,
 2344            show_selection_menu: None,
 2345            show_git_blame_inline_delay_task: None,
 2346            git_blame_inline_enabled: full_mode
 2347                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2348            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2349            buffer_serialization: is_minimap.not().then(|| {
 2350                BufferSerialization::new(
 2351                    ProjectSettings::get_global(cx)
 2352                        .session
 2353                        .restore_unsaved_buffers,
 2354                )
 2355            }),
 2356            blame: None,
 2357            blame_subscription: None,
 2358            tasks: BTreeMap::default(),
 2359
 2360            breakpoint_store,
 2361            gutter_breakpoint_indicator: (None, None),
 2362            gutter_diff_review_indicator: (None, None),
 2363            hovered_diff_hunk_row: None,
 2364            _subscriptions: (!is_minimap)
 2365                .then(|| {
 2366                    vec![
 2367                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2368                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2369                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2370                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2371                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2372                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2373                        cx.observe_window_activation(window, |editor, window, cx| {
 2374                            let active = window.is_window_active();
 2375                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2376                                if active {
 2377                                    blink_manager.enable(cx);
 2378                                } else {
 2379                                    blink_manager.disable(cx);
 2380                                }
 2381                            });
 2382                            if active {
 2383                                editor.show_mouse_cursor(cx);
 2384                            }
 2385                        }),
 2386                    ]
 2387                })
 2388                .unwrap_or_default(),
 2389            tasks_update_task: None,
 2390            pull_diagnostics_task: Task::ready(()),
 2391            pull_diagnostics_background_task: Task::ready(()),
 2392            colors: None,
 2393            refresh_colors_task: Task::ready(()),
 2394            inlay_hints: None,
 2395            next_color_inlay_id: 0,
 2396            post_scroll_update: Task::ready(()),
 2397            linked_edit_ranges: Default::default(),
 2398            in_project_search: false,
 2399            previous_search_ranges: None,
 2400            breadcrumb_header: None,
 2401            focused_block: None,
 2402            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2403            addons: HashMap::default(),
 2404            registered_buffers: HashMap::default(),
 2405            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2406            selection_mark_mode: false,
 2407            toggle_fold_multiple_buffers: Task::ready(()),
 2408            serialize_selections: Task::ready(()),
 2409            serialize_folds: Task::ready(()),
 2410            text_style_refinement: None,
 2411            load_diff_task: load_uncommitted_diff,
 2412            temporary_diff_override: false,
 2413            mouse_cursor_hidden: false,
 2414            minimap: None,
 2415            hide_mouse_mode: EditorSettings::get_global(cx)
 2416                .hide_mouse
 2417                .unwrap_or_default(),
 2418            change_list: ChangeList::new(),
 2419            mode,
 2420            selection_drag_state: SelectionDragState::None,
 2421            folding_newlines: Task::ready(()),
 2422            lookup_key: None,
 2423            select_next_is_case_sensitive: None,
 2424            applicable_language_settings: HashMap::default(),
 2425            accent_data: None,
 2426            fetched_tree_sitter_chunks: HashMap::default(),
 2427            number_deleted_lines: false,
 2428        };
 2429
 2430        if is_minimap {
 2431            return editor;
 2432        }
 2433
 2434        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2435        editor.accent_data = editor.fetch_accent_data(cx);
 2436
 2437        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2438            editor
 2439                ._subscriptions
 2440                .push(cx.observe(breakpoints, |_, _, cx| {
 2441                    cx.notify();
 2442                }));
 2443        }
 2444        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2445        editor._subscriptions.extend(project_subscriptions);
 2446
 2447        editor._subscriptions.push(cx.subscribe_in(
 2448            &cx.entity(),
 2449            window,
 2450            |editor, _, e: &EditorEvent, window, cx| match e {
 2451                EditorEvent::ScrollPositionChanged { local, .. } => {
 2452                    if *local {
 2453                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2454                        editor.inline_blame_popover.take();
 2455                        let new_anchor = editor.scroll_manager.anchor();
 2456                        let snapshot = editor.snapshot(window, cx);
 2457                        editor.update_restoration_data(cx, move |data| {
 2458                            data.scroll_position = (
 2459                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2460                                new_anchor.offset,
 2461                            );
 2462                        });
 2463
 2464                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2465                            cx.background_executor()
 2466                                .timer(Duration::from_millis(50))
 2467                                .await;
 2468                            editor
 2469                                .update_in(cx, |editor, window, cx| {
 2470                                    editor.register_visible_buffers(cx);
 2471                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2472                                    editor.refresh_inlay_hints(
 2473                                        InlayHintRefreshReason::NewLinesShown,
 2474                                        cx,
 2475                                    );
 2476                                    editor.colorize_brackets(false, cx);
 2477                                })
 2478                                .ok();
 2479                        });
 2480                    }
 2481                }
 2482                EditorEvent::Edited { .. } => {
 2483                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2484                        .map(|vim_mode| vim_mode.0)
 2485                        .unwrap_or(false);
 2486                    if !vim_mode {
 2487                        let display_map = editor.display_snapshot(cx);
 2488                        let selections = editor.selections.all_adjusted_display(&display_map);
 2489                        let pop_state = editor
 2490                            .change_list
 2491                            .last()
 2492                            .map(|previous| {
 2493                                previous.len() == selections.len()
 2494                                    && previous.iter().enumerate().all(|(ix, p)| {
 2495                                        p.to_display_point(&display_map).row()
 2496                                            == selections[ix].head().row()
 2497                                    })
 2498                            })
 2499                            .unwrap_or(false);
 2500                        let new_positions = selections
 2501                            .into_iter()
 2502                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2503                            .collect();
 2504                        editor
 2505                            .change_list
 2506                            .push_to_change_list(pop_state, new_positions);
 2507                    }
 2508                }
 2509                _ => (),
 2510            },
 2511        ));
 2512
 2513        if let Some(dap_store) = editor
 2514            .project
 2515            .as_ref()
 2516            .map(|project| project.read(cx).dap_store())
 2517        {
 2518            let weak_editor = cx.weak_entity();
 2519
 2520            editor
 2521                ._subscriptions
 2522                .push(
 2523                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2524                        let session_entity = cx.entity();
 2525                        weak_editor
 2526                            .update(cx, |editor, cx| {
 2527                                editor._subscriptions.push(
 2528                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2529                                );
 2530                            })
 2531                            .ok();
 2532                    }),
 2533                );
 2534
 2535            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2536                editor
 2537                    ._subscriptions
 2538                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2539            }
 2540        }
 2541
 2542        // skip adding the initial selection to selection history
 2543        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2544        editor.end_selection(window, cx);
 2545        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2546
 2547        editor.scroll_manager.show_scrollbars(window, cx);
 2548        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2549
 2550        if full_mode {
 2551            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2552            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2553
 2554            if editor.git_blame_inline_enabled {
 2555                editor.start_git_blame_inline(false, window, cx);
 2556            }
 2557
 2558            editor.go_to_active_debug_line(window, cx);
 2559
 2560            editor.minimap =
 2561                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2562            editor.colors = Some(LspColorData::new(cx));
 2563            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2564
 2565            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2566                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2567            }
 2568            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2569        }
 2570
 2571        editor
 2572    }
 2573
 2574    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2575        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2576    }
 2577
 2578    pub fn deploy_mouse_context_menu(
 2579        &mut self,
 2580        position: gpui::Point<Pixels>,
 2581        context_menu: Entity<ContextMenu>,
 2582        window: &mut Window,
 2583        cx: &mut Context<Self>,
 2584    ) {
 2585        self.mouse_context_menu = Some(MouseContextMenu::new(
 2586            self,
 2587            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2588            context_menu,
 2589            window,
 2590            cx,
 2591        ));
 2592    }
 2593
 2594    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2595        self.mouse_context_menu
 2596            .as_ref()
 2597            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2598    }
 2599
 2600    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2601        if self
 2602            .selections
 2603            .pending_anchor()
 2604            .is_some_and(|pending_selection| {
 2605                let snapshot = self.buffer().read(cx).snapshot(cx);
 2606                pending_selection.range().includes(range, &snapshot)
 2607            })
 2608        {
 2609            return true;
 2610        }
 2611
 2612        self.selections
 2613            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2614            .into_iter()
 2615            .any(|selection| {
 2616                // This is needed to cover a corner case, if we just check for an existing
 2617                // selection in the fold range, having a cursor at the start of the fold
 2618                // marks it as selected. Non-empty selections don't cause this.
 2619                let length = selection.end - selection.start;
 2620                length > 0
 2621            })
 2622    }
 2623
 2624    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2625        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2626    }
 2627
 2628    fn key_context_internal(
 2629        &self,
 2630        has_active_edit_prediction: bool,
 2631        window: &mut Window,
 2632        cx: &mut App,
 2633    ) -> KeyContext {
 2634        let mut key_context = KeyContext::new_with_defaults();
 2635        key_context.add("Editor");
 2636        let mode = match self.mode {
 2637            EditorMode::SingleLine => "single_line",
 2638            EditorMode::AutoHeight { .. } => "auto_height",
 2639            EditorMode::Minimap { .. } => "minimap",
 2640            EditorMode::Full { .. } => "full",
 2641        };
 2642
 2643        if EditorSettings::jupyter_enabled(cx) {
 2644            key_context.add("jupyter");
 2645        }
 2646
 2647        key_context.set("mode", mode);
 2648        if self.pending_rename.is_some() {
 2649            key_context.add("renaming");
 2650        }
 2651
 2652        if let Some(snippet_stack) = self.snippet_stack.last() {
 2653            key_context.add("in_snippet");
 2654
 2655            if snippet_stack.active_index > 0 {
 2656                key_context.add("has_previous_tabstop");
 2657            }
 2658
 2659            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2660                key_context.add("has_next_tabstop");
 2661            }
 2662        }
 2663
 2664        match self.context_menu.borrow().as_ref() {
 2665            Some(CodeContextMenu::Completions(menu)) => {
 2666                if menu.visible() {
 2667                    key_context.add("menu");
 2668                    key_context.add("showing_completions");
 2669                }
 2670            }
 2671            Some(CodeContextMenu::CodeActions(menu)) => {
 2672                if menu.visible() {
 2673                    key_context.add("menu");
 2674                    key_context.add("showing_code_actions")
 2675                }
 2676            }
 2677            None => {}
 2678        }
 2679
 2680        if self.signature_help_state.has_multiple_signatures() {
 2681            key_context.add("showing_signature_help");
 2682        }
 2683
 2684        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2685        if !self.focus_handle(cx).contains_focused(window, cx)
 2686            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2687        {
 2688            for addon in self.addons.values() {
 2689                addon.extend_key_context(&mut key_context, cx)
 2690            }
 2691        }
 2692
 2693        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2694            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2695                Some(
 2696                    file.full_path(cx)
 2697                        .extension()?
 2698                        .to_string_lossy()
 2699                        .to_lowercase(),
 2700                )
 2701            }) {
 2702                key_context.set("extension", extension);
 2703            }
 2704        } else {
 2705            key_context.add("multibuffer");
 2706        }
 2707
 2708        if has_active_edit_prediction {
 2709            if self.edit_prediction_in_conflict() {
 2710                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2711            } else {
 2712                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2713                key_context.add("copilot_suggestion");
 2714            }
 2715        }
 2716
 2717        if self.selection_mark_mode {
 2718            key_context.add("selection_mode");
 2719        }
 2720
 2721        let disjoint = self.selections.disjoint_anchors();
 2722        let snapshot = self.snapshot(window, cx);
 2723        let snapshot = snapshot.buffer_snapshot();
 2724        if self.mode == EditorMode::SingleLine
 2725            && let [selection] = disjoint
 2726            && selection.start == selection.end
 2727            && selection.end.to_offset(snapshot) == snapshot.len()
 2728        {
 2729            key_context.add("end_of_input");
 2730        }
 2731
 2732        if self.has_any_expanded_diff_hunks(cx) {
 2733            key_context.add("diffs_expanded");
 2734        }
 2735
 2736        key_context
 2737    }
 2738
 2739    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2740        self.last_bounds.as_ref()
 2741    }
 2742
 2743    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2744        if self.mouse_cursor_hidden {
 2745            self.mouse_cursor_hidden = false;
 2746            cx.notify();
 2747        }
 2748    }
 2749
 2750    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2751        let hide_mouse_cursor = match origin {
 2752            HideMouseCursorOrigin::TypingAction => {
 2753                matches!(
 2754                    self.hide_mouse_mode,
 2755                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2756                )
 2757            }
 2758            HideMouseCursorOrigin::MovementAction => {
 2759                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2760            }
 2761        };
 2762        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2763            self.mouse_cursor_hidden = hide_mouse_cursor;
 2764            cx.notify();
 2765        }
 2766    }
 2767
 2768    pub fn edit_prediction_in_conflict(&self) -> bool {
 2769        if !self.show_edit_predictions_in_menu() {
 2770            return false;
 2771        }
 2772
 2773        let showing_completions = self
 2774            .context_menu
 2775            .borrow()
 2776            .as_ref()
 2777            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2778
 2779        showing_completions
 2780            || self.edit_prediction_requires_modifier()
 2781            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2782            // bindings to insert tab characters.
 2783            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2784    }
 2785
 2786    pub fn accept_edit_prediction_keybind(
 2787        &self,
 2788        granularity: EditPredictionGranularity,
 2789        window: &mut Window,
 2790        cx: &mut App,
 2791    ) -> AcceptEditPredictionBinding {
 2792        let key_context = self.key_context_internal(true, window, cx);
 2793        let in_conflict = self.edit_prediction_in_conflict();
 2794
 2795        let bindings =
 2796            match granularity {
 2797                EditPredictionGranularity::Word => window
 2798                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2799                EditPredictionGranularity::Line => window
 2800                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2801                EditPredictionGranularity::Full => {
 2802                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2803                }
 2804            };
 2805
 2806        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2807            !in_conflict
 2808                || binding
 2809                    .keystrokes()
 2810                    .first()
 2811                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2812        }))
 2813    }
 2814
 2815    pub fn new_file(
 2816        workspace: &mut Workspace,
 2817        _: &workspace::NewFile,
 2818        window: &mut Window,
 2819        cx: &mut Context<Workspace>,
 2820    ) {
 2821        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2822            "Failed to create buffer",
 2823            window,
 2824            cx,
 2825            |e, _, _| match e.error_code() {
 2826                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2827                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2828                e.error_tag("required").unwrap_or("the latest version")
 2829            )),
 2830                _ => None,
 2831            },
 2832        );
 2833    }
 2834
 2835    pub fn new_in_workspace(
 2836        workspace: &mut Workspace,
 2837        window: &mut Window,
 2838        cx: &mut Context<Workspace>,
 2839    ) -> Task<Result<Entity<Editor>>> {
 2840        let project = workspace.project().clone();
 2841        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2842
 2843        cx.spawn_in(window, async move |workspace, cx| {
 2844            let buffer = create.await?;
 2845            workspace.update_in(cx, |workspace, window, cx| {
 2846                let editor =
 2847                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2848                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2849                editor
 2850            })
 2851        })
 2852    }
 2853
 2854    fn new_file_vertical(
 2855        workspace: &mut Workspace,
 2856        _: &workspace::NewFileSplitVertical,
 2857        window: &mut Window,
 2858        cx: &mut Context<Workspace>,
 2859    ) {
 2860        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2861    }
 2862
 2863    fn new_file_horizontal(
 2864        workspace: &mut Workspace,
 2865        _: &workspace::NewFileSplitHorizontal,
 2866        window: &mut Window,
 2867        cx: &mut Context<Workspace>,
 2868    ) {
 2869        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2870    }
 2871
 2872    fn new_file_split(
 2873        workspace: &mut Workspace,
 2874        action: &workspace::NewFileSplit,
 2875        window: &mut Window,
 2876        cx: &mut Context<Workspace>,
 2877    ) {
 2878        Self::new_file_in_direction(workspace, action.0, window, cx)
 2879    }
 2880
 2881    fn new_file_in_direction(
 2882        workspace: &mut Workspace,
 2883        direction: SplitDirection,
 2884        window: &mut Window,
 2885        cx: &mut Context<Workspace>,
 2886    ) {
 2887        let project = workspace.project().clone();
 2888        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2889
 2890        cx.spawn_in(window, async move |workspace, cx| {
 2891            let buffer = create.await?;
 2892            workspace.update_in(cx, move |workspace, window, cx| {
 2893                workspace.split_item(
 2894                    direction,
 2895                    Box::new(
 2896                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2897                    ),
 2898                    window,
 2899                    cx,
 2900                )
 2901            })?;
 2902            anyhow::Ok(())
 2903        })
 2904        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2905            match e.error_code() {
 2906                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2907                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2908                e.error_tag("required").unwrap_or("the latest version")
 2909            )),
 2910                _ => None,
 2911            }
 2912        });
 2913    }
 2914
 2915    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2916        self.leader_id
 2917    }
 2918
 2919    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2920        &self.buffer
 2921    }
 2922
 2923    pub fn project(&self) -> Option<&Entity<Project>> {
 2924        self.project.as_ref()
 2925    }
 2926
 2927    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2928        self.workspace.as_ref()?.0.upgrade()
 2929    }
 2930
 2931    /// Returns the workspace serialization ID if this editor should be serialized.
 2932    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2933        self.workspace
 2934            .as_ref()
 2935            .filter(|_| self.should_serialize_buffer())
 2936            .and_then(|workspace| workspace.1)
 2937    }
 2938
 2939    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2940        self.buffer().read(cx).title(cx)
 2941    }
 2942
 2943    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2944        let git_blame_gutter_max_author_length = self
 2945            .render_git_blame_gutter(cx)
 2946            .then(|| {
 2947                if let Some(blame) = self.blame.as_ref() {
 2948                    let max_author_length =
 2949                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2950                    Some(max_author_length)
 2951                } else {
 2952                    None
 2953                }
 2954            })
 2955            .flatten();
 2956
 2957        EditorSnapshot {
 2958            mode: self.mode.clone(),
 2959            show_gutter: self.show_gutter,
 2960            offset_content: self.offset_content,
 2961            show_line_numbers: self.show_line_numbers,
 2962            number_deleted_lines: self.number_deleted_lines,
 2963            show_git_diff_gutter: self.show_git_diff_gutter,
 2964            show_code_actions: self.show_code_actions,
 2965            show_runnables: self.show_runnables,
 2966            show_breakpoints: self.show_breakpoints,
 2967            git_blame_gutter_max_author_length,
 2968            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2969            placeholder_display_snapshot: self
 2970                .placeholder_display_map
 2971                .as_ref()
 2972                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2973            scroll_anchor: self.scroll_manager.anchor(),
 2974            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2975            is_focused: self.focus_handle.is_focused(window),
 2976            current_line_highlight: self
 2977                .current_line_highlight
 2978                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2979            gutter_hovered: self.gutter_hovered,
 2980        }
 2981    }
 2982
 2983    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2984        self.buffer.read(cx).language_at(point, cx)
 2985    }
 2986
 2987    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2988        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2989    }
 2990
 2991    pub fn active_excerpt(
 2992        &self,
 2993        cx: &App,
 2994    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2995        self.buffer
 2996            .read(cx)
 2997            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2998    }
 2999
 3000    pub fn mode(&self) -> &EditorMode {
 3001        &self.mode
 3002    }
 3003
 3004    pub fn set_mode(&mut self, mode: EditorMode) {
 3005        self.mode = mode;
 3006    }
 3007
 3008    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3009        self.collaboration_hub.as_deref()
 3010    }
 3011
 3012    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3013        self.collaboration_hub = Some(hub);
 3014    }
 3015
 3016    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3017        self.in_project_search = in_project_search;
 3018    }
 3019
 3020    pub fn set_custom_context_menu(
 3021        &mut self,
 3022        f: impl 'static
 3023        + Fn(
 3024            &mut Self,
 3025            DisplayPoint,
 3026            &mut Window,
 3027            &mut Context<Self>,
 3028        ) -> Option<Entity<ui::ContextMenu>>,
 3029    ) {
 3030        self.custom_context_menu = Some(Box::new(f))
 3031    }
 3032
 3033    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3034        self.completion_provider = provider;
 3035    }
 3036
 3037    #[cfg(any(test, feature = "test-support"))]
 3038    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3039        self.completion_provider.clone()
 3040    }
 3041
 3042    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3043        self.semantics_provider.clone()
 3044    }
 3045
 3046    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3047        self.semantics_provider = provider;
 3048    }
 3049
 3050    pub fn set_edit_prediction_provider<T>(
 3051        &mut self,
 3052        provider: Option<Entity<T>>,
 3053        window: &mut Window,
 3054        cx: &mut Context<Self>,
 3055    ) where
 3056        T: EditPredictionDelegate,
 3057    {
 3058        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3059            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3060                if this.focus_handle.is_focused(window) {
 3061                    this.update_visible_edit_prediction(window, cx);
 3062                }
 3063            }),
 3064            provider: Arc::new(provider),
 3065        });
 3066        self.update_edit_prediction_settings(cx);
 3067        self.refresh_edit_prediction(false, false, window, cx);
 3068    }
 3069
 3070    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3071        self.placeholder_display_map
 3072            .as_ref()
 3073            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3074    }
 3075
 3076    pub fn set_placeholder_text(
 3077        &mut self,
 3078        placeholder_text: &str,
 3079        window: &mut Window,
 3080        cx: &mut Context<Self>,
 3081    ) {
 3082        let multibuffer = cx
 3083            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3084
 3085        let style = window.text_style();
 3086
 3087        self.placeholder_display_map = Some(cx.new(|cx| {
 3088            DisplayMap::new(
 3089                multibuffer,
 3090                style.font(),
 3091                style.font_size.to_pixels(window.rem_size()),
 3092                None,
 3093                FILE_HEADER_HEIGHT,
 3094                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3095                Default::default(),
 3096                DiagnosticSeverity::Off,
 3097                cx,
 3098            )
 3099        }));
 3100        cx.notify();
 3101    }
 3102
 3103    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3104        self.cursor_shape = cursor_shape;
 3105
 3106        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3107        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3108
 3109        cx.notify();
 3110    }
 3111
 3112    pub fn cursor_shape(&self) -> CursorShape {
 3113        self.cursor_shape
 3114    }
 3115
 3116    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3117        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3118    }
 3119
 3120    pub fn set_current_line_highlight(
 3121        &mut self,
 3122        current_line_highlight: Option<CurrentLineHighlight>,
 3123    ) {
 3124        self.current_line_highlight = current_line_highlight;
 3125    }
 3126
 3127    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3128        self.collapse_matches = collapse_matches;
 3129    }
 3130
 3131    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3132        if self.collapse_matches {
 3133            return range.start..range.start;
 3134        }
 3135        range.clone()
 3136    }
 3137
 3138    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3139        self.display_map.read(cx).clip_at_line_ends
 3140    }
 3141
 3142    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3143        if self.display_map.read(cx).clip_at_line_ends != clip {
 3144            self.display_map
 3145                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3146        }
 3147    }
 3148
 3149    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3150        self.input_enabled = input_enabled;
 3151    }
 3152
 3153    pub fn set_edit_predictions_hidden_for_vim_mode(
 3154        &mut self,
 3155        hidden: bool,
 3156        window: &mut Window,
 3157        cx: &mut Context<Self>,
 3158    ) {
 3159        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3160            self.edit_predictions_hidden_for_vim_mode = hidden;
 3161            if hidden {
 3162                self.update_visible_edit_prediction(window, cx);
 3163            } else {
 3164                self.refresh_edit_prediction(true, false, window, cx);
 3165            }
 3166        }
 3167    }
 3168
 3169    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3170        self.menu_edit_predictions_policy = value;
 3171    }
 3172
 3173    pub fn set_autoindent(&mut self, autoindent: bool) {
 3174        if autoindent {
 3175            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3176        } else {
 3177            self.autoindent_mode = None;
 3178        }
 3179    }
 3180
 3181    pub fn capability(&self, cx: &App) -> Capability {
 3182        if self.read_only {
 3183            Capability::ReadOnly
 3184        } else {
 3185            self.buffer.read(cx).capability()
 3186        }
 3187    }
 3188
 3189    pub fn read_only(&self, cx: &App) -> bool {
 3190        self.read_only || self.buffer.read(cx).read_only()
 3191    }
 3192
 3193    pub fn set_read_only(&mut self, read_only: bool) {
 3194        self.read_only = read_only;
 3195    }
 3196
 3197    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3198        self.use_autoclose = autoclose;
 3199    }
 3200
 3201    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3202        self.use_auto_surround = auto_surround;
 3203    }
 3204
 3205    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3206        self.auto_replace_emoji_shortcode = auto_replace;
 3207    }
 3208
 3209    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3210        self.buffer_serialization = should_serialize.then(|| {
 3211            BufferSerialization::new(
 3212                ProjectSettings::get_global(cx)
 3213                    .session
 3214                    .restore_unsaved_buffers,
 3215            )
 3216        })
 3217    }
 3218
 3219    fn should_serialize_buffer(&self) -> bool {
 3220        self.buffer_serialization.is_some()
 3221    }
 3222
 3223    pub fn toggle_edit_predictions(
 3224        &mut self,
 3225        _: &ToggleEditPrediction,
 3226        window: &mut Window,
 3227        cx: &mut Context<Self>,
 3228    ) {
 3229        if self.show_edit_predictions_override.is_some() {
 3230            self.set_show_edit_predictions(None, window, cx);
 3231        } else {
 3232            let show_edit_predictions = !self.edit_predictions_enabled();
 3233            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3234        }
 3235    }
 3236
 3237    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3238        self.show_completions_on_input_override = show_completions_on_input;
 3239    }
 3240
 3241    pub fn set_show_edit_predictions(
 3242        &mut self,
 3243        show_edit_predictions: Option<bool>,
 3244        window: &mut Window,
 3245        cx: &mut Context<Self>,
 3246    ) {
 3247        self.show_edit_predictions_override = show_edit_predictions;
 3248        self.update_edit_prediction_settings(cx);
 3249
 3250        if let Some(false) = show_edit_predictions {
 3251            self.discard_edit_prediction(false, cx);
 3252        } else {
 3253            self.refresh_edit_prediction(false, true, window, cx);
 3254        }
 3255    }
 3256
 3257    fn edit_predictions_disabled_in_scope(
 3258        &self,
 3259        buffer: &Entity<Buffer>,
 3260        buffer_position: language::Anchor,
 3261        cx: &App,
 3262    ) -> bool {
 3263        let snapshot = buffer.read(cx).snapshot();
 3264        let settings = snapshot.settings_at(buffer_position, cx);
 3265
 3266        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3267            return false;
 3268        };
 3269
 3270        scope.override_name().is_some_and(|scope_name| {
 3271            settings
 3272                .edit_predictions_disabled_in
 3273                .iter()
 3274                .any(|s| s == scope_name)
 3275        })
 3276    }
 3277
 3278    pub fn set_use_modal_editing(&mut self, to: bool) {
 3279        self.use_modal_editing = to;
 3280    }
 3281
 3282    pub fn use_modal_editing(&self) -> bool {
 3283        self.use_modal_editing
 3284    }
 3285
 3286    fn selections_did_change(
 3287        &mut self,
 3288        local: bool,
 3289        old_cursor_position: &Anchor,
 3290        effects: SelectionEffects,
 3291        window: &mut Window,
 3292        cx: &mut Context<Self>,
 3293    ) {
 3294        window.invalidate_character_coordinates();
 3295
 3296        // Copy selections to primary selection buffer
 3297        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3298        if local {
 3299            let selections = self
 3300                .selections
 3301                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3302            let buffer_handle = self.buffer.read(cx).read(cx);
 3303
 3304            let mut text = String::new();
 3305            for (index, selection) in selections.iter().enumerate() {
 3306                let text_for_selection = buffer_handle
 3307                    .text_for_range(selection.start..selection.end)
 3308                    .collect::<String>();
 3309
 3310                text.push_str(&text_for_selection);
 3311                if index != selections.len() - 1 {
 3312                    text.push('\n');
 3313                }
 3314            }
 3315
 3316            if !text.is_empty() {
 3317                cx.write_to_primary(ClipboardItem::new_string(text));
 3318            }
 3319        }
 3320
 3321        let selection_anchors = self.selections.disjoint_anchors_arc();
 3322
 3323        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3324            self.buffer.update(cx, |buffer, cx| {
 3325                buffer.set_active_selections(
 3326                    &selection_anchors,
 3327                    self.selections.line_mode(),
 3328                    self.cursor_shape,
 3329                    cx,
 3330                )
 3331            });
 3332        }
 3333        let display_map = self
 3334            .display_map
 3335            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3336        let buffer = display_map.buffer_snapshot();
 3337        if self.selections.count() == 1 {
 3338            self.add_selections_state = None;
 3339        }
 3340        self.select_next_state = None;
 3341        self.select_prev_state = None;
 3342        self.select_syntax_node_history.try_clear();
 3343        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3344        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3345        self.take_rename(false, window, cx);
 3346
 3347        let newest_selection = self.selections.newest_anchor();
 3348        let new_cursor_position = newest_selection.head();
 3349        let selection_start = newest_selection.start;
 3350
 3351        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3352            self.push_to_nav_history(
 3353                *old_cursor_position,
 3354                Some(new_cursor_position.to_point(buffer)),
 3355                false,
 3356                effects.nav_history == Some(true),
 3357                cx,
 3358            );
 3359        }
 3360
 3361        if local {
 3362            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3363                self.register_buffer(buffer_id, cx);
 3364            }
 3365
 3366            let mut context_menu = self.context_menu.borrow_mut();
 3367            let completion_menu = match context_menu.as_ref() {
 3368                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3369                Some(CodeContextMenu::CodeActions(_)) => {
 3370                    *context_menu = None;
 3371                    None
 3372                }
 3373                None => None,
 3374            };
 3375            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3376            drop(context_menu);
 3377
 3378            if effects.completions
 3379                && let Some(completion_position) = completion_position
 3380            {
 3381                let start_offset = selection_start.to_offset(buffer);
 3382                let position_matches = start_offset == completion_position.to_offset(buffer);
 3383                let continue_showing = if let Some((snap, ..)) =
 3384                    buffer.point_to_buffer_offset(completion_position)
 3385                    && !snap.capability.editable()
 3386                {
 3387                    false
 3388                } else if position_matches {
 3389                    if self.snippet_stack.is_empty() {
 3390                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3391                            == Some(CharKind::Word)
 3392                    } else {
 3393                        // Snippet choices can be shown even when the cursor is in whitespace.
 3394                        // Dismissing the menu with actions like backspace is handled by
 3395                        // invalidation regions.
 3396                        true
 3397                    }
 3398                } else {
 3399                    false
 3400                };
 3401
 3402                if continue_showing {
 3403                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3404                } else {
 3405                    self.hide_context_menu(window, cx);
 3406                }
 3407            }
 3408
 3409            hide_hover(self, cx);
 3410
 3411            if old_cursor_position.to_display_point(&display_map).row()
 3412                != new_cursor_position.to_display_point(&display_map).row()
 3413            {
 3414                self.available_code_actions.take();
 3415            }
 3416            self.refresh_code_actions(window, cx);
 3417            self.refresh_document_highlights(cx);
 3418            refresh_linked_ranges(self, window, cx);
 3419
 3420            self.refresh_selected_text_highlights(false, window, cx);
 3421            self.refresh_matching_bracket_highlights(window, cx);
 3422            self.update_visible_edit_prediction(window, cx);
 3423            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3424            self.inline_blame_popover.take();
 3425            if self.git_blame_inline_enabled {
 3426                self.start_inline_blame_timer(window, cx);
 3427            }
 3428        }
 3429
 3430        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3431        cx.emit(EditorEvent::SelectionsChanged { local });
 3432
 3433        let selections = &self.selections.disjoint_anchors_arc();
 3434        if selections.len() == 1 {
 3435            cx.emit(SearchEvent::ActiveMatchChanged)
 3436        }
 3437        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3438            let inmemory_selections = selections
 3439                .iter()
 3440                .map(|s| {
 3441                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3442                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3443                })
 3444                .collect();
 3445            self.update_restoration_data(cx, |data| {
 3446                data.selections = inmemory_selections;
 3447            });
 3448
 3449            if WorkspaceSettings::get(None, cx).restore_on_startup
 3450                != RestoreOnStartupBehavior::EmptyTab
 3451                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3452            {
 3453                let snapshot = self.buffer().read(cx).snapshot(cx);
 3454                let selections = selections.clone();
 3455                let background_executor = cx.background_executor().clone();
 3456                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3457                self.serialize_selections = cx.background_spawn(async move {
 3458                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3459                    let db_selections = selections
 3460                        .iter()
 3461                        .map(|selection| {
 3462                            (
 3463                                selection.start.to_offset(&snapshot).0,
 3464                                selection.end.to_offset(&snapshot).0,
 3465                            )
 3466                        })
 3467                        .collect();
 3468
 3469                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3470                        .await
 3471                        .with_context(|| {
 3472                            format!(
 3473                                "persisting editor selections for editor {editor_id}, \
 3474                                workspace {workspace_id:?}"
 3475                            )
 3476                        })
 3477                        .log_err();
 3478                });
 3479            }
 3480        }
 3481
 3482        cx.notify();
 3483    }
 3484
 3485    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3486        use text::ToOffset as _;
 3487        use text::ToPoint as _;
 3488
 3489        if self.mode.is_minimap()
 3490            || WorkspaceSettings::get(None, cx).restore_on_startup
 3491                == RestoreOnStartupBehavior::EmptyTab
 3492        {
 3493            return;
 3494        }
 3495
 3496        if !self.buffer().read(cx).is_singleton() {
 3497            return;
 3498        }
 3499
 3500        let display_snapshot = self
 3501            .display_map
 3502            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3503        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3504            return;
 3505        };
 3506        let inmemory_folds = display_snapshot
 3507            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3508            .map(|fold| {
 3509                fold.range.start.text_anchor.to_point(&snapshot)
 3510                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3511            })
 3512            .collect();
 3513        self.update_restoration_data(cx, |data| {
 3514            data.folds = inmemory_folds;
 3515        });
 3516
 3517        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3518            return;
 3519        };
 3520        let background_executor = cx.background_executor().clone();
 3521        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3522        const FINGERPRINT_LEN: usize = 32;
 3523        let db_folds = display_snapshot
 3524            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3525            .map(|fold| {
 3526                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3527                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3528
 3529                // Extract fingerprints - content at fold boundaries for validation on restore
 3530                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3531                // content that might change independently.
 3532                // start_fp: first min(32, fold_len) bytes of fold content
 3533                // end_fp: last min(32, fold_len) bytes of fold content
 3534                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3535                let fold_len = end - start;
 3536                let start_fp_end = snapshot
 3537                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3538                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3539                let end_fp_start = snapshot
 3540                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3541                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3542
 3543                (start, end, start_fp, end_fp)
 3544            })
 3545            .collect::<Vec<_>>();
 3546        self.serialize_folds = cx.background_spawn(async move {
 3547            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3548            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3549                .await
 3550                .with_context(|| {
 3551                    format!(
 3552                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3553                    )
 3554                })
 3555                .log_err();
 3556        });
 3557    }
 3558
 3559    pub fn sync_selections(
 3560        &mut self,
 3561        other: Entity<Editor>,
 3562        cx: &mut Context<Self>,
 3563    ) -> gpui::Subscription {
 3564        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3565        if !other_selections.is_empty() {
 3566            self.selections
 3567                .change_with(&self.display_snapshot(cx), |selections| {
 3568                    selections.select_anchors(other_selections);
 3569                });
 3570        }
 3571
 3572        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3573            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3574                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3575                if other_selections.is_empty() {
 3576                    return;
 3577                }
 3578                let snapshot = this.display_snapshot(cx);
 3579                this.selections.change_with(&snapshot, |selections| {
 3580                    selections.select_anchors(other_selections);
 3581                });
 3582            }
 3583        });
 3584
 3585        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3586            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3587                let these_selections = this.selections.disjoint_anchors().to_vec();
 3588                if these_selections.is_empty() {
 3589                    return;
 3590                }
 3591                other.update(cx, |other_editor, cx| {
 3592                    let snapshot = other_editor.display_snapshot(cx);
 3593                    other_editor
 3594                        .selections
 3595                        .change_with(&snapshot, |selections| {
 3596                            selections.select_anchors(these_selections);
 3597                        })
 3598                });
 3599            }
 3600        });
 3601
 3602        Subscription::join(other_subscription, this_subscription)
 3603    }
 3604
 3605    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3606        if self.buffer().read(cx).is_singleton() {
 3607            return;
 3608        }
 3609        let snapshot = self.buffer.read(cx).snapshot(cx);
 3610        let buffer_ids: HashSet<BufferId> = self
 3611            .selections
 3612            .disjoint_anchor_ranges()
 3613            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3614            .collect();
 3615        for buffer_id in buffer_ids {
 3616            self.unfold_buffer(buffer_id, cx);
 3617        }
 3618    }
 3619
 3620    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3621    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3622    /// effects of selection change occur at the end of the transaction.
 3623    pub fn change_selections<R>(
 3624        &mut self,
 3625        effects: SelectionEffects,
 3626        window: &mut Window,
 3627        cx: &mut Context<Self>,
 3628        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3629    ) -> R {
 3630        let snapshot = self.display_snapshot(cx);
 3631        if let Some(state) = &mut self.deferred_selection_effects_state {
 3632            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3633            state.effects.completions = effects.completions;
 3634            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3635            let (changed, result) = self.selections.change_with(&snapshot, change);
 3636            state.changed |= changed;
 3637            return result;
 3638        }
 3639        let mut state = DeferredSelectionEffectsState {
 3640            changed: false,
 3641            effects,
 3642            old_cursor_position: self.selections.newest_anchor().head(),
 3643            history_entry: SelectionHistoryEntry {
 3644                selections: self.selections.disjoint_anchors_arc(),
 3645                select_next_state: self.select_next_state.clone(),
 3646                select_prev_state: self.select_prev_state.clone(),
 3647                add_selections_state: self.add_selections_state.clone(),
 3648            },
 3649        };
 3650        let (changed, result) = self.selections.change_with(&snapshot, change);
 3651        state.changed = state.changed || changed;
 3652        if self.defer_selection_effects {
 3653            self.deferred_selection_effects_state = Some(state);
 3654        } else {
 3655            self.apply_selection_effects(state, window, cx);
 3656        }
 3657        result
 3658    }
 3659
 3660    /// Defers the effects of selection change, so that the effects of multiple calls to
 3661    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3662    /// to selection history and the state of popovers based on selection position aren't
 3663    /// erroneously updated.
 3664    pub fn with_selection_effects_deferred<R>(
 3665        &mut self,
 3666        window: &mut Window,
 3667        cx: &mut Context<Self>,
 3668        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3669    ) -> R {
 3670        let already_deferred = self.defer_selection_effects;
 3671        self.defer_selection_effects = true;
 3672        let result = update(self, window, cx);
 3673        if !already_deferred {
 3674            self.defer_selection_effects = false;
 3675            if let Some(state) = self.deferred_selection_effects_state.take() {
 3676                self.apply_selection_effects(state, window, cx);
 3677            }
 3678        }
 3679        result
 3680    }
 3681
 3682    fn apply_selection_effects(
 3683        &mut self,
 3684        state: DeferredSelectionEffectsState,
 3685        window: &mut Window,
 3686        cx: &mut Context<Self>,
 3687    ) {
 3688        if state.changed {
 3689            self.selection_history.push(state.history_entry);
 3690
 3691            if let Some(autoscroll) = state.effects.scroll {
 3692                self.request_autoscroll(autoscroll, cx);
 3693            }
 3694
 3695            let old_cursor_position = &state.old_cursor_position;
 3696
 3697            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3698
 3699            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3700                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3701            }
 3702        }
 3703    }
 3704
 3705    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3706    where
 3707        I: IntoIterator<Item = (Range<S>, T)>,
 3708        S: ToOffset,
 3709        T: Into<Arc<str>>,
 3710    {
 3711        if self.read_only(cx) {
 3712            return;
 3713        }
 3714
 3715        self.buffer
 3716            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3717    }
 3718
 3719    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3720    where
 3721        I: IntoIterator<Item = (Range<S>, T)>,
 3722        S: ToOffset,
 3723        T: Into<Arc<str>>,
 3724    {
 3725        if self.read_only(cx) {
 3726            return;
 3727        }
 3728
 3729        self.buffer.update(cx, |buffer, cx| {
 3730            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3731        });
 3732    }
 3733
 3734    pub fn edit_with_block_indent<I, S, T>(
 3735        &mut self,
 3736        edits: I,
 3737        original_indent_columns: Vec<Option<u32>>,
 3738        cx: &mut Context<Self>,
 3739    ) where
 3740        I: IntoIterator<Item = (Range<S>, T)>,
 3741        S: ToOffset,
 3742        T: Into<Arc<str>>,
 3743    {
 3744        if self.read_only(cx) {
 3745            return;
 3746        }
 3747
 3748        self.buffer.update(cx, |buffer, cx| {
 3749            buffer.edit(
 3750                edits,
 3751                Some(AutoindentMode::Block {
 3752                    original_indent_columns,
 3753                }),
 3754                cx,
 3755            )
 3756        });
 3757    }
 3758
 3759    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3760        self.hide_context_menu(window, cx);
 3761
 3762        match phase {
 3763            SelectPhase::Begin {
 3764                position,
 3765                add,
 3766                click_count,
 3767            } => self.begin_selection(position, add, click_count, window, cx),
 3768            SelectPhase::BeginColumnar {
 3769                position,
 3770                goal_column,
 3771                reset,
 3772                mode,
 3773            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3774            SelectPhase::Extend {
 3775                position,
 3776                click_count,
 3777            } => self.extend_selection(position, click_count, window, cx),
 3778            SelectPhase::Update {
 3779                position,
 3780                goal_column,
 3781                scroll_delta,
 3782            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3783            SelectPhase::End => self.end_selection(window, cx),
 3784        }
 3785    }
 3786
 3787    fn extend_selection(
 3788        &mut self,
 3789        position: DisplayPoint,
 3790        click_count: usize,
 3791        window: &mut Window,
 3792        cx: &mut Context<Self>,
 3793    ) {
 3794        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3795        let tail = self
 3796            .selections
 3797            .newest::<MultiBufferOffset>(&display_map)
 3798            .tail();
 3799        let click_count = click_count.max(match self.selections.select_mode() {
 3800            SelectMode::Character => 1,
 3801            SelectMode::Word(_) => 2,
 3802            SelectMode::Line(_) => 3,
 3803            SelectMode::All => 4,
 3804        });
 3805        self.begin_selection(position, false, click_count, window, cx);
 3806
 3807        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3808
 3809        let current_selection = match self.selections.select_mode() {
 3810            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3811            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3812        };
 3813
 3814        let mut pending_selection = self
 3815            .selections
 3816            .pending_anchor()
 3817            .cloned()
 3818            .expect("extend_selection not called with pending selection");
 3819
 3820        if pending_selection
 3821            .start
 3822            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3823            == Ordering::Greater
 3824        {
 3825            pending_selection.start = current_selection.start;
 3826        }
 3827        if pending_selection
 3828            .end
 3829            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3830            == Ordering::Less
 3831        {
 3832            pending_selection.end = current_selection.end;
 3833            pending_selection.reversed = true;
 3834        }
 3835
 3836        let mut pending_mode = self.selections.pending_mode().unwrap();
 3837        match &mut pending_mode {
 3838            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3839            _ => {}
 3840        }
 3841
 3842        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3843            SelectionEffects::scroll(Autoscroll::fit())
 3844        } else {
 3845            SelectionEffects::no_scroll()
 3846        };
 3847
 3848        self.change_selections(effects, window, cx, |s| {
 3849            s.set_pending(pending_selection.clone(), pending_mode);
 3850            s.set_is_extending(true);
 3851        });
 3852    }
 3853
 3854    fn begin_selection(
 3855        &mut self,
 3856        position: DisplayPoint,
 3857        add: bool,
 3858        click_count: usize,
 3859        window: &mut Window,
 3860        cx: &mut Context<Self>,
 3861    ) {
 3862        if !self.focus_handle.is_focused(window) {
 3863            self.last_focused_descendant = None;
 3864            window.focus(&self.focus_handle, cx);
 3865        }
 3866
 3867        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3868        let buffer = display_map.buffer_snapshot();
 3869        let position = display_map.clip_point(position, Bias::Left);
 3870
 3871        let start;
 3872        let end;
 3873        let mode;
 3874        let mut auto_scroll;
 3875        match click_count {
 3876            1 => {
 3877                start = buffer.anchor_before(position.to_point(&display_map));
 3878                end = start;
 3879                mode = SelectMode::Character;
 3880                auto_scroll = true;
 3881            }
 3882            2 => {
 3883                let position = display_map
 3884                    .clip_point(position, Bias::Left)
 3885                    .to_offset(&display_map, Bias::Left);
 3886                let (range, _) = buffer.surrounding_word(position, None);
 3887                start = buffer.anchor_before(range.start);
 3888                end = buffer.anchor_before(range.end);
 3889                mode = SelectMode::Word(start..end);
 3890                auto_scroll = true;
 3891            }
 3892            3 => {
 3893                let position = display_map
 3894                    .clip_point(position, Bias::Left)
 3895                    .to_point(&display_map);
 3896                let line_start = display_map.prev_line_boundary(position).0;
 3897                let next_line_start = buffer.clip_point(
 3898                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3899                    Bias::Left,
 3900                );
 3901                start = buffer.anchor_before(line_start);
 3902                end = buffer.anchor_before(next_line_start);
 3903                mode = SelectMode::Line(start..end);
 3904                auto_scroll = true;
 3905            }
 3906            _ => {
 3907                start = buffer.anchor_before(MultiBufferOffset(0));
 3908                end = buffer.anchor_before(buffer.len());
 3909                mode = SelectMode::All;
 3910                auto_scroll = false;
 3911            }
 3912        }
 3913        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3914
 3915        let point_to_delete: Option<usize> = {
 3916            let selected_points: Vec<Selection<Point>> =
 3917                self.selections.disjoint_in_range(start..end, &display_map);
 3918
 3919            if !add || click_count > 1 {
 3920                None
 3921            } else if !selected_points.is_empty() {
 3922                Some(selected_points[0].id)
 3923            } else {
 3924                let clicked_point_already_selected =
 3925                    self.selections.disjoint_anchors().iter().find(|selection| {
 3926                        selection.start.to_point(buffer) == start.to_point(buffer)
 3927                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3928                    });
 3929
 3930                clicked_point_already_selected.map(|selection| selection.id)
 3931            }
 3932        };
 3933
 3934        let selections_count = self.selections.count();
 3935        let effects = if auto_scroll {
 3936            SelectionEffects::default()
 3937        } else {
 3938            SelectionEffects::no_scroll()
 3939        };
 3940
 3941        self.change_selections(effects, window, cx, |s| {
 3942            if let Some(point_to_delete) = point_to_delete {
 3943                s.delete(point_to_delete);
 3944
 3945                if selections_count == 1 {
 3946                    s.set_pending_anchor_range(start..end, mode);
 3947                }
 3948            } else {
 3949                if !add {
 3950                    s.clear_disjoint();
 3951                }
 3952
 3953                s.set_pending_anchor_range(start..end, mode);
 3954            }
 3955        });
 3956    }
 3957
 3958    fn begin_columnar_selection(
 3959        &mut self,
 3960        position: DisplayPoint,
 3961        goal_column: u32,
 3962        reset: bool,
 3963        mode: ColumnarMode,
 3964        window: &mut Window,
 3965        cx: &mut Context<Self>,
 3966    ) {
 3967        if !self.focus_handle.is_focused(window) {
 3968            self.last_focused_descendant = None;
 3969            window.focus(&self.focus_handle, cx);
 3970        }
 3971
 3972        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3973
 3974        if reset {
 3975            let pointer_position = display_map
 3976                .buffer_snapshot()
 3977                .anchor_before(position.to_point(&display_map));
 3978
 3979            self.change_selections(
 3980                SelectionEffects::scroll(Autoscroll::newest()),
 3981                window,
 3982                cx,
 3983                |s| {
 3984                    s.clear_disjoint();
 3985                    s.set_pending_anchor_range(
 3986                        pointer_position..pointer_position,
 3987                        SelectMode::Character,
 3988                    );
 3989                },
 3990            );
 3991        };
 3992
 3993        let tail = self.selections.newest::<Point>(&display_map).tail();
 3994        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3995        self.columnar_selection_state = match mode {
 3996            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3997                selection_tail: selection_anchor,
 3998                display_point: if reset {
 3999                    if position.column() != goal_column {
 4000                        Some(DisplayPoint::new(position.row(), goal_column))
 4001                    } else {
 4002                        None
 4003                    }
 4004                } else {
 4005                    None
 4006                },
 4007            }),
 4008            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4009                selection_tail: selection_anchor,
 4010            }),
 4011        };
 4012
 4013        if !reset {
 4014            self.select_columns(position, goal_column, &display_map, window, cx);
 4015        }
 4016    }
 4017
 4018    fn update_selection(
 4019        &mut self,
 4020        position: DisplayPoint,
 4021        goal_column: u32,
 4022        scroll_delta: gpui::Point<f32>,
 4023        window: &mut Window,
 4024        cx: &mut Context<Self>,
 4025    ) {
 4026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4027
 4028        if self.columnar_selection_state.is_some() {
 4029            self.select_columns(position, goal_column, &display_map, window, cx);
 4030        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4031            let buffer = display_map.buffer_snapshot();
 4032            let head;
 4033            let tail;
 4034            let mode = self.selections.pending_mode().unwrap();
 4035            match &mode {
 4036                SelectMode::Character => {
 4037                    head = position.to_point(&display_map);
 4038                    tail = pending.tail().to_point(buffer);
 4039                }
 4040                SelectMode::Word(original_range) => {
 4041                    let offset = display_map
 4042                        .clip_point(position, Bias::Left)
 4043                        .to_offset(&display_map, Bias::Left);
 4044                    let original_range = original_range.to_offset(buffer);
 4045
 4046                    let head_offset = if buffer.is_inside_word(offset, None)
 4047                        || original_range.contains(&offset)
 4048                    {
 4049                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4050                        if word_range.start < original_range.start {
 4051                            word_range.start
 4052                        } else {
 4053                            word_range.end
 4054                        }
 4055                    } else {
 4056                        offset
 4057                    };
 4058
 4059                    head = head_offset.to_point(buffer);
 4060                    if head_offset <= original_range.start {
 4061                        tail = original_range.end.to_point(buffer);
 4062                    } else {
 4063                        tail = original_range.start.to_point(buffer);
 4064                    }
 4065                }
 4066                SelectMode::Line(original_range) => {
 4067                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4068
 4069                    let position = display_map
 4070                        .clip_point(position, Bias::Left)
 4071                        .to_point(&display_map);
 4072                    let line_start = display_map.prev_line_boundary(position).0;
 4073                    let next_line_start = buffer.clip_point(
 4074                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4075                        Bias::Left,
 4076                    );
 4077
 4078                    if line_start < original_range.start {
 4079                        head = line_start
 4080                    } else {
 4081                        head = next_line_start
 4082                    }
 4083
 4084                    if head <= original_range.start {
 4085                        tail = original_range.end;
 4086                    } else {
 4087                        tail = original_range.start;
 4088                    }
 4089                }
 4090                SelectMode::All => {
 4091                    return;
 4092                }
 4093            };
 4094
 4095            if head < tail {
 4096                pending.start = buffer.anchor_before(head);
 4097                pending.end = buffer.anchor_before(tail);
 4098                pending.reversed = true;
 4099            } else {
 4100                pending.start = buffer.anchor_before(tail);
 4101                pending.end = buffer.anchor_before(head);
 4102                pending.reversed = false;
 4103            }
 4104
 4105            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4106                s.set_pending(pending.clone(), mode);
 4107            });
 4108        } else {
 4109            log::error!("update_selection dispatched with no pending selection");
 4110            return;
 4111        }
 4112
 4113        self.apply_scroll_delta(scroll_delta, window, cx);
 4114        cx.notify();
 4115    }
 4116
 4117    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4118        self.columnar_selection_state.take();
 4119        if let Some(pending_mode) = self.selections.pending_mode() {
 4120            let selections = self
 4121                .selections
 4122                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4123            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4124                s.select(selections);
 4125                s.clear_pending();
 4126                if s.is_extending() {
 4127                    s.set_is_extending(false);
 4128                } else {
 4129                    s.set_select_mode(pending_mode);
 4130                }
 4131            });
 4132        }
 4133    }
 4134
 4135    fn select_columns(
 4136        &mut self,
 4137        head: DisplayPoint,
 4138        goal_column: u32,
 4139        display_map: &DisplaySnapshot,
 4140        window: &mut Window,
 4141        cx: &mut Context<Self>,
 4142    ) {
 4143        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4144            return;
 4145        };
 4146
 4147        let tail = match columnar_state {
 4148            ColumnarSelectionState::FromMouse {
 4149                selection_tail,
 4150                display_point,
 4151            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4152            ColumnarSelectionState::FromSelection { selection_tail } => {
 4153                selection_tail.to_display_point(display_map)
 4154            }
 4155        };
 4156
 4157        let start_row = cmp::min(tail.row(), head.row());
 4158        let end_row = cmp::max(tail.row(), head.row());
 4159        let start_column = cmp::min(tail.column(), goal_column);
 4160        let end_column = cmp::max(tail.column(), goal_column);
 4161        let reversed = start_column < tail.column();
 4162
 4163        let selection_ranges = (start_row.0..=end_row.0)
 4164            .map(DisplayRow)
 4165            .filter_map(|row| {
 4166                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4167                    || start_column <= display_map.line_len(row))
 4168                    && !display_map.is_block_line(row)
 4169                {
 4170                    let start = display_map
 4171                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4172                        .to_point(display_map);
 4173                    let end = display_map
 4174                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4175                        .to_point(display_map);
 4176                    if reversed {
 4177                        Some(end..start)
 4178                    } else {
 4179                        Some(start..end)
 4180                    }
 4181                } else {
 4182                    None
 4183                }
 4184            })
 4185            .collect::<Vec<_>>();
 4186        if selection_ranges.is_empty() {
 4187            return;
 4188        }
 4189
 4190        let ranges = match columnar_state {
 4191            ColumnarSelectionState::FromMouse { .. } => {
 4192                let mut non_empty_ranges = selection_ranges
 4193                    .iter()
 4194                    .filter(|selection_range| selection_range.start != selection_range.end)
 4195                    .peekable();
 4196                if non_empty_ranges.peek().is_some() {
 4197                    non_empty_ranges.cloned().collect()
 4198                } else {
 4199                    selection_ranges
 4200                }
 4201            }
 4202            _ => selection_ranges,
 4203        };
 4204
 4205        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4206            s.select_ranges(ranges);
 4207        });
 4208        cx.notify();
 4209    }
 4210
 4211    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4212        self.selections
 4213            .all_adjusted(snapshot)
 4214            .iter()
 4215            .any(|selection| !selection.is_empty())
 4216    }
 4217
 4218    pub fn has_pending_nonempty_selection(&self) -> bool {
 4219        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4220            Some(Selection { start, end, .. }) => start != end,
 4221            None => false,
 4222        };
 4223
 4224        pending_nonempty_selection
 4225            || (self.columnar_selection_state.is_some()
 4226                && self.selections.disjoint_anchors().len() > 1)
 4227    }
 4228
 4229    pub fn has_pending_selection(&self) -> bool {
 4230        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4231    }
 4232
 4233    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4234        self.selection_mark_mode = false;
 4235        self.selection_drag_state = SelectionDragState::None;
 4236
 4237        if self.dismiss_menus_and_popups(true, window, cx) {
 4238            cx.notify();
 4239            return;
 4240        }
 4241        if self.clear_expanded_diff_hunks(cx) {
 4242            cx.notify();
 4243            return;
 4244        }
 4245        if self.show_git_blame_gutter {
 4246            self.show_git_blame_gutter = false;
 4247            cx.notify();
 4248            return;
 4249        }
 4250
 4251        if self.mode.is_full()
 4252            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4253        {
 4254            cx.notify();
 4255            return;
 4256        }
 4257
 4258        cx.propagate();
 4259    }
 4260
 4261    pub fn dismiss_menus_and_popups(
 4262        &mut self,
 4263        is_user_requested: bool,
 4264        window: &mut Window,
 4265        cx: &mut Context<Self>,
 4266    ) -> bool {
 4267        let mut dismissed = false;
 4268
 4269        dismissed |= self.take_rename(false, window, cx).is_some();
 4270        dismissed |= self.hide_blame_popover(true, cx);
 4271        dismissed |= hide_hover(self, cx);
 4272        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4273        dismissed |= self.hide_context_menu(window, cx).is_some();
 4274        dismissed |= self.mouse_context_menu.take().is_some();
 4275        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4276        dismissed |= self.snippet_stack.pop().is_some();
 4277
 4278        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4279            self.dismiss_diagnostics(cx);
 4280            dismissed = true;
 4281        }
 4282
 4283        dismissed
 4284    }
 4285
 4286    fn linked_editing_ranges_for(
 4287        &self,
 4288        selection: Range<text::Anchor>,
 4289        cx: &App,
 4290    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4291        if self.linked_edit_ranges.is_empty() {
 4292            return None;
 4293        }
 4294        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4295            selection.end.buffer_id.and_then(|end_buffer_id| {
 4296                if selection.start.buffer_id != Some(end_buffer_id) {
 4297                    return None;
 4298                }
 4299                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4300                let snapshot = buffer.read(cx).snapshot();
 4301                self.linked_edit_ranges
 4302                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4303                    .map(|ranges| (ranges, snapshot, buffer))
 4304            })?;
 4305        use text::ToOffset as TO;
 4306        // find offset from the start of current range to current cursor position
 4307        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4308
 4309        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4310        let start_difference = start_offset - start_byte_offset;
 4311        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4312        let end_difference = end_offset - start_byte_offset;
 4313        // Current range has associated linked ranges.
 4314        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4315        for range in linked_ranges.iter() {
 4316            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4317            let end_offset = start_offset + end_difference;
 4318            let start_offset = start_offset + start_difference;
 4319            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4320                continue;
 4321            }
 4322            if self.selections.disjoint_anchor_ranges().any(|s| {
 4323                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4324                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4325                {
 4326                    return false;
 4327                }
 4328                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4329                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4330            }) {
 4331                continue;
 4332            }
 4333            let start = buffer_snapshot.anchor_after(start_offset);
 4334            let end = buffer_snapshot.anchor_after(end_offset);
 4335            linked_edits
 4336                .entry(buffer.clone())
 4337                .or_default()
 4338                .push(start..end);
 4339        }
 4340        Some(linked_edits)
 4341    }
 4342
 4343    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4344        let text: Arc<str> = text.into();
 4345
 4346        if self.read_only(cx) {
 4347            return;
 4348        }
 4349
 4350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4351
 4352        self.unfold_buffers_with_selections(cx);
 4353
 4354        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4355        let mut bracket_inserted = false;
 4356        let mut edits = Vec::new();
 4357        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4358        let mut new_selections = Vec::with_capacity(selections.len());
 4359        let mut new_autoclose_regions = Vec::new();
 4360        let snapshot = self.buffer.read(cx).read(cx);
 4361        let mut clear_linked_edit_ranges = false;
 4362        let mut all_selections_read_only = true;
 4363        let mut has_adjacent_edits = false;
 4364        let mut in_adjacent_group = false;
 4365
 4366        let mut regions = self
 4367            .selections_with_autoclose_regions(selections, &snapshot)
 4368            .peekable();
 4369
 4370        while let Some((selection, autoclose_region)) = regions.next() {
 4371            if snapshot
 4372                .point_to_buffer_point(selection.head())
 4373                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4374            {
 4375                continue;
 4376            }
 4377            if snapshot
 4378                .point_to_buffer_point(selection.tail())
 4379                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4380            {
 4381                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4382                continue;
 4383            }
 4384            all_selections_read_only = false;
 4385
 4386            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4387                // Determine if the inserted text matches the opening or closing
 4388                // bracket of any of this language's bracket pairs.
 4389                let mut bracket_pair = None;
 4390                let mut is_bracket_pair_start = false;
 4391                let mut is_bracket_pair_end = false;
 4392                if !text.is_empty() {
 4393                    let mut bracket_pair_matching_end = None;
 4394                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4395                    //  and they are removing the character that triggered IME popup.
 4396                    for (pair, enabled) in scope.brackets() {
 4397                        if !pair.close && !pair.surround {
 4398                            continue;
 4399                        }
 4400
 4401                        if enabled && pair.start.ends_with(text.as_ref()) {
 4402                            let prefix_len = pair.start.len() - text.len();
 4403                            let preceding_text_matches_prefix = prefix_len == 0
 4404                                || (selection.start.column >= (prefix_len as u32)
 4405                                    && snapshot.contains_str_at(
 4406                                        Point::new(
 4407                                            selection.start.row,
 4408                                            selection.start.column - (prefix_len as u32),
 4409                                        ),
 4410                                        &pair.start[..prefix_len],
 4411                                    ));
 4412                            if preceding_text_matches_prefix {
 4413                                bracket_pair = Some(pair.clone());
 4414                                is_bracket_pair_start = true;
 4415                                break;
 4416                            }
 4417                        }
 4418                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4419                        {
 4420                            // take first bracket pair matching end, but don't break in case a later bracket
 4421                            // pair matches start
 4422                            bracket_pair_matching_end = Some(pair.clone());
 4423                        }
 4424                    }
 4425                    if let Some(end) = bracket_pair_matching_end
 4426                        && bracket_pair.is_none()
 4427                    {
 4428                        bracket_pair = Some(end);
 4429                        is_bracket_pair_end = true;
 4430                    }
 4431                }
 4432
 4433                if let Some(bracket_pair) = bracket_pair {
 4434                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4435                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4436                    let auto_surround =
 4437                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4438                    if selection.is_empty() {
 4439                        if is_bracket_pair_start {
 4440                            // If the inserted text is a suffix of an opening bracket and the
 4441                            // selection is preceded by the rest of the opening bracket, then
 4442                            // insert the closing bracket.
 4443                            let following_text_allows_autoclose = snapshot
 4444                                .chars_at(selection.start)
 4445                                .next()
 4446                                .is_none_or(|c| scope.should_autoclose_before(c));
 4447
 4448                            let preceding_text_allows_autoclose = selection.start.column == 0
 4449                                || snapshot
 4450                                    .reversed_chars_at(selection.start)
 4451                                    .next()
 4452                                    .is_none_or(|c| {
 4453                                        bracket_pair.start != bracket_pair.end
 4454                                            || !snapshot
 4455                                                .char_classifier_at(selection.start)
 4456                                                .is_word(c)
 4457                                    });
 4458
 4459                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4460                                && bracket_pair.start.len() == 1
 4461                            {
 4462                                let target = bracket_pair.start.chars().next().unwrap();
 4463                                let mut byte_offset = 0u32;
 4464                                let current_line_count = snapshot
 4465                                    .reversed_chars_at(selection.start)
 4466                                    .take_while(|&c| c != '\n')
 4467                                    .filter(|c| {
 4468                                        byte_offset += c.len_utf8() as u32;
 4469                                        if *c != target {
 4470                                            return false;
 4471                                        }
 4472
 4473                                        let point = Point::new(
 4474                                            selection.start.row,
 4475                                            selection.start.column.saturating_sub(byte_offset),
 4476                                        );
 4477
 4478                                        let is_enabled = snapshot
 4479                                            .language_scope_at(point)
 4480                                            .and_then(|scope| {
 4481                                                scope
 4482                                                    .brackets()
 4483                                                    .find(|(pair, _)| {
 4484                                                        pair.start == bracket_pair.start
 4485                                                    })
 4486                                                    .map(|(_, enabled)| enabled)
 4487                                            })
 4488                                            .unwrap_or(true);
 4489
 4490                                        let is_delimiter = snapshot
 4491                                            .language_scope_at(Point::new(
 4492                                                point.row,
 4493                                                point.column + 1,
 4494                                            ))
 4495                                            .and_then(|scope| {
 4496                                                scope
 4497                                                    .brackets()
 4498                                                    .find(|(pair, _)| {
 4499                                                        pair.start == bracket_pair.start
 4500                                                    })
 4501                                                    .map(|(_, enabled)| !enabled)
 4502                                            })
 4503                                            .unwrap_or(false);
 4504
 4505                                        is_enabled && !is_delimiter
 4506                                    })
 4507                                    .count();
 4508                                current_line_count % 2 == 1
 4509                            } else {
 4510                                false
 4511                            };
 4512
 4513                            if autoclose
 4514                                && bracket_pair.close
 4515                                && following_text_allows_autoclose
 4516                                && preceding_text_allows_autoclose
 4517                                && !is_closing_quote
 4518                            {
 4519                                let anchor = snapshot.anchor_before(selection.end);
 4520                                new_selections.push((selection.map(|_| anchor), text.len()));
 4521                                new_autoclose_regions.push((
 4522                                    anchor,
 4523                                    text.len(),
 4524                                    selection.id,
 4525                                    bracket_pair.clone(),
 4526                                ));
 4527                                edits.push((
 4528                                    selection.range(),
 4529                                    format!("{}{}", text, bracket_pair.end).into(),
 4530                                ));
 4531                                bracket_inserted = true;
 4532                                continue;
 4533                            }
 4534                        }
 4535
 4536                        if let Some(region) = autoclose_region {
 4537                            // If the selection is followed by an auto-inserted closing bracket,
 4538                            // then don't insert that closing bracket again; just move the selection
 4539                            // past the closing bracket.
 4540                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4541                                && text.as_ref() == region.pair.end.as_str()
 4542                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4543                            if should_skip {
 4544                                let anchor = snapshot.anchor_after(selection.end);
 4545                                new_selections
 4546                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4547                                continue;
 4548                            }
 4549                        }
 4550
 4551                        let always_treat_brackets_as_autoclosed = snapshot
 4552                            .language_settings_at(selection.start, cx)
 4553                            .always_treat_brackets_as_autoclosed;
 4554                        if always_treat_brackets_as_autoclosed
 4555                            && is_bracket_pair_end
 4556                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4557                        {
 4558                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4559                            // and the inserted text is a closing bracket and the selection is followed
 4560                            // by the closing bracket then move the selection past the closing bracket.
 4561                            let anchor = snapshot.anchor_after(selection.end);
 4562                            new_selections.push((selection.map(|_| anchor), text.len()));
 4563                            continue;
 4564                        }
 4565                    }
 4566                    // If an opening bracket is 1 character long and is typed while
 4567                    // text is selected, then surround that text with the bracket pair.
 4568                    else if auto_surround
 4569                        && bracket_pair.surround
 4570                        && is_bracket_pair_start
 4571                        && bracket_pair.start.chars().count() == 1
 4572                    {
 4573                        edits.push((selection.start..selection.start, text.clone()));
 4574                        edits.push((
 4575                            selection.end..selection.end,
 4576                            bracket_pair.end.as_str().into(),
 4577                        ));
 4578                        bracket_inserted = true;
 4579                        new_selections.push((
 4580                            Selection {
 4581                                id: selection.id,
 4582                                start: snapshot.anchor_after(selection.start),
 4583                                end: snapshot.anchor_before(selection.end),
 4584                                reversed: selection.reversed,
 4585                                goal: selection.goal,
 4586                            },
 4587                            0,
 4588                        ));
 4589                        continue;
 4590                    }
 4591                }
 4592            }
 4593
 4594            if self.auto_replace_emoji_shortcode
 4595                && selection.is_empty()
 4596                && text.as_ref().ends_with(':')
 4597                && let Some(possible_emoji_short_code) =
 4598                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4599                && !possible_emoji_short_code.is_empty()
 4600                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4601            {
 4602                let emoji_shortcode_start = Point::new(
 4603                    selection.start.row,
 4604                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4605                );
 4606
 4607                // Remove shortcode from buffer
 4608                edits.push((
 4609                    emoji_shortcode_start..selection.start,
 4610                    "".to_string().into(),
 4611                ));
 4612                new_selections.push((
 4613                    Selection {
 4614                        id: selection.id,
 4615                        start: snapshot.anchor_after(emoji_shortcode_start),
 4616                        end: snapshot.anchor_before(selection.start),
 4617                        reversed: selection.reversed,
 4618                        goal: selection.goal,
 4619                    },
 4620                    0,
 4621                ));
 4622
 4623                // Insert emoji
 4624                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4625                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4626                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4627
 4628                continue;
 4629            }
 4630
 4631            let next_is_adjacent = regions
 4632                .peek()
 4633                .is_some_and(|(next, _)| selection.end == next.start);
 4634
 4635            // If not handling any auto-close operation, then just replace the selected
 4636            // text with the given input and move the selection to the end of the
 4637            // newly inserted text.
 4638            let anchor = if in_adjacent_group || next_is_adjacent {
 4639                // After edits the right bias would shift those anchor to the next visible fragment
 4640                // but we want to resolve to the previous one
 4641                snapshot.anchor_before(selection.end)
 4642            } else {
 4643                snapshot.anchor_after(selection.end)
 4644            };
 4645
 4646            if !self.linked_edit_ranges.is_empty() {
 4647                let start_anchor = snapshot.anchor_before(selection.start);
 4648
 4649                let is_word_char = text.chars().next().is_none_or(|char| {
 4650                    let classifier = snapshot
 4651                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4652                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4653                    classifier.is_word(char)
 4654                });
 4655
 4656                if is_word_char {
 4657                    if let Some(ranges) = self
 4658                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4659                    {
 4660                        for (buffer, edits) in ranges {
 4661                            linked_edits
 4662                                .entry(buffer.clone())
 4663                                .or_default()
 4664                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4665                        }
 4666                    }
 4667                } else {
 4668                    clear_linked_edit_ranges = true;
 4669                }
 4670            }
 4671
 4672            new_selections.push((selection.map(|_| anchor), 0));
 4673            edits.push((selection.start..selection.end, text.clone()));
 4674
 4675            has_adjacent_edits |= next_is_adjacent;
 4676            in_adjacent_group = next_is_adjacent;
 4677        }
 4678
 4679        if all_selections_read_only {
 4680            return;
 4681        }
 4682
 4683        drop(regions);
 4684        drop(snapshot);
 4685
 4686        self.transact(window, cx, |this, window, cx| {
 4687            if clear_linked_edit_ranges {
 4688                this.linked_edit_ranges.clear();
 4689            }
 4690            let initial_buffer_versions =
 4691                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4692
 4693            this.buffer.update(cx, |buffer, cx| {
 4694                if has_adjacent_edits {
 4695                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4696                } else {
 4697                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4698                }
 4699            });
 4700            for (buffer, edits) in linked_edits {
 4701                buffer.update(cx, |buffer, cx| {
 4702                    let snapshot = buffer.snapshot();
 4703                    let edits = edits
 4704                        .into_iter()
 4705                        .map(|(range, text)| {
 4706                            use text::ToPoint as TP;
 4707                            let end_point = TP::to_point(&range.end, &snapshot);
 4708                            let start_point = TP::to_point(&range.start, &snapshot);
 4709                            (start_point..end_point, text)
 4710                        })
 4711                        .sorted_by_key(|(range, _)| range.start);
 4712                    buffer.edit(edits, None, cx);
 4713                })
 4714            }
 4715            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4716            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4717            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4718            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4719                new_anchor_selections,
 4720                &map,
 4721            )
 4722            .zip(new_selection_deltas)
 4723            .map(|(selection, delta)| Selection {
 4724                id: selection.id,
 4725                start: selection.start + delta,
 4726                end: selection.end + delta,
 4727                reversed: selection.reversed,
 4728                goal: SelectionGoal::None,
 4729            })
 4730            .collect::<Vec<_>>();
 4731
 4732            let mut i = 0;
 4733            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4734                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4735                let start = map.buffer_snapshot().anchor_before(position);
 4736                let end = map.buffer_snapshot().anchor_after(position);
 4737                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4738                    match existing_state
 4739                        .range
 4740                        .start
 4741                        .cmp(&start, map.buffer_snapshot())
 4742                    {
 4743                        Ordering::Less => i += 1,
 4744                        Ordering::Greater => break,
 4745                        Ordering::Equal => {
 4746                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4747                                Ordering::Less => i += 1,
 4748                                Ordering::Equal => break,
 4749                                Ordering::Greater => break,
 4750                            }
 4751                        }
 4752                    }
 4753                }
 4754                this.autoclose_regions.insert(
 4755                    i,
 4756                    AutocloseRegion {
 4757                        selection_id,
 4758                        range: start..end,
 4759                        pair,
 4760                    },
 4761                );
 4762            }
 4763
 4764            let had_active_edit_prediction = this.has_active_edit_prediction();
 4765            this.change_selections(
 4766                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4767                window,
 4768                cx,
 4769                |s| s.select(new_selections),
 4770            );
 4771
 4772            if !bracket_inserted
 4773                && let Some(on_type_format_task) =
 4774                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4775            {
 4776                on_type_format_task.detach_and_log_err(cx);
 4777            }
 4778
 4779            let editor_settings = EditorSettings::get_global(cx);
 4780            if bracket_inserted
 4781                && (editor_settings.auto_signature_help
 4782                    || editor_settings.show_signature_help_after_edits)
 4783            {
 4784                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4785            }
 4786
 4787            let trigger_in_words =
 4788                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4789            if this.hard_wrap.is_some() {
 4790                let latest: Range<Point> = this.selections.newest(&map).range();
 4791                if latest.is_empty()
 4792                    && this
 4793                        .buffer()
 4794                        .read(cx)
 4795                        .snapshot(cx)
 4796                        .line_len(MultiBufferRow(latest.start.row))
 4797                        == latest.start.column
 4798                {
 4799                    this.rewrap_impl(
 4800                        RewrapOptions {
 4801                            override_language_settings: true,
 4802                            preserve_existing_whitespace: true,
 4803                        },
 4804                        cx,
 4805                    )
 4806                }
 4807            }
 4808            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4809            refresh_linked_ranges(this, window, cx);
 4810            this.refresh_edit_prediction(true, false, window, cx);
 4811            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4812        });
 4813    }
 4814
 4815    fn find_possible_emoji_shortcode_at_position(
 4816        snapshot: &MultiBufferSnapshot,
 4817        position: Point,
 4818    ) -> Option<String> {
 4819        let mut chars = Vec::new();
 4820        let mut found_colon = false;
 4821        for char in snapshot.reversed_chars_at(position).take(100) {
 4822            // Found a possible emoji shortcode in the middle of the buffer
 4823            if found_colon {
 4824                if char.is_whitespace() {
 4825                    chars.reverse();
 4826                    return Some(chars.iter().collect());
 4827                }
 4828                // If the previous character is not a whitespace, we are in the middle of a word
 4829                // and we only want to complete the shortcode if the word is made up of other emojis
 4830                let mut containing_word = String::new();
 4831                for ch in snapshot
 4832                    .reversed_chars_at(position)
 4833                    .skip(chars.len() + 1)
 4834                    .take(100)
 4835                {
 4836                    if ch.is_whitespace() {
 4837                        break;
 4838                    }
 4839                    containing_word.push(ch);
 4840                }
 4841                let containing_word = containing_word.chars().rev().collect::<String>();
 4842                if util::word_consists_of_emojis(containing_word.as_str()) {
 4843                    chars.reverse();
 4844                    return Some(chars.iter().collect());
 4845                }
 4846            }
 4847
 4848            if char.is_whitespace() || !char.is_ascii() {
 4849                return None;
 4850            }
 4851            if char == ':' {
 4852                found_colon = true;
 4853            } else {
 4854                chars.push(char);
 4855            }
 4856        }
 4857        // Found a possible emoji shortcode at the beginning of the buffer
 4858        chars.reverse();
 4859        Some(chars.iter().collect())
 4860    }
 4861
 4862    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4864        self.transact(window, cx, |this, window, cx| {
 4865            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4866                let selections = this
 4867                    .selections
 4868                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4869                let multi_buffer = this.buffer.read(cx);
 4870                let buffer = multi_buffer.snapshot(cx);
 4871                selections
 4872                    .iter()
 4873                    .map(|selection| {
 4874                        let start_point = selection.start.to_point(&buffer);
 4875                        let mut existing_indent =
 4876                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4877                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4878                        let start = selection.start;
 4879                        let end = selection.end;
 4880                        let selection_is_empty = start == end;
 4881                        let language_scope = buffer.language_scope_at(start);
 4882                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4883                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4884                                &buffer,
 4885                                start..end,
 4886                                language,
 4887                            )
 4888                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4889                                    &buffer,
 4890                                    start..end,
 4891                                );
 4892
 4893                            let mut newline_config = NewlineConfig::Newline {
 4894                                additional_indent: IndentSize::spaces(0),
 4895                                extra_line_additional_indent: if needs_extra_newline {
 4896                                    Some(IndentSize::spaces(0))
 4897                                } else {
 4898                                    None
 4899                                },
 4900                                prevent_auto_indent: false,
 4901                            };
 4902
 4903                            let comment_delimiter = maybe!({
 4904                                if !selection_is_empty {
 4905                                    return None;
 4906                                }
 4907
 4908                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4909                                    return None;
 4910                                }
 4911
 4912                                return comment_delimiter_for_newline(
 4913                                    &start_point,
 4914                                    &buffer,
 4915                                    language,
 4916                                );
 4917                            });
 4918
 4919                            let doc_delimiter = maybe!({
 4920                                if !selection_is_empty {
 4921                                    return None;
 4922                                }
 4923
 4924                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4925                                    return None;
 4926                                }
 4927
 4928                                return documentation_delimiter_for_newline(
 4929                                    &start_point,
 4930                                    &buffer,
 4931                                    language,
 4932                                    &mut newline_config,
 4933                                );
 4934                            });
 4935
 4936                            let list_delimiter = maybe!({
 4937                                if !selection_is_empty {
 4938                                    return None;
 4939                                }
 4940
 4941                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 4942                                    return None;
 4943                                }
 4944
 4945                                return list_delimiter_for_newline(
 4946                                    &start_point,
 4947                                    &buffer,
 4948                                    language,
 4949                                    &mut newline_config,
 4950                                );
 4951                            });
 4952
 4953                            (
 4954                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 4955                                newline_config,
 4956                            )
 4957                        } else {
 4958                            (
 4959                                None,
 4960                                NewlineConfig::Newline {
 4961                                    additional_indent: IndentSize::spaces(0),
 4962                                    extra_line_additional_indent: None,
 4963                                    prevent_auto_indent: false,
 4964                                },
 4965                            )
 4966                        };
 4967
 4968                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 4969                            NewlineConfig::ClearCurrentLine => {
 4970                                let row_start =
 4971                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4972                                (row_start, String::new(), false)
 4973                            }
 4974                            NewlineConfig::UnindentCurrentLine { continuation } => {
 4975                                let row_start =
 4976                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4977                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 4978                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 4979                                let reduced_indent =
 4980                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 4981                                let mut new_text = String::new();
 4982                                new_text.extend(reduced_indent.chars());
 4983                                new_text.push_str(continuation);
 4984                                (row_start, new_text, true)
 4985                            }
 4986                            NewlineConfig::Newline {
 4987                                additional_indent,
 4988                                extra_line_additional_indent,
 4989                                prevent_auto_indent,
 4990                            } => {
 4991                                let capacity_for_delimiter =
 4992                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 4993                                let extra_line_len = extra_line_additional_indent
 4994                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 4995                                    .unwrap_or(0);
 4996                                let mut new_text = String::with_capacity(
 4997                                    1 + capacity_for_delimiter
 4998                                        + existing_indent.len as usize
 4999                                        + additional_indent.len as usize
 5000                                        + extra_line_len,
 5001                                );
 5002                                new_text.push('\n');
 5003                                new_text.extend(existing_indent.chars());
 5004                                new_text.extend(additional_indent.chars());
 5005                                if let Some(delimiter) = &delimiter {
 5006                                    new_text.push_str(delimiter);
 5007                                }
 5008                                if let Some(extra_indent) = extra_line_additional_indent {
 5009                                    new_text.push('\n');
 5010                                    new_text.extend(existing_indent.chars());
 5011                                    new_text.extend(extra_indent.chars());
 5012                                }
 5013                                (start, new_text, *prevent_auto_indent)
 5014                            }
 5015                        };
 5016
 5017                        let anchor = buffer.anchor_after(end);
 5018                        let new_selection = selection.map(|_| anchor);
 5019                        (
 5020                            ((edit_start..end, new_text), prevent_auto_indent),
 5021                            (newline_config.has_extra_line(), new_selection),
 5022                        )
 5023                    })
 5024                    .unzip()
 5025            };
 5026
 5027            let mut auto_indent_edits = Vec::new();
 5028            let mut edits = Vec::new();
 5029            for (edit, prevent_auto_indent) in edits_with_flags {
 5030                if prevent_auto_indent {
 5031                    edits.push(edit);
 5032                } else {
 5033                    auto_indent_edits.push(edit);
 5034                }
 5035            }
 5036            if !edits.is_empty() {
 5037                this.edit(edits, cx);
 5038            }
 5039            if !auto_indent_edits.is_empty() {
 5040                this.edit_with_autoindent(auto_indent_edits, cx);
 5041            }
 5042
 5043            let buffer = this.buffer.read(cx).snapshot(cx);
 5044            let new_selections = selection_info
 5045                .into_iter()
 5046                .map(|(extra_newline_inserted, new_selection)| {
 5047                    let mut cursor = new_selection.end.to_point(&buffer);
 5048                    if extra_newline_inserted {
 5049                        cursor.row -= 1;
 5050                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5051                    }
 5052                    new_selection.map(|_| cursor)
 5053                })
 5054                .collect();
 5055
 5056            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5057            this.refresh_edit_prediction(true, false, window, cx);
 5058            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5059                task.detach_and_log_err(cx);
 5060            }
 5061        });
 5062    }
 5063
 5064    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5065        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5066
 5067        let buffer = self.buffer.read(cx);
 5068        let snapshot = buffer.snapshot(cx);
 5069
 5070        let mut edits = Vec::new();
 5071        let mut rows = Vec::new();
 5072
 5073        for (rows_inserted, selection) in self
 5074            .selections
 5075            .all_adjusted(&self.display_snapshot(cx))
 5076            .into_iter()
 5077            .enumerate()
 5078        {
 5079            let cursor = selection.head();
 5080            let row = cursor.row;
 5081
 5082            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5083
 5084            let newline = "\n".to_string();
 5085            edits.push((start_of_line..start_of_line, newline));
 5086
 5087            rows.push(row + rows_inserted as u32);
 5088        }
 5089
 5090        self.transact(window, cx, |editor, window, cx| {
 5091            editor.edit(edits, cx);
 5092
 5093            editor.change_selections(Default::default(), window, cx, |s| {
 5094                let mut index = 0;
 5095                s.move_cursors_with(|map, _, _| {
 5096                    let row = rows[index];
 5097                    index += 1;
 5098
 5099                    let point = Point::new(row, 0);
 5100                    let boundary = map.next_line_boundary(point).1;
 5101                    let clipped = map.clip_point(boundary, Bias::Left);
 5102
 5103                    (clipped, SelectionGoal::None)
 5104                });
 5105            });
 5106
 5107            let mut indent_edits = Vec::new();
 5108            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5109            for row in rows {
 5110                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5111                for (row, indent) in indents {
 5112                    if indent.len == 0 {
 5113                        continue;
 5114                    }
 5115
 5116                    let text = match indent.kind {
 5117                        IndentKind::Space => " ".repeat(indent.len as usize),
 5118                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5119                    };
 5120                    let point = Point::new(row.0, 0);
 5121                    indent_edits.push((point..point, text));
 5122                }
 5123            }
 5124            editor.edit(indent_edits, cx);
 5125            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5126                format.detach_and_log_err(cx);
 5127            }
 5128        });
 5129    }
 5130
 5131    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5133
 5134        let buffer = self.buffer.read(cx);
 5135        let snapshot = buffer.snapshot(cx);
 5136
 5137        let mut edits = Vec::new();
 5138        let mut rows = Vec::new();
 5139        let mut rows_inserted = 0;
 5140
 5141        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5142            let cursor = selection.head();
 5143            let row = cursor.row;
 5144
 5145            let point = Point::new(row + 1, 0);
 5146            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5147
 5148            let newline = "\n".to_string();
 5149            edits.push((start_of_line..start_of_line, newline));
 5150
 5151            rows_inserted += 1;
 5152            rows.push(row + rows_inserted);
 5153        }
 5154
 5155        self.transact(window, cx, |editor, window, cx| {
 5156            editor.edit(edits, cx);
 5157
 5158            editor.change_selections(Default::default(), window, cx, |s| {
 5159                let mut index = 0;
 5160                s.move_cursors_with(|map, _, _| {
 5161                    let row = rows[index];
 5162                    index += 1;
 5163
 5164                    let point = Point::new(row, 0);
 5165                    let boundary = map.next_line_boundary(point).1;
 5166                    let clipped = map.clip_point(boundary, Bias::Left);
 5167
 5168                    (clipped, SelectionGoal::None)
 5169                });
 5170            });
 5171
 5172            let mut indent_edits = Vec::new();
 5173            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5174            for row in rows {
 5175                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5176                for (row, indent) in indents {
 5177                    if indent.len == 0 {
 5178                        continue;
 5179                    }
 5180
 5181                    let text = match indent.kind {
 5182                        IndentKind::Space => " ".repeat(indent.len as usize),
 5183                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5184                    };
 5185                    let point = Point::new(row.0, 0);
 5186                    indent_edits.push((point..point, text));
 5187                }
 5188            }
 5189            editor.edit(indent_edits, cx);
 5190            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5191                format.detach_and_log_err(cx);
 5192            }
 5193        });
 5194    }
 5195
 5196    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5197        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5198            original_indent_columns: Vec::new(),
 5199        });
 5200        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5201    }
 5202
 5203    fn insert_with_autoindent_mode(
 5204        &mut self,
 5205        text: &str,
 5206        autoindent_mode: Option<AutoindentMode>,
 5207        window: &mut Window,
 5208        cx: &mut Context<Self>,
 5209    ) {
 5210        if self.read_only(cx) {
 5211            return;
 5212        }
 5213
 5214        let text: Arc<str> = text.into();
 5215        self.transact(window, cx, |this, window, cx| {
 5216            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5217            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5218                let anchors = {
 5219                    let snapshot = buffer.read(cx);
 5220                    old_selections
 5221                        .iter()
 5222                        .map(|s| {
 5223                            let anchor = snapshot.anchor_after(s.head());
 5224                            s.map(|_| anchor)
 5225                        })
 5226                        .collect::<Vec<_>>()
 5227                };
 5228                buffer.edit(
 5229                    old_selections
 5230                        .iter()
 5231                        .map(|s| (s.start..s.end, text.clone())),
 5232                    autoindent_mode,
 5233                    cx,
 5234                );
 5235                anchors
 5236            });
 5237
 5238            this.change_selections(Default::default(), window, cx, |s| {
 5239                s.select_anchors(selection_anchors);
 5240            });
 5241
 5242            cx.notify();
 5243        });
 5244    }
 5245
 5246    fn trigger_completion_on_input(
 5247        &mut self,
 5248        text: &str,
 5249        trigger_in_words: bool,
 5250        window: &mut Window,
 5251        cx: &mut Context<Self>,
 5252    ) {
 5253        let completions_source = self
 5254            .context_menu
 5255            .borrow()
 5256            .as_ref()
 5257            .and_then(|menu| match menu {
 5258                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5259                CodeContextMenu::CodeActions(_) => None,
 5260            });
 5261
 5262        match completions_source {
 5263            Some(CompletionsMenuSource::Words { .. }) => {
 5264                self.open_or_update_completions_menu(
 5265                    Some(CompletionsMenuSource::Words {
 5266                        ignore_threshold: false,
 5267                    }),
 5268                    None,
 5269                    trigger_in_words,
 5270                    window,
 5271                    cx,
 5272                );
 5273            }
 5274            _ => self.open_or_update_completions_menu(
 5275                None,
 5276                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5277                true,
 5278                window,
 5279                cx,
 5280            ),
 5281        }
 5282    }
 5283
 5284    /// If any empty selections is touching the start of its innermost containing autoclose
 5285    /// region, expand it to select the brackets.
 5286    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5287        let selections = self
 5288            .selections
 5289            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5290        let buffer = self.buffer.read(cx).read(cx);
 5291        let new_selections = self
 5292            .selections_with_autoclose_regions(selections, &buffer)
 5293            .map(|(mut selection, region)| {
 5294                if !selection.is_empty() {
 5295                    return selection;
 5296                }
 5297
 5298                if let Some(region) = region {
 5299                    let mut range = region.range.to_offset(&buffer);
 5300                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5301                        range.start -= region.pair.start.len();
 5302                        if buffer.contains_str_at(range.start, &region.pair.start)
 5303                            && buffer.contains_str_at(range.end, &region.pair.end)
 5304                        {
 5305                            range.end += region.pair.end.len();
 5306                            selection.start = range.start;
 5307                            selection.end = range.end;
 5308
 5309                            return selection;
 5310                        }
 5311                    }
 5312                }
 5313
 5314                let always_treat_brackets_as_autoclosed = buffer
 5315                    .language_settings_at(selection.start, cx)
 5316                    .always_treat_brackets_as_autoclosed;
 5317
 5318                if !always_treat_brackets_as_autoclosed {
 5319                    return selection;
 5320                }
 5321
 5322                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5323                    for (pair, enabled) in scope.brackets() {
 5324                        if !enabled || !pair.close {
 5325                            continue;
 5326                        }
 5327
 5328                        if buffer.contains_str_at(selection.start, &pair.end) {
 5329                            let pair_start_len = pair.start.len();
 5330                            if buffer.contains_str_at(
 5331                                selection.start.saturating_sub_usize(pair_start_len),
 5332                                &pair.start,
 5333                            ) {
 5334                                selection.start -= pair_start_len;
 5335                                selection.end += pair.end.len();
 5336
 5337                                return selection;
 5338                            }
 5339                        }
 5340                    }
 5341                }
 5342
 5343                selection
 5344            })
 5345            .collect();
 5346
 5347        drop(buffer);
 5348        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5349            selections.select(new_selections)
 5350        });
 5351    }
 5352
 5353    /// Iterate the given selections, and for each one, find the smallest surrounding
 5354    /// autoclose region. This uses the ordering of the selections and the autoclose
 5355    /// regions to avoid repeated comparisons.
 5356    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5357        &'a self,
 5358        selections: impl IntoIterator<Item = Selection<D>>,
 5359        buffer: &'a MultiBufferSnapshot,
 5360    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5361        let mut i = 0;
 5362        let mut regions = self.autoclose_regions.as_slice();
 5363        selections.into_iter().map(move |selection| {
 5364            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5365
 5366            let mut enclosing = None;
 5367            while let Some(pair_state) = regions.get(i) {
 5368                if pair_state.range.end.to_offset(buffer) < range.start {
 5369                    regions = &regions[i + 1..];
 5370                    i = 0;
 5371                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5372                    break;
 5373                } else {
 5374                    if pair_state.selection_id == selection.id {
 5375                        enclosing = Some(pair_state);
 5376                    }
 5377                    i += 1;
 5378                }
 5379            }
 5380
 5381            (selection, enclosing)
 5382        })
 5383    }
 5384
 5385    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5386    fn invalidate_autoclose_regions(
 5387        &mut self,
 5388        mut selections: &[Selection<Anchor>],
 5389        buffer: &MultiBufferSnapshot,
 5390    ) {
 5391        self.autoclose_regions.retain(|state| {
 5392            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5393                return false;
 5394            }
 5395
 5396            let mut i = 0;
 5397            while let Some(selection) = selections.get(i) {
 5398                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5399                    selections = &selections[1..];
 5400                    continue;
 5401                }
 5402                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5403                    break;
 5404                }
 5405                if selection.id == state.selection_id {
 5406                    return true;
 5407                } else {
 5408                    i += 1;
 5409                }
 5410            }
 5411            false
 5412        });
 5413    }
 5414
 5415    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5416        let offset = position.to_offset(buffer);
 5417        let (word_range, kind) =
 5418            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5419        if offset > word_range.start && kind == Some(CharKind::Word) {
 5420            Some(
 5421                buffer
 5422                    .text_for_range(word_range.start..offset)
 5423                    .collect::<String>(),
 5424            )
 5425        } else {
 5426            None
 5427        }
 5428    }
 5429
 5430    pub fn visible_excerpts(
 5431        &self,
 5432        lsp_related_only: bool,
 5433        cx: &mut Context<Editor>,
 5434    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5435        let project = self.project().cloned();
 5436        let multi_buffer = self.buffer().read(cx);
 5437        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5438        let multi_buffer_visible_start = self
 5439            .scroll_manager
 5440            .anchor()
 5441            .anchor
 5442            .to_point(&multi_buffer_snapshot);
 5443        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5444            multi_buffer_visible_start
 5445                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5446            Bias::Left,
 5447        );
 5448        multi_buffer_snapshot
 5449            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5450            .into_iter()
 5451            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5452            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5453                if !lsp_related_only {
 5454                    return Some((
 5455                        excerpt_id,
 5456                        (
 5457                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5458                            buffer.version().clone(),
 5459                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5460                        ),
 5461                    ));
 5462                }
 5463
 5464                let project = project.as_ref()?.read(cx);
 5465                let buffer_file = project::File::from_dyn(buffer.file())?;
 5466                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5467                let worktree_entry = buffer_worktree
 5468                    .read(cx)
 5469                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5470                if worktree_entry.is_ignored {
 5471                    None
 5472                } else {
 5473                    Some((
 5474                        excerpt_id,
 5475                        (
 5476                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5477                            buffer.version().clone(),
 5478                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5479                        ),
 5480                    ))
 5481                }
 5482            })
 5483            .collect()
 5484    }
 5485
 5486    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5487        TextLayoutDetails {
 5488            text_system: window.text_system().clone(),
 5489            editor_style: self.style.clone().unwrap(),
 5490            rem_size: window.rem_size(),
 5491            scroll_anchor: self.scroll_manager.anchor(),
 5492            visible_rows: self.visible_line_count(),
 5493            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5494        }
 5495    }
 5496
 5497    fn trigger_on_type_formatting(
 5498        &self,
 5499        input: String,
 5500        window: &mut Window,
 5501        cx: &mut Context<Self>,
 5502    ) -> Option<Task<Result<()>>> {
 5503        if input.chars().count() != 1 {
 5504            return None;
 5505        }
 5506
 5507        let project = self.project()?;
 5508        let position = self.selections.newest_anchor().head();
 5509        let (buffer, buffer_position) = self
 5510            .buffer
 5511            .read(cx)
 5512            .text_anchor_for_position(position, cx)?;
 5513
 5514        let settings = language_settings::language_settings(
 5515            buffer
 5516                .read(cx)
 5517                .language_at(buffer_position)
 5518                .map(|l| l.name()),
 5519            buffer.read(cx).file(),
 5520            cx,
 5521        );
 5522        if !settings.use_on_type_format {
 5523            return None;
 5524        }
 5525
 5526        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5527        // hence we do LSP request & edit on host side only — add formats to host's history.
 5528        let push_to_lsp_host_history = true;
 5529        // If this is not the host, append its history with new edits.
 5530        let push_to_client_history = project.read(cx).is_via_collab();
 5531
 5532        let on_type_formatting = project.update(cx, |project, cx| {
 5533            project.on_type_format(
 5534                buffer.clone(),
 5535                buffer_position,
 5536                input,
 5537                push_to_lsp_host_history,
 5538                cx,
 5539            )
 5540        });
 5541        Some(cx.spawn_in(window, async move |editor, cx| {
 5542            if let Some(transaction) = on_type_formatting.await? {
 5543                if push_to_client_history {
 5544                    buffer.update(cx, |buffer, _| {
 5545                        buffer.push_transaction(transaction, Instant::now());
 5546                        buffer.finalize_last_transaction();
 5547                    });
 5548                }
 5549                editor.update(cx, |editor, cx| {
 5550                    editor.refresh_document_highlights(cx);
 5551                })?;
 5552            }
 5553            Ok(())
 5554        }))
 5555    }
 5556
 5557    pub fn show_word_completions(
 5558        &mut self,
 5559        _: &ShowWordCompletions,
 5560        window: &mut Window,
 5561        cx: &mut Context<Self>,
 5562    ) {
 5563        self.open_or_update_completions_menu(
 5564            Some(CompletionsMenuSource::Words {
 5565                ignore_threshold: true,
 5566            }),
 5567            None,
 5568            false,
 5569            window,
 5570            cx,
 5571        );
 5572    }
 5573
 5574    pub fn show_completions(
 5575        &mut self,
 5576        _: &ShowCompletions,
 5577        window: &mut Window,
 5578        cx: &mut Context<Self>,
 5579    ) {
 5580        self.open_or_update_completions_menu(None, None, false, window, cx);
 5581    }
 5582
 5583    fn open_or_update_completions_menu(
 5584        &mut self,
 5585        requested_source: Option<CompletionsMenuSource>,
 5586        trigger: Option<String>,
 5587        trigger_in_words: bool,
 5588        window: &mut Window,
 5589        cx: &mut Context<Self>,
 5590    ) {
 5591        if self.pending_rename.is_some() {
 5592            return;
 5593        }
 5594
 5595        let completions_source = self
 5596            .context_menu
 5597            .borrow()
 5598            .as_ref()
 5599            .and_then(|menu| match menu {
 5600                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5601                CodeContextMenu::CodeActions(_) => None,
 5602            });
 5603
 5604        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5605
 5606        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5607        // inserted and selected. To handle that case, the start of the selection is used so that
 5608        // the menu starts with all choices.
 5609        let position = self
 5610            .selections
 5611            .newest_anchor()
 5612            .start
 5613            .bias_right(&multibuffer_snapshot);
 5614        if position.diff_base_anchor.is_some() {
 5615            return;
 5616        }
 5617        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5618        let Some(buffer) = buffer_position
 5619            .text_anchor
 5620            .buffer_id
 5621            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5622        else {
 5623            return;
 5624        };
 5625        let buffer_snapshot = buffer.read(cx).snapshot();
 5626
 5627        let menu_is_open = matches!(
 5628            self.context_menu.borrow().as_ref(),
 5629            Some(CodeContextMenu::Completions(_))
 5630        );
 5631
 5632        let language = buffer_snapshot
 5633            .language_at(buffer_position.text_anchor)
 5634            .map(|language| language.name());
 5635
 5636        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5637        let completion_settings = language_settings.completions.clone();
 5638
 5639        let show_completions_on_input = self
 5640            .show_completions_on_input_override
 5641            .unwrap_or(language_settings.show_completions_on_input);
 5642        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5643            return;
 5644        }
 5645
 5646        let query: Option<Arc<String>> =
 5647            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5648                .map(|query| query.into());
 5649
 5650        drop(multibuffer_snapshot);
 5651
 5652        // Hide the current completions menu when query is empty. Without this, cached
 5653        // completions from before the trigger char may be reused (#32774).
 5654        if query.is_none() && menu_is_open {
 5655            self.hide_context_menu(window, cx);
 5656        }
 5657
 5658        let mut ignore_word_threshold = false;
 5659        let provider = match requested_source {
 5660            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5661            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5662                ignore_word_threshold = ignore_threshold;
 5663                None
 5664            }
 5665            Some(CompletionsMenuSource::SnippetChoices)
 5666            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5667                log::error!("bug: SnippetChoices requested_source is not handled");
 5668                None
 5669            }
 5670        };
 5671
 5672        let sort_completions = provider
 5673            .as_ref()
 5674            .is_some_and(|provider| provider.sort_completions());
 5675
 5676        let filter_completions = provider
 5677            .as_ref()
 5678            .is_none_or(|provider| provider.filter_completions());
 5679
 5680        let was_snippets_only = matches!(
 5681            completions_source,
 5682            Some(CompletionsMenuSource::SnippetsOnly)
 5683        );
 5684
 5685        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5686            if filter_completions {
 5687                menu.filter(
 5688                    query.clone().unwrap_or_default(),
 5689                    buffer_position.text_anchor,
 5690                    &buffer,
 5691                    provider.clone(),
 5692                    window,
 5693                    cx,
 5694                );
 5695            }
 5696            // When `is_incomplete` is false, no need to re-query completions when the current query
 5697            // is a suffix of the initial query.
 5698            let was_complete = !menu.is_incomplete;
 5699            if was_complete && !was_snippets_only {
 5700                // If the new query is a suffix of the old query (typing more characters) and
 5701                // the previous result was complete, the existing completions can be filtered.
 5702                //
 5703                // Note that snippet completions are always complete.
 5704                let query_matches = match (&menu.initial_query, &query) {
 5705                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5706                    (None, _) => true,
 5707                    _ => false,
 5708                };
 5709                if query_matches {
 5710                    let position_matches = if menu.initial_position == position {
 5711                        true
 5712                    } else {
 5713                        let snapshot = self.buffer.read(cx).read(cx);
 5714                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5715                    };
 5716                    if position_matches {
 5717                        return;
 5718                    }
 5719                }
 5720            }
 5721        };
 5722
 5723        let Anchor {
 5724            excerpt_id: buffer_excerpt_id,
 5725            text_anchor: buffer_position,
 5726            ..
 5727        } = buffer_position;
 5728
 5729        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5730            buffer_snapshot.surrounding_word(buffer_position, None)
 5731        {
 5732            let word_to_exclude = buffer_snapshot
 5733                .text_for_range(word_range.clone())
 5734                .collect::<String>();
 5735            (
 5736                buffer_snapshot.anchor_before(word_range.start)
 5737                    ..buffer_snapshot.anchor_after(buffer_position),
 5738                Some(word_to_exclude),
 5739            )
 5740        } else {
 5741            (buffer_position..buffer_position, None)
 5742        };
 5743
 5744        let show_completion_documentation = buffer_snapshot
 5745            .settings_at(buffer_position, cx)
 5746            .show_completion_documentation;
 5747
 5748        // The document can be large, so stay in reasonable bounds when searching for words,
 5749        // otherwise completion pop-up might be slow to appear.
 5750        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5751        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5752        let min_word_search = buffer_snapshot.clip_point(
 5753            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5754            Bias::Left,
 5755        );
 5756        let max_word_search = buffer_snapshot.clip_point(
 5757            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5758            Bias::Right,
 5759        );
 5760        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5761            ..buffer_snapshot.point_to_offset(max_word_search);
 5762
 5763        let skip_digits = query
 5764            .as_ref()
 5765            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5766
 5767        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5768            trigger.as_ref().is_none_or(|trigger| {
 5769                provider.is_completion_trigger(
 5770                    &buffer,
 5771                    position.text_anchor,
 5772                    trigger,
 5773                    trigger_in_words,
 5774                    cx,
 5775                )
 5776            })
 5777        });
 5778
 5779        let provider_responses = if let Some(provider) = &provider
 5780            && load_provider_completions
 5781        {
 5782            let trigger_character =
 5783                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5784            let completion_context = CompletionContext {
 5785                trigger_kind: match &trigger_character {
 5786                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5787                    None => CompletionTriggerKind::INVOKED,
 5788                },
 5789                trigger_character,
 5790            };
 5791
 5792            provider.completions(
 5793                buffer_excerpt_id,
 5794                &buffer,
 5795                buffer_position,
 5796                completion_context,
 5797                window,
 5798                cx,
 5799            )
 5800        } else {
 5801            Task::ready(Ok(Vec::new()))
 5802        };
 5803
 5804        let load_word_completions = if !self.word_completions_enabled {
 5805            false
 5806        } else if requested_source
 5807            == Some(CompletionsMenuSource::Words {
 5808                ignore_threshold: true,
 5809            })
 5810        {
 5811            true
 5812        } else {
 5813            load_provider_completions
 5814                && completion_settings.words != WordsCompletionMode::Disabled
 5815                && (ignore_word_threshold || {
 5816                    let words_min_length = completion_settings.words_min_length;
 5817                    // check whether word has at least `words_min_length` characters
 5818                    let query_chars = query.iter().flat_map(|q| q.chars());
 5819                    query_chars.take(words_min_length).count() == words_min_length
 5820                })
 5821        };
 5822
 5823        let mut words = if load_word_completions {
 5824            cx.background_spawn({
 5825                let buffer_snapshot = buffer_snapshot.clone();
 5826                async move {
 5827                    buffer_snapshot.words_in_range(WordsQuery {
 5828                        fuzzy_contents: None,
 5829                        range: word_search_range,
 5830                        skip_digits,
 5831                    })
 5832                }
 5833            })
 5834        } else {
 5835            Task::ready(BTreeMap::default())
 5836        };
 5837
 5838        let snippets = if let Some(provider) = &provider
 5839            && provider.show_snippets()
 5840            && let Some(project) = self.project()
 5841        {
 5842            let char_classifier = buffer_snapshot
 5843                .char_classifier_at(buffer_position)
 5844                .scope_context(Some(CharScopeContext::Completion));
 5845            project.update(cx, |project, cx| {
 5846                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5847            })
 5848        } else {
 5849            Task::ready(Ok(CompletionResponse {
 5850                completions: Vec::new(),
 5851                display_options: Default::default(),
 5852                is_incomplete: false,
 5853            }))
 5854        };
 5855
 5856        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5857
 5858        let id = post_inc(&mut self.next_completion_id);
 5859        let task = cx.spawn_in(window, async move |editor, cx| {
 5860            let Ok(()) = editor.update(cx, |this, _| {
 5861                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5862            }) else {
 5863                return;
 5864            };
 5865
 5866            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5867            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5868            let mut completions = Vec::new();
 5869            let mut is_incomplete = false;
 5870            let mut display_options: Option<CompletionDisplayOptions> = None;
 5871            if let Some(provider_responses) = provider_responses.await.log_err()
 5872                && !provider_responses.is_empty()
 5873            {
 5874                for response in provider_responses {
 5875                    completions.extend(response.completions);
 5876                    is_incomplete = is_incomplete || response.is_incomplete;
 5877                    match display_options.as_mut() {
 5878                        None => {
 5879                            display_options = Some(response.display_options);
 5880                        }
 5881                        Some(options) => options.merge(&response.display_options),
 5882                    }
 5883                }
 5884                if completion_settings.words == WordsCompletionMode::Fallback {
 5885                    words = Task::ready(BTreeMap::default());
 5886                }
 5887            }
 5888            let display_options = display_options.unwrap_or_default();
 5889
 5890            let mut words = words.await;
 5891            if let Some(word_to_exclude) = &word_to_exclude {
 5892                words.remove(word_to_exclude);
 5893            }
 5894            for lsp_completion in &completions {
 5895                words.remove(&lsp_completion.new_text);
 5896            }
 5897            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5898                replace_range: word_replace_range.clone(),
 5899                new_text: word.clone(),
 5900                label: CodeLabel::plain(word, None),
 5901                match_start: None,
 5902                snippet_deduplication_key: None,
 5903                icon_path: None,
 5904                documentation: None,
 5905                source: CompletionSource::BufferWord {
 5906                    word_range,
 5907                    resolved: false,
 5908                },
 5909                insert_text_mode: Some(InsertTextMode::AS_IS),
 5910                confirm: None,
 5911            }));
 5912
 5913            completions.extend(
 5914                snippets
 5915                    .await
 5916                    .into_iter()
 5917                    .flat_map(|response| response.completions),
 5918            );
 5919
 5920            let menu = if completions.is_empty() {
 5921                None
 5922            } else {
 5923                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5924                    let languages = editor
 5925                        .workspace
 5926                        .as_ref()
 5927                        .and_then(|(workspace, _)| workspace.upgrade())
 5928                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5929                    let menu = CompletionsMenu::new(
 5930                        id,
 5931                        requested_source.unwrap_or(if load_provider_completions {
 5932                            CompletionsMenuSource::Normal
 5933                        } else {
 5934                            CompletionsMenuSource::SnippetsOnly
 5935                        }),
 5936                        sort_completions,
 5937                        show_completion_documentation,
 5938                        position,
 5939                        query.clone(),
 5940                        is_incomplete,
 5941                        buffer.clone(),
 5942                        completions.into(),
 5943                        editor
 5944                            .context_menu()
 5945                            .borrow_mut()
 5946                            .as_ref()
 5947                            .map(|menu| menu.primary_scroll_handle()),
 5948                        display_options,
 5949                        snippet_sort_order,
 5950                        languages,
 5951                        language,
 5952                        cx,
 5953                    );
 5954
 5955                    let query = if filter_completions { query } else { None };
 5956                    let matches_task = menu.do_async_filtering(
 5957                        query.unwrap_or_default(),
 5958                        buffer_position,
 5959                        &buffer,
 5960                        cx,
 5961                    );
 5962                    (menu, matches_task)
 5963                }) else {
 5964                    return;
 5965                };
 5966
 5967                let matches = matches_task.await;
 5968
 5969                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5970                    // Newer menu already set, so exit.
 5971                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5972                        editor.context_menu.borrow().as_ref()
 5973                        && prev_menu.id > id
 5974                    {
 5975                        return;
 5976                    };
 5977
 5978                    // Only valid to take prev_menu because either the new menu is immediately set
 5979                    // below, or the menu is hidden.
 5980                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5981                        editor.context_menu.borrow_mut().take()
 5982                    {
 5983                        let position_matches =
 5984                            if prev_menu.initial_position == menu.initial_position {
 5985                                true
 5986                            } else {
 5987                                let snapshot = editor.buffer.read(cx).read(cx);
 5988                                prev_menu.initial_position.to_offset(&snapshot)
 5989                                    == menu.initial_position.to_offset(&snapshot)
 5990                            };
 5991                        if position_matches {
 5992                            // Preserve markdown cache before `set_filter_results` because it will
 5993                            // try to populate the documentation cache.
 5994                            menu.preserve_markdown_cache(prev_menu);
 5995                        }
 5996                    };
 5997
 5998                    menu.set_filter_results(matches, provider, window, cx);
 5999                }) else {
 6000                    return;
 6001                };
 6002
 6003                menu.visible().then_some(menu)
 6004            };
 6005
 6006            editor
 6007                .update_in(cx, |editor, window, cx| {
 6008                    if editor.focus_handle.is_focused(window)
 6009                        && let Some(menu) = menu
 6010                    {
 6011                        *editor.context_menu.borrow_mut() =
 6012                            Some(CodeContextMenu::Completions(menu));
 6013
 6014                        crate::hover_popover::hide_hover(editor, cx);
 6015                        if editor.show_edit_predictions_in_menu() {
 6016                            editor.update_visible_edit_prediction(window, cx);
 6017                        } else {
 6018                            editor.discard_edit_prediction(false, cx);
 6019                        }
 6020
 6021                        cx.notify();
 6022                        return;
 6023                    }
 6024
 6025                    if editor.completion_tasks.len() <= 1 {
 6026                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6027                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6028                        // If it was already hidden and we don't show edit predictions in the menu,
 6029                        // we should also show the edit prediction when available.
 6030                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6031                            editor.update_visible_edit_prediction(window, cx);
 6032                        }
 6033                    }
 6034                })
 6035                .ok();
 6036        });
 6037
 6038        self.completion_tasks.push((id, task));
 6039    }
 6040
 6041    #[cfg(feature = "test-support")]
 6042    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6043        let menu = self.context_menu.borrow();
 6044        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6045            let completions = menu.completions.borrow();
 6046            Some(completions.to_vec())
 6047        } else {
 6048            None
 6049        }
 6050    }
 6051
 6052    pub fn with_completions_menu_matching_id<R>(
 6053        &self,
 6054        id: CompletionId,
 6055        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6056    ) -> R {
 6057        let mut context_menu = self.context_menu.borrow_mut();
 6058        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6059            return f(None);
 6060        };
 6061        if completions_menu.id != id {
 6062            return f(None);
 6063        }
 6064        f(Some(completions_menu))
 6065    }
 6066
 6067    pub fn confirm_completion(
 6068        &mut self,
 6069        action: &ConfirmCompletion,
 6070        window: &mut Window,
 6071        cx: &mut Context<Self>,
 6072    ) -> Option<Task<Result<()>>> {
 6073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6074        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6075    }
 6076
 6077    pub fn confirm_completion_insert(
 6078        &mut self,
 6079        _: &ConfirmCompletionInsert,
 6080        window: &mut Window,
 6081        cx: &mut Context<Self>,
 6082    ) -> Option<Task<Result<()>>> {
 6083        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6084        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6085    }
 6086
 6087    pub fn confirm_completion_replace(
 6088        &mut self,
 6089        _: &ConfirmCompletionReplace,
 6090        window: &mut Window,
 6091        cx: &mut Context<Self>,
 6092    ) -> Option<Task<Result<()>>> {
 6093        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6094        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6095    }
 6096
 6097    pub fn compose_completion(
 6098        &mut self,
 6099        action: &ComposeCompletion,
 6100        window: &mut Window,
 6101        cx: &mut Context<Self>,
 6102    ) -> Option<Task<Result<()>>> {
 6103        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6104        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6105    }
 6106
 6107    fn do_completion(
 6108        &mut self,
 6109        item_ix: Option<usize>,
 6110        intent: CompletionIntent,
 6111        window: &mut Window,
 6112        cx: &mut Context<Editor>,
 6113    ) -> Option<Task<Result<()>>> {
 6114        use language::ToOffset as _;
 6115
 6116        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6117        else {
 6118            return None;
 6119        };
 6120
 6121        let candidate_id = {
 6122            let entries = completions_menu.entries.borrow();
 6123            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6124            if self.show_edit_predictions_in_menu() {
 6125                self.discard_edit_prediction(true, cx);
 6126            }
 6127            mat.candidate_id
 6128        };
 6129
 6130        let completion = completions_menu
 6131            .completions
 6132            .borrow()
 6133            .get(candidate_id)?
 6134            .clone();
 6135        cx.stop_propagation();
 6136
 6137        let buffer_handle = completions_menu.buffer.clone();
 6138
 6139        let CompletionEdit {
 6140            new_text,
 6141            snippet,
 6142            replace_range,
 6143        } = process_completion_for_edit(
 6144            &completion,
 6145            intent,
 6146            &buffer_handle,
 6147            &completions_menu.initial_position.text_anchor,
 6148            cx,
 6149        );
 6150
 6151        let buffer = buffer_handle.read(cx);
 6152        let snapshot = self.buffer.read(cx).snapshot(cx);
 6153        let newest_anchor = self.selections.newest_anchor();
 6154        let replace_range_multibuffer = {
 6155            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6156            excerpt.map_range_from_buffer(replace_range.clone())
 6157        };
 6158        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6159            return None;
 6160        }
 6161
 6162        let old_text = buffer
 6163            .text_for_range(replace_range.clone())
 6164            .collect::<String>();
 6165        let lookbehind = newest_anchor
 6166            .start
 6167            .text_anchor
 6168            .to_offset(buffer)
 6169            .saturating_sub(replace_range.start.0);
 6170        let lookahead = replace_range
 6171            .end
 6172            .0
 6173            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6174        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6175        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6176
 6177        let selections = self
 6178            .selections
 6179            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6180        let mut ranges = Vec::new();
 6181        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6182
 6183        for selection in &selections {
 6184            let range = if selection.id == newest_anchor.id {
 6185                replace_range_multibuffer.clone()
 6186            } else {
 6187                let mut range = selection.range();
 6188
 6189                // if prefix is present, don't duplicate it
 6190                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6191                    range.start = range.start.saturating_sub_usize(lookbehind);
 6192
 6193                    // if suffix is also present, mimic the newest cursor and replace it
 6194                    if selection.id != newest_anchor.id
 6195                        && snapshot.contains_str_at(range.end, suffix)
 6196                    {
 6197                        range.end += lookahead;
 6198                    }
 6199                }
 6200                range
 6201            };
 6202
 6203            ranges.push(range.clone());
 6204
 6205            if !self.linked_edit_ranges.is_empty() {
 6206                let start_anchor = snapshot.anchor_before(range.start);
 6207                let end_anchor = snapshot.anchor_after(range.end);
 6208                if let Some(ranges) = self
 6209                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6210                {
 6211                    for (buffer, edits) in ranges {
 6212                        linked_edits
 6213                            .entry(buffer.clone())
 6214                            .or_default()
 6215                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6216                    }
 6217                }
 6218            }
 6219        }
 6220
 6221        let common_prefix_len = old_text
 6222            .chars()
 6223            .zip(new_text.chars())
 6224            .take_while(|(a, b)| a == b)
 6225            .map(|(a, _)| a.len_utf8())
 6226            .sum::<usize>();
 6227
 6228        cx.emit(EditorEvent::InputHandled {
 6229            utf16_range_to_replace: None,
 6230            text: new_text[common_prefix_len..].into(),
 6231        });
 6232
 6233        self.transact(window, cx, |editor, window, cx| {
 6234            if let Some(mut snippet) = snippet {
 6235                snippet.text = new_text.to_string();
 6236                editor
 6237                    .insert_snippet(&ranges, snippet, window, cx)
 6238                    .log_err();
 6239            } else {
 6240                editor.buffer.update(cx, |multi_buffer, cx| {
 6241                    let auto_indent = match completion.insert_text_mode {
 6242                        Some(InsertTextMode::AS_IS) => None,
 6243                        _ => editor.autoindent_mode.clone(),
 6244                    };
 6245                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6246                    multi_buffer.edit(edits, auto_indent, cx);
 6247                });
 6248            }
 6249            for (buffer, edits) in linked_edits {
 6250                buffer.update(cx, |buffer, cx| {
 6251                    let snapshot = buffer.snapshot();
 6252                    let edits = edits
 6253                        .into_iter()
 6254                        .map(|(range, text)| {
 6255                            use text::ToPoint as TP;
 6256                            let end_point = TP::to_point(&range.end, &snapshot);
 6257                            let start_point = TP::to_point(&range.start, &snapshot);
 6258                            (start_point..end_point, text)
 6259                        })
 6260                        .sorted_by_key(|(range, _)| range.start);
 6261                    buffer.edit(edits, None, cx);
 6262                })
 6263            }
 6264
 6265            editor.refresh_edit_prediction(true, false, window, cx);
 6266        });
 6267        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6268
 6269        let show_new_completions_on_confirm = completion
 6270            .confirm
 6271            .as_ref()
 6272            .is_some_and(|confirm| confirm(intent, window, cx));
 6273        if show_new_completions_on_confirm {
 6274            self.open_or_update_completions_menu(None, None, false, window, cx);
 6275        }
 6276
 6277        let provider = self.completion_provider.as_ref()?;
 6278
 6279        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6280        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6281            let CompletionSource::Lsp {
 6282                lsp_completion,
 6283                server_id,
 6284                ..
 6285            } = &completion.source
 6286            else {
 6287                return None;
 6288            };
 6289            let lsp_command = lsp_completion.command.as_ref()?;
 6290            let available_commands = lsp_store
 6291                .read(cx)
 6292                .lsp_server_capabilities
 6293                .get(server_id)
 6294                .and_then(|server_capabilities| {
 6295                    server_capabilities
 6296                        .execute_command_provider
 6297                        .as_ref()
 6298                        .map(|options| options.commands.as_slice())
 6299                })?;
 6300            if available_commands.contains(&lsp_command.command) {
 6301                Some(CodeAction {
 6302                    server_id: *server_id,
 6303                    range: language::Anchor::MIN..language::Anchor::MIN,
 6304                    lsp_action: LspAction::Command(lsp_command.clone()),
 6305                    resolved: false,
 6306                })
 6307            } else {
 6308                None
 6309            }
 6310        });
 6311
 6312        drop(completion);
 6313        let apply_edits = provider.apply_additional_edits_for_completion(
 6314            buffer_handle.clone(),
 6315            completions_menu.completions.clone(),
 6316            candidate_id,
 6317            true,
 6318            cx,
 6319        );
 6320
 6321        let editor_settings = EditorSettings::get_global(cx);
 6322        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6323            // After the code completion is finished, users often want to know what signatures are needed.
 6324            // so we should automatically call signature_help
 6325            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6326        }
 6327
 6328        Some(cx.spawn_in(window, async move |editor, cx| {
 6329            apply_edits.await?;
 6330
 6331            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6332                let title = command.lsp_action.title().to_owned();
 6333                let project_transaction = lsp_store
 6334                    .update(cx, |lsp_store, cx| {
 6335                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6336                    })
 6337                    .await
 6338                    .context("applying post-completion command")?;
 6339                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6340                    Self::open_project_transaction(
 6341                        &editor,
 6342                        workspace.downgrade(),
 6343                        project_transaction,
 6344                        title,
 6345                        cx,
 6346                    )
 6347                    .await?;
 6348                }
 6349            }
 6350
 6351            Ok(())
 6352        }))
 6353    }
 6354
 6355    pub fn toggle_code_actions(
 6356        &mut self,
 6357        action: &ToggleCodeActions,
 6358        window: &mut Window,
 6359        cx: &mut Context<Self>,
 6360    ) {
 6361        let quick_launch = action.quick_launch;
 6362        let mut context_menu = self.context_menu.borrow_mut();
 6363        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6364            if code_actions.deployed_from == action.deployed_from {
 6365                // Toggle if we're selecting the same one
 6366                *context_menu = None;
 6367                cx.notify();
 6368                return;
 6369            } else {
 6370                // Otherwise, clear it and start a new one
 6371                *context_menu = None;
 6372                cx.notify();
 6373            }
 6374        }
 6375        drop(context_menu);
 6376        let snapshot = self.snapshot(window, cx);
 6377        let deployed_from = action.deployed_from.clone();
 6378        let action = action.clone();
 6379        self.completion_tasks.clear();
 6380        self.discard_edit_prediction(false, cx);
 6381
 6382        let multibuffer_point = match &action.deployed_from {
 6383            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6384                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6385            }
 6386            _ => self
 6387                .selections
 6388                .newest::<Point>(&snapshot.display_snapshot)
 6389                .head(),
 6390        };
 6391        let Some((buffer, buffer_row)) = snapshot
 6392            .buffer_snapshot()
 6393            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6394            .and_then(|(buffer_snapshot, range)| {
 6395                self.buffer()
 6396                    .read(cx)
 6397                    .buffer(buffer_snapshot.remote_id())
 6398                    .map(|buffer| (buffer, range.start.row))
 6399            })
 6400        else {
 6401            return;
 6402        };
 6403        let buffer_id = buffer.read(cx).remote_id();
 6404        let tasks = self
 6405            .tasks
 6406            .get(&(buffer_id, buffer_row))
 6407            .map(|t| Arc::new(t.to_owned()));
 6408
 6409        if !self.focus_handle.is_focused(window) {
 6410            return;
 6411        }
 6412        let project = self.project.clone();
 6413
 6414        let code_actions_task = match deployed_from {
 6415            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6416            _ => self.code_actions(buffer_row, window, cx),
 6417        };
 6418
 6419        let runnable_task = match deployed_from {
 6420            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6421            _ => {
 6422                let mut task_context_task = Task::ready(None);
 6423                if let Some(tasks) = &tasks
 6424                    && let Some(project) = project
 6425                {
 6426                    task_context_task =
 6427                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6428                }
 6429
 6430                cx.spawn_in(window, {
 6431                    let buffer = buffer.clone();
 6432                    async move |editor, cx| {
 6433                        let task_context = task_context_task.await;
 6434
 6435                        let resolved_tasks =
 6436                            tasks
 6437                                .zip(task_context.clone())
 6438                                .map(|(tasks, task_context)| ResolvedTasks {
 6439                                    templates: tasks.resolve(&task_context).collect(),
 6440                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6441                                        multibuffer_point.row,
 6442                                        tasks.column,
 6443                                    )),
 6444                                });
 6445                        let debug_scenarios = editor
 6446                            .update(cx, |editor, cx| {
 6447                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6448                            })?
 6449                            .await;
 6450                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6451                    }
 6452                })
 6453            }
 6454        };
 6455
 6456        cx.spawn_in(window, async move |editor, cx| {
 6457            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6458            let code_actions = code_actions_task.await;
 6459            let spawn_straight_away = quick_launch
 6460                && resolved_tasks
 6461                    .as_ref()
 6462                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6463                && code_actions
 6464                    .as_ref()
 6465                    .is_none_or(|actions| actions.is_empty())
 6466                && debug_scenarios.is_empty();
 6467
 6468            editor.update_in(cx, |editor, window, cx| {
 6469                crate::hover_popover::hide_hover(editor, cx);
 6470                let actions = CodeActionContents::new(
 6471                    resolved_tasks,
 6472                    code_actions,
 6473                    debug_scenarios,
 6474                    task_context.unwrap_or_default(),
 6475                );
 6476
 6477                // Don't show the menu if there are no actions available
 6478                if actions.is_empty() {
 6479                    cx.notify();
 6480                    return Task::ready(Ok(()));
 6481                }
 6482
 6483                *editor.context_menu.borrow_mut() =
 6484                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6485                        buffer,
 6486                        actions,
 6487                        selected_item: Default::default(),
 6488                        scroll_handle: UniformListScrollHandle::default(),
 6489                        deployed_from,
 6490                    }));
 6491                cx.notify();
 6492                if spawn_straight_away
 6493                    && let Some(task) = editor.confirm_code_action(
 6494                        &ConfirmCodeAction { item_ix: Some(0) },
 6495                        window,
 6496                        cx,
 6497                    )
 6498                {
 6499                    return task;
 6500                }
 6501
 6502                Task::ready(Ok(()))
 6503            })
 6504        })
 6505        .detach_and_log_err(cx);
 6506    }
 6507
 6508    fn debug_scenarios(
 6509        &mut self,
 6510        resolved_tasks: &Option<ResolvedTasks>,
 6511        buffer: &Entity<Buffer>,
 6512        cx: &mut App,
 6513    ) -> Task<Vec<task::DebugScenario>> {
 6514        maybe!({
 6515            let project = self.project()?;
 6516            let dap_store = project.read(cx).dap_store();
 6517            let mut scenarios = vec![];
 6518            let resolved_tasks = resolved_tasks.as_ref()?;
 6519            let buffer = buffer.read(cx);
 6520            let language = buffer.language()?;
 6521            let file = buffer.file();
 6522            let debug_adapter = language_settings(language.name().into(), file, cx)
 6523                .debuggers
 6524                .first()
 6525                .map(SharedString::from)
 6526                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6527
 6528            dap_store.update(cx, |dap_store, cx| {
 6529                for (_, task) in &resolved_tasks.templates {
 6530                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6531                        task.original_task().clone(),
 6532                        debug_adapter.clone().into(),
 6533                        task.display_label().to_owned().into(),
 6534                        cx,
 6535                    );
 6536                    scenarios.push(maybe_scenario);
 6537                }
 6538            });
 6539            Some(cx.background_spawn(async move {
 6540                futures::future::join_all(scenarios)
 6541                    .await
 6542                    .into_iter()
 6543                    .flatten()
 6544                    .collect::<Vec<_>>()
 6545            }))
 6546        })
 6547        .unwrap_or_else(|| Task::ready(vec![]))
 6548    }
 6549
 6550    fn code_actions(
 6551        &mut self,
 6552        buffer_row: u32,
 6553        window: &mut Window,
 6554        cx: &mut Context<Self>,
 6555    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6556        let mut task = self.code_actions_task.take();
 6557        cx.spawn_in(window, async move |editor, cx| {
 6558            while let Some(prev_task) = task {
 6559                prev_task.await.log_err();
 6560                task = editor
 6561                    .update(cx, |this, _| this.code_actions_task.take())
 6562                    .ok()?;
 6563            }
 6564
 6565            editor
 6566                .update(cx, |editor, cx| {
 6567                    editor
 6568                        .available_code_actions
 6569                        .clone()
 6570                        .and_then(|(location, code_actions)| {
 6571                            let snapshot = location.buffer.read(cx).snapshot();
 6572                            let point_range = location.range.to_point(&snapshot);
 6573                            let point_range = point_range.start.row..=point_range.end.row;
 6574                            if point_range.contains(&buffer_row) {
 6575                                Some(code_actions)
 6576                            } else {
 6577                                None
 6578                            }
 6579                        })
 6580                })
 6581                .ok()
 6582                .flatten()
 6583        })
 6584    }
 6585
 6586    pub fn confirm_code_action(
 6587        &mut self,
 6588        action: &ConfirmCodeAction,
 6589        window: &mut Window,
 6590        cx: &mut Context<Self>,
 6591    ) -> Option<Task<Result<()>>> {
 6592        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6593
 6594        let actions_menu =
 6595            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6596                menu
 6597            } else {
 6598                return None;
 6599            };
 6600
 6601        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6602        let action = actions_menu.actions.get(action_ix)?;
 6603        let title = action.label();
 6604        let buffer = actions_menu.buffer;
 6605        let workspace = self.workspace()?;
 6606
 6607        match action {
 6608            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6609                workspace.update(cx, |workspace, cx| {
 6610                    workspace.schedule_resolved_task(
 6611                        task_source_kind,
 6612                        resolved_task,
 6613                        false,
 6614                        window,
 6615                        cx,
 6616                    );
 6617
 6618                    Some(Task::ready(Ok(())))
 6619                })
 6620            }
 6621            CodeActionsItem::CodeAction {
 6622                excerpt_id,
 6623                action,
 6624                provider,
 6625            } => {
 6626                let apply_code_action =
 6627                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6628                let workspace = workspace.downgrade();
 6629                Some(cx.spawn_in(window, async move |editor, cx| {
 6630                    let project_transaction = apply_code_action.await?;
 6631                    Self::open_project_transaction(
 6632                        &editor,
 6633                        workspace,
 6634                        project_transaction,
 6635                        title,
 6636                        cx,
 6637                    )
 6638                    .await
 6639                }))
 6640            }
 6641            CodeActionsItem::DebugScenario(scenario) => {
 6642                let context = actions_menu.actions.context;
 6643
 6644                workspace.update(cx, |workspace, cx| {
 6645                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6646                    workspace.start_debug_session(
 6647                        scenario,
 6648                        context,
 6649                        Some(buffer),
 6650                        None,
 6651                        window,
 6652                        cx,
 6653                    );
 6654                });
 6655                Some(Task::ready(Ok(())))
 6656            }
 6657        }
 6658    }
 6659
 6660    fn open_transaction_for_hidden_buffers(
 6661        workspace: Entity<Workspace>,
 6662        transaction: ProjectTransaction,
 6663        title: String,
 6664        window: &mut Window,
 6665        cx: &mut Context<Self>,
 6666    ) {
 6667        if transaction.0.is_empty() {
 6668            return;
 6669        }
 6670
 6671        let edited_buffers_already_open = {
 6672            let other_editors: Vec<Entity<Editor>> = workspace
 6673                .read(cx)
 6674                .panes()
 6675                .iter()
 6676                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6677                .filter(|editor| editor.entity_id() != cx.entity_id())
 6678                .collect();
 6679
 6680            transaction.0.keys().all(|buffer| {
 6681                other_editors.iter().any(|editor| {
 6682                    let multi_buffer = editor.read(cx).buffer();
 6683                    multi_buffer.read(cx).is_singleton()
 6684                        && multi_buffer
 6685                            .read(cx)
 6686                            .as_singleton()
 6687                            .map_or(false, |singleton| {
 6688                                singleton.entity_id() == buffer.entity_id()
 6689                            })
 6690                })
 6691            })
 6692        };
 6693        if !edited_buffers_already_open {
 6694            let workspace = workspace.downgrade();
 6695            cx.defer_in(window, move |_, window, cx| {
 6696                cx.spawn_in(window, async move |editor, cx| {
 6697                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6698                        .await
 6699                        .ok()
 6700                })
 6701                .detach();
 6702            });
 6703        }
 6704    }
 6705
 6706    pub async fn open_project_transaction(
 6707        editor: &WeakEntity<Editor>,
 6708        workspace: WeakEntity<Workspace>,
 6709        transaction: ProjectTransaction,
 6710        title: String,
 6711        cx: &mut AsyncWindowContext,
 6712    ) -> Result<()> {
 6713        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6714        cx.update(|_, cx| {
 6715            entries.sort_unstable_by_key(|(buffer, _)| {
 6716                buffer.read(cx).file().map(|f| f.path().clone())
 6717            });
 6718        })?;
 6719        if entries.is_empty() {
 6720            return Ok(());
 6721        }
 6722
 6723        // If the project transaction's edits are all contained within this editor, then
 6724        // avoid opening a new editor to display them.
 6725
 6726        if let [(buffer, transaction)] = &*entries {
 6727            let excerpt = editor.update(cx, |editor, cx| {
 6728                editor
 6729                    .buffer()
 6730                    .read(cx)
 6731                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6732            })?;
 6733            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6734                && excerpted_buffer == *buffer
 6735            {
 6736                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6737                    let excerpt_range = excerpt_range.to_offset(buffer);
 6738                    buffer
 6739                        .edited_ranges_for_transaction::<usize>(transaction)
 6740                        .all(|range| {
 6741                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6742                        })
 6743                });
 6744
 6745                if all_edits_within_excerpt {
 6746                    return Ok(());
 6747                }
 6748            }
 6749        }
 6750
 6751        let mut ranges_to_highlight = Vec::new();
 6752        let excerpt_buffer = cx.new(|cx| {
 6753            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6754            for (buffer_handle, transaction) in &entries {
 6755                let edited_ranges = buffer_handle
 6756                    .read(cx)
 6757                    .edited_ranges_for_transaction::<Point>(transaction)
 6758                    .collect::<Vec<_>>();
 6759                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6760                    PathKey::for_buffer(buffer_handle, cx),
 6761                    buffer_handle.clone(),
 6762                    edited_ranges,
 6763                    multibuffer_context_lines(cx),
 6764                    cx,
 6765                );
 6766
 6767                ranges_to_highlight.extend(ranges);
 6768            }
 6769            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6770            multibuffer
 6771        });
 6772
 6773        workspace.update_in(cx, |workspace, window, cx| {
 6774            let project = workspace.project().clone();
 6775            let editor =
 6776                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6777            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6778            editor.update(cx, |editor, cx| {
 6779                editor.highlight_background::<Self>(
 6780                    &ranges_to_highlight,
 6781                    |_, theme| theme.colors().editor_highlighted_line_background,
 6782                    cx,
 6783                );
 6784            });
 6785        })?;
 6786
 6787        Ok(())
 6788    }
 6789
 6790    pub fn clear_code_action_providers(&mut self) {
 6791        self.code_action_providers.clear();
 6792        self.available_code_actions.take();
 6793    }
 6794
 6795    pub fn add_code_action_provider(
 6796        &mut self,
 6797        provider: Rc<dyn CodeActionProvider>,
 6798        window: &mut Window,
 6799        cx: &mut Context<Self>,
 6800    ) {
 6801        if self
 6802            .code_action_providers
 6803            .iter()
 6804            .any(|existing_provider| existing_provider.id() == provider.id())
 6805        {
 6806            return;
 6807        }
 6808
 6809        self.code_action_providers.push(provider);
 6810        self.refresh_code_actions(window, cx);
 6811    }
 6812
 6813    pub fn remove_code_action_provider(
 6814        &mut self,
 6815        id: Arc<str>,
 6816        window: &mut Window,
 6817        cx: &mut Context<Self>,
 6818    ) {
 6819        self.code_action_providers
 6820            .retain(|provider| provider.id() != id);
 6821        self.refresh_code_actions(window, cx);
 6822    }
 6823
 6824    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6825        !self.code_action_providers.is_empty()
 6826            && EditorSettings::get_global(cx).toolbar.code_actions
 6827    }
 6828
 6829    pub fn has_available_code_actions(&self) -> bool {
 6830        self.available_code_actions
 6831            .as_ref()
 6832            .is_some_and(|(_, actions)| !actions.is_empty())
 6833    }
 6834
 6835    fn render_inline_code_actions(
 6836        &self,
 6837        icon_size: ui::IconSize,
 6838        display_row: DisplayRow,
 6839        is_active: bool,
 6840        cx: &mut Context<Self>,
 6841    ) -> AnyElement {
 6842        let show_tooltip = !self.context_menu_visible();
 6843        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6844            .icon_size(icon_size)
 6845            .shape(ui::IconButtonShape::Square)
 6846            .icon_color(ui::Color::Hidden)
 6847            .toggle_state(is_active)
 6848            .when(show_tooltip, |this| {
 6849                this.tooltip({
 6850                    let focus_handle = self.focus_handle.clone();
 6851                    move |_window, cx| {
 6852                        Tooltip::for_action_in(
 6853                            "Toggle Code Actions",
 6854                            &ToggleCodeActions {
 6855                                deployed_from: None,
 6856                                quick_launch: false,
 6857                            },
 6858                            &focus_handle,
 6859                            cx,
 6860                        )
 6861                    }
 6862                })
 6863            })
 6864            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6865                window.focus(&editor.focus_handle(cx), cx);
 6866                editor.toggle_code_actions(
 6867                    &crate::actions::ToggleCodeActions {
 6868                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6869                            display_row,
 6870                        )),
 6871                        quick_launch: false,
 6872                    },
 6873                    window,
 6874                    cx,
 6875                );
 6876            }))
 6877            .into_any_element()
 6878    }
 6879
 6880    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6881        &self.context_menu
 6882    }
 6883
 6884    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6885        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6886            cx.background_executor()
 6887                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6888                .await;
 6889
 6890            let (start_buffer, start, _, end, newest_selection) = this
 6891                .update(cx, |this, cx| {
 6892                    let newest_selection = this.selections.newest_anchor().clone();
 6893                    if newest_selection.head().diff_base_anchor.is_some() {
 6894                        return None;
 6895                    }
 6896                    let display_snapshot = this.display_snapshot(cx);
 6897                    let newest_selection_adjusted =
 6898                        this.selections.newest_adjusted(&display_snapshot);
 6899                    let buffer = this.buffer.read(cx);
 6900
 6901                    let (start_buffer, start) =
 6902                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6903                    let (end_buffer, end) =
 6904                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6905
 6906                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6907                })?
 6908                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6909                .context(
 6910                    "Expected selection to lie in a single buffer when refreshing code actions",
 6911                )?;
 6912            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6913                let providers = this.code_action_providers.clone();
 6914                let tasks = this
 6915                    .code_action_providers
 6916                    .iter()
 6917                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6918                    .collect::<Vec<_>>();
 6919                (providers, tasks)
 6920            })?;
 6921
 6922            let mut actions = Vec::new();
 6923            for (provider, provider_actions) in
 6924                providers.into_iter().zip(future::join_all(tasks).await)
 6925            {
 6926                if let Some(provider_actions) = provider_actions.log_err() {
 6927                    actions.extend(provider_actions.into_iter().map(|action| {
 6928                        AvailableCodeAction {
 6929                            excerpt_id: newest_selection.start.excerpt_id,
 6930                            action,
 6931                            provider: provider.clone(),
 6932                        }
 6933                    }));
 6934                }
 6935            }
 6936
 6937            this.update(cx, |this, cx| {
 6938                this.available_code_actions = if actions.is_empty() {
 6939                    None
 6940                } else {
 6941                    Some((
 6942                        Location {
 6943                            buffer: start_buffer,
 6944                            range: start..end,
 6945                        },
 6946                        actions.into(),
 6947                    ))
 6948                };
 6949                cx.notify();
 6950            })
 6951        }));
 6952    }
 6953
 6954    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6955        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6956            self.show_git_blame_inline = false;
 6957
 6958            self.show_git_blame_inline_delay_task =
 6959                Some(cx.spawn_in(window, async move |this, cx| {
 6960                    cx.background_executor().timer(delay).await;
 6961
 6962                    this.update(cx, |this, cx| {
 6963                        this.show_git_blame_inline = true;
 6964                        cx.notify();
 6965                    })
 6966                    .log_err();
 6967                }));
 6968        }
 6969    }
 6970
 6971    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6972        let snapshot = self.snapshot(window, cx);
 6973        let cursor = self
 6974            .selections
 6975            .newest::<Point>(&snapshot.display_snapshot)
 6976            .head();
 6977        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6978        else {
 6979            return;
 6980        };
 6981
 6982        if self.blame.is_none() {
 6983            self.start_git_blame(true, window, cx);
 6984        }
 6985        let Some(blame) = self.blame.as_ref() else {
 6986            return;
 6987        };
 6988
 6989        let row_info = RowInfo {
 6990            buffer_id: Some(buffer.remote_id()),
 6991            buffer_row: Some(point.row),
 6992            ..Default::default()
 6993        };
 6994        let Some((buffer, blame_entry)) = blame
 6995            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6996            .flatten()
 6997        else {
 6998            return;
 6999        };
 7000
 7001        let anchor = self.selections.newest_anchor().head();
 7002        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7003        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7004            self.show_blame_popover(
 7005                buffer,
 7006                &blame_entry,
 7007                position + last_bounds.origin,
 7008                true,
 7009                cx,
 7010            );
 7011        };
 7012    }
 7013
 7014    fn show_blame_popover(
 7015        &mut self,
 7016        buffer: BufferId,
 7017        blame_entry: &BlameEntry,
 7018        position: gpui::Point<Pixels>,
 7019        ignore_timeout: bool,
 7020        cx: &mut Context<Self>,
 7021    ) {
 7022        if let Some(state) = &mut self.inline_blame_popover {
 7023            state.hide_task.take();
 7024        } else {
 7025            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7026            let blame_entry = blame_entry.clone();
 7027            let show_task = cx.spawn(async move |editor, cx| {
 7028                if !ignore_timeout {
 7029                    cx.background_executor()
 7030                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7031                        .await;
 7032                }
 7033                editor
 7034                    .update(cx, |editor, cx| {
 7035                        editor.inline_blame_popover_show_task.take();
 7036                        let Some(blame) = editor.blame.as_ref() else {
 7037                            return;
 7038                        };
 7039                        let blame = blame.read(cx);
 7040                        let details = blame.details_for_entry(buffer, &blame_entry);
 7041                        let markdown = cx.new(|cx| {
 7042                            Markdown::new(
 7043                                details
 7044                                    .as_ref()
 7045                                    .map(|message| message.message.clone())
 7046                                    .unwrap_or_default(),
 7047                                None,
 7048                                None,
 7049                                cx,
 7050                            )
 7051                        });
 7052                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7053                            position,
 7054                            hide_task: None,
 7055                            popover_bounds: None,
 7056                            popover_state: InlineBlamePopoverState {
 7057                                scroll_handle: ScrollHandle::new(),
 7058                                commit_message: details,
 7059                                markdown,
 7060                            },
 7061                            keyboard_grace: ignore_timeout,
 7062                        });
 7063                        cx.notify();
 7064                    })
 7065                    .ok();
 7066            });
 7067            self.inline_blame_popover_show_task = Some(show_task);
 7068        }
 7069    }
 7070
 7071    pub fn has_mouse_context_menu(&self) -> bool {
 7072        self.mouse_context_menu.is_some()
 7073    }
 7074
 7075    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7076        self.inline_blame_popover_show_task.take();
 7077        if let Some(state) = &mut self.inline_blame_popover {
 7078            let hide_task = cx.spawn(async move |editor, cx| {
 7079                if !ignore_timeout {
 7080                    cx.background_executor()
 7081                        .timer(std::time::Duration::from_millis(100))
 7082                        .await;
 7083                }
 7084                editor
 7085                    .update(cx, |editor, cx| {
 7086                        editor.inline_blame_popover.take();
 7087                        cx.notify();
 7088                    })
 7089                    .ok();
 7090            });
 7091            state.hide_task = Some(hide_task);
 7092            true
 7093        } else {
 7094            false
 7095        }
 7096    }
 7097
 7098    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7099        if self.pending_rename.is_some() {
 7100            return None;
 7101        }
 7102
 7103        let provider = self.semantics_provider.clone()?;
 7104        let buffer = self.buffer.read(cx);
 7105        let newest_selection = self.selections.newest_anchor().clone();
 7106        let cursor_position = newest_selection.head();
 7107        let (cursor_buffer, cursor_buffer_position) =
 7108            buffer.text_anchor_for_position(cursor_position, cx)?;
 7109        let (tail_buffer, tail_buffer_position) =
 7110            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7111        if cursor_buffer != tail_buffer {
 7112            return None;
 7113        }
 7114
 7115        let snapshot = cursor_buffer.read(cx).snapshot();
 7116        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7117        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7118        if start_word_range != end_word_range {
 7119            self.document_highlights_task.take();
 7120            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7121            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7122            return None;
 7123        }
 7124
 7125        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7126        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7127            cx.background_executor()
 7128                .timer(Duration::from_millis(debounce))
 7129                .await;
 7130
 7131            let highlights = if let Some(highlights) = cx.update(|cx| {
 7132                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7133            }) {
 7134                highlights.await.log_err()
 7135            } else {
 7136                None
 7137            };
 7138
 7139            if let Some(highlights) = highlights {
 7140                this.update(cx, |this, cx| {
 7141                    if this.pending_rename.is_some() {
 7142                        return;
 7143                    }
 7144
 7145                    let buffer = this.buffer.read(cx);
 7146                    if buffer
 7147                        .text_anchor_for_position(cursor_position, cx)
 7148                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7149                    {
 7150                        return;
 7151                    }
 7152
 7153                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7154                    let mut write_ranges = Vec::new();
 7155                    let mut read_ranges = Vec::new();
 7156                    for highlight in highlights {
 7157                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7158                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7159                        {
 7160                            let start = highlight
 7161                                .range
 7162                                .start
 7163                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7164                            let end = highlight
 7165                                .range
 7166                                .end
 7167                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7168                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7169                                continue;
 7170                            }
 7171
 7172                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7173                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7174                                write_ranges.push(range);
 7175                            } else {
 7176                                read_ranges.push(range);
 7177                            }
 7178                        }
 7179                    }
 7180
 7181                    this.highlight_background::<DocumentHighlightRead>(
 7182                        &read_ranges,
 7183                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7184                        cx,
 7185                    );
 7186                    this.highlight_background::<DocumentHighlightWrite>(
 7187                        &write_ranges,
 7188                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7189                        cx,
 7190                    );
 7191                    cx.notify();
 7192                })
 7193                .log_err();
 7194            }
 7195        }));
 7196        None
 7197    }
 7198
 7199    fn prepare_highlight_query_from_selection(
 7200        &mut self,
 7201        window: &Window,
 7202        cx: &mut Context<Editor>,
 7203    ) -> Option<(String, Range<Anchor>)> {
 7204        if matches!(self.mode, EditorMode::SingleLine) {
 7205            return None;
 7206        }
 7207        if !EditorSettings::get_global(cx).selection_highlight {
 7208            return None;
 7209        }
 7210        if self.selections.count() != 1 || self.selections.line_mode() {
 7211            return None;
 7212        }
 7213        let snapshot = self.snapshot(window, cx);
 7214        let selection = self.selections.newest::<Point>(&snapshot);
 7215        // If the selection spans multiple rows OR it is empty
 7216        if selection.start.row != selection.end.row
 7217            || selection.start.column == selection.end.column
 7218        {
 7219            return None;
 7220        }
 7221        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7222        let query = snapshot
 7223            .buffer_snapshot()
 7224            .text_for_range(selection_anchor_range.clone())
 7225            .collect::<String>();
 7226        if query.trim().is_empty() {
 7227            return None;
 7228        }
 7229        Some((query, selection_anchor_range))
 7230    }
 7231
 7232    #[ztracing::instrument(skip_all)]
 7233    fn update_selection_occurrence_highlights(
 7234        &mut self,
 7235        query_text: String,
 7236        query_range: Range<Anchor>,
 7237        multi_buffer_range_to_query: Range<Point>,
 7238        use_debounce: bool,
 7239        window: &mut Window,
 7240        cx: &mut Context<Editor>,
 7241    ) -> Task<()> {
 7242        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7243        cx.spawn_in(window, async move |editor, cx| {
 7244            if use_debounce {
 7245                cx.background_executor()
 7246                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7247                    .await;
 7248            }
 7249            let match_task = cx.background_spawn(async move {
 7250                let buffer_ranges = multi_buffer_snapshot
 7251                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7252                    .into_iter()
 7253                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7254                let mut match_ranges = Vec::new();
 7255                let Ok(regex) = project::search::SearchQuery::text(
 7256                    query_text.clone(),
 7257                    false,
 7258                    false,
 7259                    false,
 7260                    Default::default(),
 7261                    Default::default(),
 7262                    false,
 7263                    None,
 7264                ) else {
 7265                    return Vec::default();
 7266                };
 7267                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7268                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7269                    match_ranges.extend(
 7270                        regex
 7271                            .search(
 7272                                buffer_snapshot,
 7273                                Some(search_range.start.0..search_range.end.0),
 7274                            )
 7275                            .await
 7276                            .into_iter()
 7277                            .filter_map(|match_range| {
 7278                                let match_start = buffer_snapshot
 7279                                    .anchor_after(search_range.start + match_range.start);
 7280                                let match_end = buffer_snapshot
 7281                                    .anchor_before(search_range.start + match_range.end);
 7282                                let match_anchor_range =
 7283                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7284                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7285                            }),
 7286                    );
 7287                }
 7288                match_ranges
 7289            });
 7290            let match_ranges = match_task.await;
 7291            editor
 7292                .update_in(cx, |editor, _, cx| {
 7293                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7294                    if !match_ranges.is_empty() {
 7295                        editor.highlight_background::<SelectedTextHighlight>(
 7296                            &match_ranges,
 7297                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7298                            cx,
 7299                        )
 7300                    }
 7301                })
 7302                .log_err();
 7303        })
 7304    }
 7305
 7306    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7307        struct NewlineFold;
 7308        let type_id = std::any::TypeId::of::<NewlineFold>();
 7309        if !self.mode.is_single_line() {
 7310            return;
 7311        }
 7312        let snapshot = self.snapshot(window, cx);
 7313        if snapshot.buffer_snapshot().max_point().row == 0 {
 7314            return;
 7315        }
 7316        let task = cx.background_spawn(async move {
 7317            let new_newlines = snapshot
 7318                .buffer_chars_at(MultiBufferOffset(0))
 7319                .filter_map(|(c, i)| {
 7320                    if c == '\n' {
 7321                        Some(
 7322                            snapshot.buffer_snapshot().anchor_after(i)
 7323                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7324                        )
 7325                    } else {
 7326                        None
 7327                    }
 7328                })
 7329                .collect::<Vec<_>>();
 7330            let existing_newlines = snapshot
 7331                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7332                .filter_map(|fold| {
 7333                    if fold.placeholder.type_tag == Some(type_id) {
 7334                        Some(fold.range.start..fold.range.end)
 7335                    } else {
 7336                        None
 7337                    }
 7338                })
 7339                .collect::<Vec<_>>();
 7340
 7341            (new_newlines, existing_newlines)
 7342        });
 7343        self.folding_newlines = cx.spawn(async move |this, cx| {
 7344            let (new_newlines, existing_newlines) = task.await;
 7345            if new_newlines == existing_newlines {
 7346                return;
 7347            }
 7348            let placeholder = FoldPlaceholder {
 7349                render: Arc::new(move |_, _, cx| {
 7350                    div()
 7351                        .bg(cx.theme().status().hint_background)
 7352                        .border_b_1()
 7353                        .size_full()
 7354                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7355                        .border_color(cx.theme().status().hint)
 7356                        .child("\\n")
 7357                        .into_any()
 7358                }),
 7359                constrain_width: false,
 7360                merge_adjacent: false,
 7361                type_tag: Some(type_id),
 7362            };
 7363            let creases = new_newlines
 7364                .into_iter()
 7365                .map(|range| Crease::simple(range, placeholder.clone()))
 7366                .collect();
 7367            this.update(cx, |this, cx| {
 7368                this.display_map.update(cx, |display_map, cx| {
 7369                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7370                    display_map.fold(creases, cx);
 7371                });
 7372            })
 7373            .ok();
 7374        });
 7375    }
 7376
 7377    #[ztracing::instrument(skip_all)]
 7378    fn refresh_selected_text_highlights(
 7379        &mut self,
 7380        on_buffer_edit: bool,
 7381        window: &mut Window,
 7382        cx: &mut Context<Editor>,
 7383    ) {
 7384        let Some((query_text, query_range)) =
 7385            self.prepare_highlight_query_from_selection(window, cx)
 7386        else {
 7387            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7388            self.quick_selection_highlight_task.take();
 7389            self.debounced_selection_highlight_task.take();
 7390            return;
 7391        };
 7392        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7393        if on_buffer_edit
 7394            || self
 7395                .quick_selection_highlight_task
 7396                .as_ref()
 7397                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7398        {
 7399            let multi_buffer_visible_start = self
 7400                .scroll_manager
 7401                .anchor()
 7402                .anchor
 7403                .to_point(&multi_buffer_snapshot);
 7404            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7405                multi_buffer_visible_start
 7406                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7407                Bias::Left,
 7408            );
 7409            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7410            self.quick_selection_highlight_task = Some((
 7411                query_range.clone(),
 7412                self.update_selection_occurrence_highlights(
 7413                    query_text.clone(),
 7414                    query_range.clone(),
 7415                    multi_buffer_visible_range,
 7416                    false,
 7417                    window,
 7418                    cx,
 7419                ),
 7420            ));
 7421        }
 7422        if on_buffer_edit
 7423            || self
 7424                .debounced_selection_highlight_task
 7425                .as_ref()
 7426                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7427        {
 7428            let multi_buffer_start = multi_buffer_snapshot
 7429                .anchor_before(MultiBufferOffset(0))
 7430                .to_point(&multi_buffer_snapshot);
 7431            let multi_buffer_end = multi_buffer_snapshot
 7432                .anchor_after(multi_buffer_snapshot.len())
 7433                .to_point(&multi_buffer_snapshot);
 7434            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7435            self.debounced_selection_highlight_task = Some((
 7436                query_range.clone(),
 7437                self.update_selection_occurrence_highlights(
 7438                    query_text,
 7439                    query_range,
 7440                    multi_buffer_full_range,
 7441                    true,
 7442                    window,
 7443                    cx,
 7444                ),
 7445            ));
 7446        }
 7447    }
 7448
 7449    pub fn refresh_edit_prediction(
 7450        &mut self,
 7451        debounce: bool,
 7452        user_requested: bool,
 7453        window: &mut Window,
 7454        cx: &mut Context<Self>,
 7455    ) -> Option<()> {
 7456        if DisableAiSettings::get_global(cx).disable_ai {
 7457            return None;
 7458        }
 7459
 7460        let provider = self.edit_prediction_provider()?;
 7461        let cursor = self.selections.newest_anchor().head();
 7462        let (buffer, cursor_buffer_position) =
 7463            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7464
 7465        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7466            self.discard_edit_prediction(false, cx);
 7467            return None;
 7468        }
 7469
 7470        self.update_visible_edit_prediction(window, cx);
 7471
 7472        if !user_requested
 7473            && (!self.should_show_edit_predictions()
 7474                || !self.is_focused(window)
 7475                || buffer.read(cx).is_empty())
 7476        {
 7477            self.discard_edit_prediction(false, cx);
 7478            return None;
 7479        }
 7480
 7481        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7482        Some(())
 7483    }
 7484
 7485    fn show_edit_predictions_in_menu(&self) -> bool {
 7486        match self.edit_prediction_settings {
 7487            EditPredictionSettings::Disabled => false,
 7488            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7489        }
 7490    }
 7491
 7492    pub fn edit_predictions_enabled(&self) -> bool {
 7493        match self.edit_prediction_settings {
 7494            EditPredictionSettings::Disabled => false,
 7495            EditPredictionSettings::Enabled { .. } => true,
 7496        }
 7497    }
 7498
 7499    fn edit_prediction_requires_modifier(&self) -> bool {
 7500        match self.edit_prediction_settings {
 7501            EditPredictionSettings::Disabled => false,
 7502            EditPredictionSettings::Enabled {
 7503                preview_requires_modifier,
 7504                ..
 7505            } => preview_requires_modifier,
 7506        }
 7507    }
 7508
 7509    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7510        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7511            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7512            self.discard_edit_prediction(false, cx);
 7513        } else {
 7514            let selection = self.selections.newest_anchor();
 7515            let cursor = selection.head();
 7516
 7517            if let Some((buffer, cursor_buffer_position)) =
 7518                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7519            {
 7520                self.edit_prediction_settings =
 7521                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7522            }
 7523        }
 7524    }
 7525
 7526    fn edit_prediction_settings_at_position(
 7527        &self,
 7528        buffer: &Entity<Buffer>,
 7529        buffer_position: language::Anchor,
 7530        cx: &App,
 7531    ) -> EditPredictionSettings {
 7532        if !self.mode.is_full()
 7533            || !self.show_edit_predictions_override.unwrap_or(true)
 7534            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7535        {
 7536            return EditPredictionSettings::Disabled;
 7537        }
 7538
 7539        let buffer = buffer.read(cx);
 7540
 7541        let file = buffer.file();
 7542
 7543        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7544            return EditPredictionSettings::Disabled;
 7545        };
 7546
 7547        let by_provider = matches!(
 7548            self.menu_edit_predictions_policy,
 7549            MenuEditPredictionsPolicy::ByProvider
 7550        );
 7551
 7552        let show_in_menu = by_provider
 7553            && self
 7554                .edit_prediction_provider
 7555                .as_ref()
 7556                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7557
 7558        let preview_requires_modifier =
 7559            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7560
 7561        EditPredictionSettings::Enabled {
 7562            show_in_menu,
 7563            preview_requires_modifier,
 7564        }
 7565    }
 7566
 7567    fn should_show_edit_predictions(&self) -> bool {
 7568        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7569    }
 7570
 7571    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7572        matches!(
 7573            self.edit_prediction_preview,
 7574            EditPredictionPreview::Active { .. }
 7575        )
 7576    }
 7577
 7578    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7579        let cursor = self.selections.newest_anchor().head();
 7580        if let Some((buffer, cursor_position)) =
 7581            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7582        {
 7583            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7584        } else {
 7585            false
 7586        }
 7587    }
 7588
 7589    pub fn supports_minimap(&self, cx: &App) -> bool {
 7590        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7591    }
 7592
 7593    fn edit_predictions_enabled_in_buffer(
 7594        &self,
 7595        buffer: &Entity<Buffer>,
 7596        buffer_position: language::Anchor,
 7597        cx: &App,
 7598    ) -> bool {
 7599        maybe!({
 7600            if self.read_only(cx) {
 7601                return Some(false);
 7602            }
 7603            let provider = self.edit_prediction_provider()?;
 7604            if !provider.is_enabled(buffer, buffer_position, cx) {
 7605                return Some(false);
 7606            }
 7607            let buffer = buffer.read(cx);
 7608            let Some(file) = buffer.file() else {
 7609                return Some(true);
 7610            };
 7611            let settings = all_language_settings(Some(file), cx);
 7612            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7613        })
 7614        .unwrap_or(false)
 7615    }
 7616
 7617    pub fn show_edit_prediction(
 7618        &mut self,
 7619        _: &ShowEditPrediction,
 7620        window: &mut Window,
 7621        cx: &mut Context<Self>,
 7622    ) {
 7623        if !self.has_active_edit_prediction() {
 7624            self.refresh_edit_prediction(false, true, window, cx);
 7625            return;
 7626        }
 7627
 7628        self.update_visible_edit_prediction(window, cx);
 7629    }
 7630
 7631    pub fn display_cursor_names(
 7632        &mut self,
 7633        _: &DisplayCursorNames,
 7634        window: &mut Window,
 7635        cx: &mut Context<Self>,
 7636    ) {
 7637        self.show_cursor_names(window, cx);
 7638    }
 7639
 7640    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7641        self.show_cursor_names = true;
 7642        cx.notify();
 7643        cx.spawn_in(window, async move |this, cx| {
 7644            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7645            this.update(cx, |this, cx| {
 7646                this.show_cursor_names = false;
 7647                cx.notify()
 7648            })
 7649            .ok()
 7650        })
 7651        .detach();
 7652    }
 7653
 7654    pub fn accept_partial_edit_prediction(
 7655        &mut self,
 7656        granularity: EditPredictionGranularity,
 7657        window: &mut Window,
 7658        cx: &mut Context<Self>,
 7659    ) {
 7660        if self.show_edit_predictions_in_menu() {
 7661            self.hide_context_menu(window, cx);
 7662        }
 7663
 7664        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7665            return;
 7666        };
 7667
 7668        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7669            return;
 7670        }
 7671
 7672        match &active_edit_prediction.completion {
 7673            EditPrediction::MoveWithin { target, .. } => {
 7674                let target = *target;
 7675
 7676                if matches!(granularity, EditPredictionGranularity::Full) {
 7677                    if let Some(position_map) = &self.last_position_map {
 7678                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7679                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7680
 7681                        if is_visible || !self.edit_prediction_requires_modifier() {
 7682                            self.unfold_ranges(&[target..target], true, false, cx);
 7683                            self.change_selections(
 7684                                SelectionEffects::scroll(Autoscroll::newest()),
 7685                                window,
 7686                                cx,
 7687                                |selections| {
 7688                                    selections.select_anchor_ranges([target..target]);
 7689                                },
 7690                            );
 7691                            self.clear_row_highlights::<EditPredictionPreview>();
 7692                            self.edit_prediction_preview
 7693                                .set_previous_scroll_position(None);
 7694                        } else {
 7695                            // Highlight and request scroll
 7696                            self.edit_prediction_preview
 7697                                .set_previous_scroll_position(Some(
 7698                                    position_map.snapshot.scroll_anchor,
 7699                                ));
 7700                            self.highlight_rows::<EditPredictionPreview>(
 7701                                target..target,
 7702                                cx.theme().colors().editor_highlighted_line_background,
 7703                                RowHighlightOptions {
 7704                                    autoscroll: true,
 7705                                    ..Default::default()
 7706                                },
 7707                                cx,
 7708                            );
 7709                            self.request_autoscroll(Autoscroll::fit(), cx);
 7710                        }
 7711                    }
 7712                } else {
 7713                    self.change_selections(
 7714                        SelectionEffects::scroll(Autoscroll::newest()),
 7715                        window,
 7716                        cx,
 7717                        |selections| {
 7718                            selections.select_anchor_ranges([target..target]);
 7719                        },
 7720                    );
 7721                }
 7722            }
 7723            EditPrediction::MoveOutside { snapshot, target } => {
 7724                if let Some(workspace) = self.workspace() {
 7725                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7726                        .detach_and_log_err(cx);
 7727                }
 7728            }
 7729            EditPrediction::Edit { edits, .. } => {
 7730                self.report_edit_prediction_event(
 7731                    active_edit_prediction.completion_id.clone(),
 7732                    true,
 7733                    cx,
 7734                );
 7735
 7736                match granularity {
 7737                    EditPredictionGranularity::Full => {
 7738                        if let Some(provider) = self.edit_prediction_provider() {
 7739                            provider.accept(cx);
 7740                        }
 7741
 7742                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7743                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7744                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7745
 7746                        self.buffer.update(cx, |buffer, cx| {
 7747                            buffer.edit(edits.iter().cloned(), None, cx)
 7748                        });
 7749
 7750                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7751                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7752                        });
 7753
 7754                        let selections = self.selections.disjoint_anchors_arc();
 7755                        if let Some(transaction_id_now) =
 7756                            self.buffer.read(cx).last_transaction_id(cx)
 7757                        {
 7758                            if transaction_id_prev != Some(transaction_id_now) {
 7759                                self.selection_history
 7760                                    .insert_transaction(transaction_id_now, selections);
 7761                            }
 7762                        }
 7763
 7764                        self.update_visible_edit_prediction(window, cx);
 7765                        if self.active_edit_prediction.is_none() {
 7766                            self.refresh_edit_prediction(true, true, window, cx);
 7767                        }
 7768                        cx.notify();
 7769                    }
 7770                    _ => {
 7771                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7772                        let cursor_offset = self
 7773                            .selections
 7774                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7775                            .head();
 7776
 7777                        let insertion = edits.iter().find_map(|(range, text)| {
 7778                            let range = range.to_offset(&snapshot);
 7779                            if range.is_empty() && range.start == cursor_offset {
 7780                                Some(text)
 7781                            } else {
 7782                                None
 7783                            }
 7784                        });
 7785
 7786                        if let Some(text) = insertion {
 7787                            let text_to_insert = match granularity {
 7788                                EditPredictionGranularity::Word => {
 7789                                    let mut partial = text
 7790                                        .chars()
 7791                                        .by_ref()
 7792                                        .take_while(|c| c.is_alphabetic())
 7793                                        .collect::<String>();
 7794                                    if partial.is_empty() {
 7795                                        partial = text
 7796                                            .chars()
 7797                                            .by_ref()
 7798                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7799                                            .collect::<String>();
 7800                                    }
 7801                                    partial
 7802                                }
 7803                                EditPredictionGranularity::Line => {
 7804                                    if let Some(line) = text.split_inclusive('\n').next() {
 7805                                        line.to_string()
 7806                                    } else {
 7807                                        text.to_string()
 7808                                    }
 7809                                }
 7810                                EditPredictionGranularity::Full => unreachable!(),
 7811                            };
 7812
 7813                            cx.emit(EditorEvent::InputHandled {
 7814                                utf16_range_to_replace: None,
 7815                                text: text_to_insert.clone().into(),
 7816                            });
 7817
 7818                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7819                            self.refresh_edit_prediction(true, true, window, cx);
 7820                            cx.notify();
 7821                        } else {
 7822                            self.accept_partial_edit_prediction(
 7823                                EditPredictionGranularity::Full,
 7824                                window,
 7825                                cx,
 7826                            );
 7827                        }
 7828                    }
 7829                }
 7830            }
 7831        }
 7832
 7833        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7834    }
 7835
 7836    pub fn accept_next_word_edit_prediction(
 7837        &mut self,
 7838        _: &AcceptNextWordEditPrediction,
 7839        window: &mut Window,
 7840        cx: &mut Context<Self>,
 7841    ) {
 7842        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7843    }
 7844
 7845    pub fn accept_next_line_edit_prediction(
 7846        &mut self,
 7847        _: &AcceptNextLineEditPrediction,
 7848        window: &mut Window,
 7849        cx: &mut Context<Self>,
 7850    ) {
 7851        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7852    }
 7853
 7854    pub fn accept_edit_prediction(
 7855        &mut self,
 7856        _: &AcceptEditPrediction,
 7857        window: &mut Window,
 7858        cx: &mut Context<Self>,
 7859    ) {
 7860        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7861    }
 7862
 7863    fn discard_edit_prediction(
 7864        &mut self,
 7865        should_report_edit_prediction_event: bool,
 7866        cx: &mut Context<Self>,
 7867    ) -> bool {
 7868        if should_report_edit_prediction_event {
 7869            let completion_id = self
 7870                .active_edit_prediction
 7871                .as_ref()
 7872                .and_then(|active_completion| active_completion.completion_id.clone());
 7873
 7874            self.report_edit_prediction_event(completion_id, false, cx);
 7875        }
 7876
 7877        if let Some(provider) = self.edit_prediction_provider() {
 7878            provider.discard(cx);
 7879        }
 7880
 7881        self.take_active_edit_prediction(cx)
 7882    }
 7883
 7884    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7885        let Some(provider) = self.edit_prediction_provider() else {
 7886            return;
 7887        };
 7888
 7889        let Some((_, buffer, _)) = self
 7890            .buffer
 7891            .read(cx)
 7892            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7893        else {
 7894            return;
 7895        };
 7896
 7897        let extension = buffer
 7898            .read(cx)
 7899            .file()
 7900            .and_then(|file| Some(file.path().extension()?.to_string()));
 7901
 7902        let event_type = match accepted {
 7903            true => "Edit Prediction Accepted",
 7904            false => "Edit Prediction Discarded",
 7905        };
 7906        telemetry::event!(
 7907            event_type,
 7908            provider = provider.name(),
 7909            prediction_id = id,
 7910            suggestion_accepted = accepted,
 7911            file_extension = extension,
 7912        );
 7913    }
 7914
 7915    fn open_editor_at_anchor(
 7916        snapshot: &language::BufferSnapshot,
 7917        target: language::Anchor,
 7918        workspace: &Entity<Workspace>,
 7919        window: &mut Window,
 7920        cx: &mut App,
 7921    ) -> Task<Result<()>> {
 7922        workspace.update(cx, |workspace, cx| {
 7923            let path = snapshot.file().map(|file| file.full_path(cx));
 7924            let Some(path) =
 7925                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7926            else {
 7927                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7928            };
 7929            let target = text::ToPoint::to_point(&target, snapshot);
 7930            let item = workspace.open_path(path, None, true, window, cx);
 7931            window.spawn(cx, async move |cx| {
 7932                let Some(editor) = item.await?.downcast::<Editor>() else {
 7933                    return Ok(());
 7934                };
 7935                editor
 7936                    .update_in(cx, |editor, window, cx| {
 7937                        editor.go_to_singleton_buffer_point(target, window, cx);
 7938                    })
 7939                    .ok();
 7940                anyhow::Ok(())
 7941            })
 7942        })
 7943    }
 7944
 7945    pub fn has_active_edit_prediction(&self) -> bool {
 7946        self.active_edit_prediction.is_some()
 7947    }
 7948
 7949    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7950        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7951            return false;
 7952        };
 7953
 7954        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7955        self.clear_highlights::<EditPredictionHighlight>(cx);
 7956        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7957        true
 7958    }
 7959
 7960    /// Returns true when we're displaying the edit prediction popover below the cursor
 7961    /// like we are not previewing and the LSP autocomplete menu is visible
 7962    /// or we are in `when_holding_modifier` mode.
 7963    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7964        if self.edit_prediction_preview_is_active()
 7965            || !self.show_edit_predictions_in_menu()
 7966            || !self.edit_predictions_enabled()
 7967        {
 7968            return false;
 7969        }
 7970
 7971        if self.has_visible_completions_menu() {
 7972            return true;
 7973        }
 7974
 7975        has_completion && self.edit_prediction_requires_modifier()
 7976    }
 7977
 7978    fn handle_modifiers_changed(
 7979        &mut self,
 7980        modifiers: Modifiers,
 7981        position_map: &PositionMap,
 7982        window: &mut Window,
 7983        cx: &mut Context<Self>,
 7984    ) {
 7985        // Ensure that the edit prediction preview is updated, even when not
 7986        // enabled, if there's an active edit prediction preview.
 7987        if self.show_edit_predictions_in_menu()
 7988            || matches!(
 7989                self.edit_prediction_preview,
 7990                EditPredictionPreview::Active { .. }
 7991            )
 7992        {
 7993            self.update_edit_prediction_preview(&modifiers, window, cx);
 7994        }
 7995
 7996        self.update_selection_mode(&modifiers, position_map, window, cx);
 7997
 7998        let mouse_position = window.mouse_position();
 7999        if !position_map.text_hitbox.is_hovered(window) {
 8000            return;
 8001        }
 8002
 8003        self.update_hovered_link(
 8004            position_map.point_for_position(mouse_position),
 8005            &position_map.snapshot,
 8006            modifiers,
 8007            window,
 8008            cx,
 8009        )
 8010    }
 8011
 8012    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8013        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8014            MultiCursorModifier::Alt => modifiers.secondary(),
 8015            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8016        }
 8017    }
 8018
 8019    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8020        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8021            MultiCursorModifier::Alt => modifiers.alt,
 8022            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8023        }
 8024    }
 8025
 8026    fn columnar_selection_mode(
 8027        modifiers: &Modifiers,
 8028        cx: &mut Context<Self>,
 8029    ) -> Option<ColumnarMode> {
 8030        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8031            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8032                Some(ColumnarMode::FromMouse)
 8033            } else if Self::is_alt_pressed(modifiers, cx) {
 8034                Some(ColumnarMode::FromSelection)
 8035            } else {
 8036                None
 8037            }
 8038        } else {
 8039            None
 8040        }
 8041    }
 8042
 8043    fn update_selection_mode(
 8044        &mut self,
 8045        modifiers: &Modifiers,
 8046        position_map: &PositionMap,
 8047        window: &mut Window,
 8048        cx: &mut Context<Self>,
 8049    ) {
 8050        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8051            return;
 8052        };
 8053        if self.selections.pending_anchor().is_none() {
 8054            return;
 8055        }
 8056
 8057        let mouse_position = window.mouse_position();
 8058        let point_for_position = position_map.point_for_position(mouse_position);
 8059        let position = point_for_position.previous_valid;
 8060
 8061        self.select(
 8062            SelectPhase::BeginColumnar {
 8063                position,
 8064                reset: false,
 8065                mode,
 8066                goal_column: point_for_position.exact_unclipped.column(),
 8067            },
 8068            window,
 8069            cx,
 8070        );
 8071    }
 8072
 8073    fn update_edit_prediction_preview(
 8074        &mut self,
 8075        modifiers: &Modifiers,
 8076        window: &mut Window,
 8077        cx: &mut Context<Self>,
 8078    ) {
 8079        let mut modifiers_held = false;
 8080
 8081        // Check bindings for all granularities.
 8082        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8083        let granularities = [
 8084            EditPredictionGranularity::Full,
 8085            EditPredictionGranularity::Line,
 8086            EditPredictionGranularity::Word,
 8087        ];
 8088
 8089        for granularity in granularities {
 8090            if let Some(keystroke) = self
 8091                .accept_edit_prediction_keybind(granularity, window, cx)
 8092                .keystroke()
 8093            {
 8094                modifiers_held = modifiers_held
 8095                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8096            }
 8097        }
 8098
 8099        if modifiers_held {
 8100            if matches!(
 8101                self.edit_prediction_preview,
 8102                EditPredictionPreview::Inactive { .. }
 8103            ) {
 8104                self.edit_prediction_preview = EditPredictionPreview::Active {
 8105                    previous_scroll_position: None,
 8106                    since: Instant::now(),
 8107                };
 8108
 8109                self.update_visible_edit_prediction(window, cx);
 8110                cx.notify();
 8111            }
 8112        } else if let EditPredictionPreview::Active {
 8113            previous_scroll_position,
 8114            since,
 8115        } = self.edit_prediction_preview
 8116        {
 8117            if let (Some(previous_scroll_position), Some(position_map)) =
 8118                (previous_scroll_position, self.last_position_map.as_ref())
 8119            {
 8120                self.set_scroll_position(
 8121                    previous_scroll_position
 8122                        .scroll_position(&position_map.snapshot.display_snapshot),
 8123                    window,
 8124                    cx,
 8125                );
 8126            }
 8127
 8128            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8129                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8130            };
 8131            self.clear_row_highlights::<EditPredictionPreview>();
 8132            self.update_visible_edit_prediction(window, cx);
 8133            cx.notify();
 8134        }
 8135    }
 8136
 8137    fn update_visible_edit_prediction(
 8138        &mut self,
 8139        _window: &mut Window,
 8140        cx: &mut Context<Self>,
 8141    ) -> Option<()> {
 8142        if DisableAiSettings::get_global(cx).disable_ai {
 8143            return None;
 8144        }
 8145
 8146        if self.ime_transaction.is_some() {
 8147            self.discard_edit_prediction(false, cx);
 8148            return None;
 8149        }
 8150
 8151        let selection = self.selections.newest_anchor();
 8152        let cursor = selection.head();
 8153        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8154        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8155        let excerpt_id = cursor.excerpt_id;
 8156
 8157        let show_in_menu = self.show_edit_predictions_in_menu();
 8158        let completions_menu_has_precedence = !show_in_menu
 8159            && (self.context_menu.borrow().is_some()
 8160                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8161
 8162        if completions_menu_has_precedence
 8163            || !offset_selection.is_empty()
 8164            || self
 8165                .active_edit_prediction
 8166                .as_ref()
 8167                .is_some_and(|completion| {
 8168                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8169                        return false;
 8170                    };
 8171                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8172                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8173                    !invalidation_range.contains(&offset_selection.head())
 8174                })
 8175        {
 8176            self.discard_edit_prediction(false, cx);
 8177            return None;
 8178        }
 8179
 8180        self.take_active_edit_prediction(cx);
 8181        let Some(provider) = self.edit_prediction_provider() else {
 8182            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8183            return None;
 8184        };
 8185
 8186        let (buffer, cursor_buffer_position) =
 8187            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8188
 8189        self.edit_prediction_settings =
 8190            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8191
 8192        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8193
 8194        if self.edit_prediction_indent_conflict {
 8195            let cursor_point = cursor.to_point(&multibuffer);
 8196            let mut suggested_indent = None;
 8197            multibuffer.suggested_indents_callback(
 8198                cursor_point.row..cursor_point.row + 1,
 8199                |_, indent| {
 8200                    suggested_indent = Some(indent);
 8201                    ControlFlow::Break(())
 8202                },
 8203                cx,
 8204            );
 8205
 8206            if let Some(indent) = suggested_indent
 8207                && indent.len == cursor_point.column
 8208            {
 8209                self.edit_prediction_indent_conflict = false;
 8210            }
 8211        }
 8212
 8213        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8214
 8215        let (completion_id, edits, edit_preview) = match edit_prediction {
 8216            edit_prediction_types::EditPrediction::Local {
 8217                id,
 8218                edits,
 8219                edit_preview,
 8220            } => (id, edits, edit_preview),
 8221            edit_prediction_types::EditPrediction::Jump {
 8222                id,
 8223                snapshot,
 8224                target,
 8225            } => {
 8226                if let Some(provider) = &self.edit_prediction_provider {
 8227                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8228                }
 8229                self.stale_edit_prediction_in_menu = None;
 8230                self.active_edit_prediction = Some(EditPredictionState {
 8231                    inlay_ids: vec![],
 8232                    completion: EditPrediction::MoveOutside { snapshot, target },
 8233                    completion_id: id,
 8234                    invalidation_range: None,
 8235                });
 8236                cx.notify();
 8237                return Some(());
 8238            }
 8239        };
 8240
 8241        let edits = edits
 8242            .into_iter()
 8243            .flat_map(|(range, new_text)| {
 8244                Some((
 8245                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8246                    new_text,
 8247                ))
 8248            })
 8249            .collect::<Vec<_>>();
 8250        if edits.is_empty() {
 8251            return None;
 8252        }
 8253
 8254        let first_edit_start = edits.first().unwrap().0.start;
 8255        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8256        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8257
 8258        let last_edit_end = edits.last().unwrap().0.end;
 8259        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8260        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8261
 8262        let cursor_row = cursor.to_point(&multibuffer).row;
 8263
 8264        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8265
 8266        let mut inlay_ids = Vec::new();
 8267        let invalidation_row_range;
 8268        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8269            Some(cursor_row..edit_end_row)
 8270        } else if cursor_row > edit_end_row {
 8271            Some(edit_start_row..cursor_row)
 8272        } else {
 8273            None
 8274        };
 8275        let supports_jump = self
 8276            .edit_prediction_provider
 8277            .as_ref()
 8278            .map(|provider| provider.provider.supports_jump_to_edit())
 8279            .unwrap_or(true);
 8280
 8281        let is_move = supports_jump
 8282            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8283        let completion = if is_move {
 8284            if let Some(provider) = &self.edit_prediction_provider {
 8285                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8286            }
 8287            invalidation_row_range =
 8288                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8289            let target = first_edit_start;
 8290            EditPrediction::MoveWithin { target, snapshot }
 8291        } else {
 8292            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8293                && !self.edit_predictions_hidden_for_vim_mode;
 8294
 8295            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8296                if provider.show_tab_accept_marker() {
 8297                    EditDisplayMode::TabAccept
 8298                } else {
 8299                    EditDisplayMode::Inline
 8300                }
 8301            } else {
 8302                EditDisplayMode::DiffPopover
 8303            };
 8304
 8305            if show_completions_in_buffer {
 8306                if let Some(provider) = &self.edit_prediction_provider {
 8307                    let suggestion_display_type = match display_mode {
 8308                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8309                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8310                            SuggestionDisplayType::GhostText
 8311                        }
 8312                    };
 8313                    provider.provider.did_show(suggestion_display_type, cx);
 8314                }
 8315                if edits
 8316                    .iter()
 8317                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8318                {
 8319                    let mut inlays = Vec::new();
 8320                    for (range, new_text) in &edits {
 8321                        let inlay = Inlay::edit_prediction(
 8322                            post_inc(&mut self.next_inlay_id),
 8323                            range.start,
 8324                            new_text.as_ref(),
 8325                        );
 8326                        inlay_ids.push(inlay.id);
 8327                        inlays.push(inlay);
 8328                    }
 8329
 8330                    self.splice_inlays(&[], inlays, cx);
 8331                } else {
 8332                    let background_color = cx.theme().status().deleted_background;
 8333                    self.highlight_text::<EditPredictionHighlight>(
 8334                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8335                        HighlightStyle {
 8336                            background_color: Some(background_color),
 8337                            ..Default::default()
 8338                        },
 8339                        cx,
 8340                    );
 8341                }
 8342            }
 8343
 8344            invalidation_row_range = edit_start_row..edit_end_row;
 8345
 8346            EditPrediction::Edit {
 8347                edits,
 8348                edit_preview,
 8349                display_mode,
 8350                snapshot,
 8351            }
 8352        };
 8353
 8354        let invalidation_range = multibuffer
 8355            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8356            ..multibuffer.anchor_after(Point::new(
 8357                invalidation_row_range.end,
 8358                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8359            ));
 8360
 8361        self.stale_edit_prediction_in_menu = None;
 8362        self.active_edit_prediction = Some(EditPredictionState {
 8363            inlay_ids,
 8364            completion,
 8365            completion_id,
 8366            invalidation_range: Some(invalidation_range),
 8367        });
 8368
 8369        cx.notify();
 8370
 8371        Some(())
 8372    }
 8373
 8374    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8375        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8376    }
 8377
 8378    fn clear_tasks(&mut self) {
 8379        self.tasks.clear()
 8380    }
 8381
 8382    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8383        if self.tasks.insert(key, value).is_some() {
 8384            // This case should hopefully be rare, but just in case...
 8385            log::error!(
 8386                "multiple different run targets found on a single line, only the last target will be rendered"
 8387            )
 8388        }
 8389    }
 8390
 8391    /// Get all display points of breakpoints that will be rendered within editor
 8392    ///
 8393    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8394    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8395    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8396    fn active_breakpoints(
 8397        &self,
 8398        range: Range<DisplayRow>,
 8399        window: &mut Window,
 8400        cx: &mut Context<Self>,
 8401    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8402        let mut breakpoint_display_points = HashMap::default();
 8403
 8404        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8405            return breakpoint_display_points;
 8406        };
 8407
 8408        let snapshot = self.snapshot(window, cx);
 8409
 8410        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8411        let Some(project) = self.project() else {
 8412            return breakpoint_display_points;
 8413        };
 8414
 8415        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8416            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8417
 8418        for (buffer_snapshot, range, excerpt_id) in
 8419            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8420        {
 8421            let Some(buffer) = project
 8422                .read(cx)
 8423                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8424            else {
 8425                continue;
 8426            };
 8427            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8428                &buffer,
 8429                Some(
 8430                    buffer_snapshot.anchor_before(range.start)
 8431                        ..buffer_snapshot.anchor_after(range.end),
 8432                ),
 8433                buffer_snapshot,
 8434                cx,
 8435            );
 8436            for (breakpoint, state) in breakpoints {
 8437                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8438                let position = multi_buffer_anchor
 8439                    .to_point(&multi_buffer_snapshot)
 8440                    .to_display_point(&snapshot);
 8441
 8442                breakpoint_display_points.insert(
 8443                    position.row(),
 8444                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8445                );
 8446            }
 8447        }
 8448
 8449        breakpoint_display_points
 8450    }
 8451
 8452    fn breakpoint_context_menu(
 8453        &self,
 8454        anchor: Anchor,
 8455        window: &mut Window,
 8456        cx: &mut Context<Self>,
 8457    ) -> Entity<ui::ContextMenu> {
 8458        let weak_editor = cx.weak_entity();
 8459        let focus_handle = self.focus_handle(cx);
 8460
 8461        let row = self
 8462            .buffer
 8463            .read(cx)
 8464            .snapshot(cx)
 8465            .summary_for_anchor::<Point>(&anchor)
 8466            .row;
 8467
 8468        let breakpoint = self
 8469            .breakpoint_at_row(row, window, cx)
 8470            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8471
 8472        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8473            "Edit Log Breakpoint"
 8474        } else {
 8475            "Set Log Breakpoint"
 8476        };
 8477
 8478        let condition_breakpoint_msg = if breakpoint
 8479            .as_ref()
 8480            .is_some_and(|bp| bp.1.condition.is_some())
 8481        {
 8482            "Edit Condition Breakpoint"
 8483        } else {
 8484            "Set Condition Breakpoint"
 8485        };
 8486
 8487        let hit_condition_breakpoint_msg = if breakpoint
 8488            .as_ref()
 8489            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8490        {
 8491            "Edit Hit Condition Breakpoint"
 8492        } else {
 8493            "Set Hit Condition Breakpoint"
 8494        };
 8495
 8496        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8497            "Unset Breakpoint"
 8498        } else {
 8499            "Set Breakpoint"
 8500        };
 8501
 8502        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8503
 8504        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8505            BreakpointState::Enabled => Some("Disable"),
 8506            BreakpointState::Disabled => Some("Enable"),
 8507        });
 8508
 8509        let (anchor, breakpoint) =
 8510            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8511
 8512        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8513            menu.on_blur_subscription(Subscription::new(|| {}))
 8514                .context(focus_handle)
 8515                .when(run_to_cursor, |this| {
 8516                    let weak_editor = weak_editor.clone();
 8517                    this.entry("Run to cursor", None, move |window, cx| {
 8518                        weak_editor
 8519                            .update(cx, |editor, cx| {
 8520                                editor.change_selections(
 8521                                    SelectionEffects::no_scroll(),
 8522                                    window,
 8523                                    cx,
 8524                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8525                                );
 8526                            })
 8527                            .ok();
 8528
 8529                        window.dispatch_action(Box::new(RunToCursor), cx);
 8530                    })
 8531                    .separator()
 8532                })
 8533                .when_some(toggle_state_msg, |this, msg| {
 8534                    this.entry(msg, None, {
 8535                        let weak_editor = weak_editor.clone();
 8536                        let breakpoint = breakpoint.clone();
 8537                        move |_window, cx| {
 8538                            weak_editor
 8539                                .update(cx, |this, cx| {
 8540                                    this.edit_breakpoint_at_anchor(
 8541                                        anchor,
 8542                                        breakpoint.as_ref().clone(),
 8543                                        BreakpointEditAction::InvertState,
 8544                                        cx,
 8545                                    );
 8546                                })
 8547                                .log_err();
 8548                        }
 8549                    })
 8550                })
 8551                .entry(set_breakpoint_msg, None, {
 8552                    let weak_editor = weak_editor.clone();
 8553                    let breakpoint = breakpoint.clone();
 8554                    move |_window, cx| {
 8555                        weak_editor
 8556                            .update(cx, |this, cx| {
 8557                                this.edit_breakpoint_at_anchor(
 8558                                    anchor,
 8559                                    breakpoint.as_ref().clone(),
 8560                                    BreakpointEditAction::Toggle,
 8561                                    cx,
 8562                                );
 8563                            })
 8564                            .log_err();
 8565                    }
 8566                })
 8567                .entry(log_breakpoint_msg, None, {
 8568                    let breakpoint = breakpoint.clone();
 8569                    let weak_editor = weak_editor.clone();
 8570                    move |window, cx| {
 8571                        weak_editor
 8572                            .update(cx, |this, cx| {
 8573                                this.add_edit_breakpoint_block(
 8574                                    anchor,
 8575                                    breakpoint.as_ref(),
 8576                                    BreakpointPromptEditAction::Log,
 8577                                    window,
 8578                                    cx,
 8579                                );
 8580                            })
 8581                            .log_err();
 8582                    }
 8583                })
 8584                .entry(condition_breakpoint_msg, None, {
 8585                    let breakpoint = breakpoint.clone();
 8586                    let weak_editor = weak_editor.clone();
 8587                    move |window, cx| {
 8588                        weak_editor
 8589                            .update(cx, |this, cx| {
 8590                                this.add_edit_breakpoint_block(
 8591                                    anchor,
 8592                                    breakpoint.as_ref(),
 8593                                    BreakpointPromptEditAction::Condition,
 8594                                    window,
 8595                                    cx,
 8596                                );
 8597                            })
 8598                            .log_err();
 8599                    }
 8600                })
 8601                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8602                    weak_editor
 8603                        .update(cx, |this, cx| {
 8604                            this.add_edit_breakpoint_block(
 8605                                anchor,
 8606                                breakpoint.as_ref(),
 8607                                BreakpointPromptEditAction::HitCondition,
 8608                                window,
 8609                                cx,
 8610                            );
 8611                        })
 8612                        .log_err();
 8613                })
 8614        })
 8615    }
 8616
 8617    fn render_breakpoint(
 8618        &self,
 8619        position: Anchor,
 8620        row: DisplayRow,
 8621        breakpoint: &Breakpoint,
 8622        state: Option<BreakpointSessionState>,
 8623        cx: &mut Context<Self>,
 8624    ) -> IconButton {
 8625        let is_rejected = state.is_some_and(|s| !s.verified);
 8626        // Is it a breakpoint that shows up when hovering over gutter?
 8627        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8628            (false, false),
 8629            |PhantomBreakpointIndicator {
 8630                 is_active,
 8631                 display_row,
 8632                 collides_with_existing_breakpoint,
 8633             }| {
 8634                (
 8635                    is_active && display_row == row,
 8636                    collides_with_existing_breakpoint,
 8637                )
 8638            },
 8639        );
 8640
 8641        let (color, icon) = {
 8642            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8643                (false, false) => ui::IconName::DebugBreakpoint,
 8644                (true, false) => ui::IconName::DebugLogBreakpoint,
 8645                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8646                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8647            };
 8648
 8649            let theme_colors = cx.theme().colors();
 8650
 8651            let color = if is_phantom {
 8652                if collides_with_existing {
 8653                    Color::Custom(
 8654                        theme_colors
 8655                            .debugger_accent
 8656                            .blend(theme_colors.text.opacity(0.6)),
 8657                    )
 8658                } else {
 8659                    Color::Hint
 8660                }
 8661            } else if is_rejected {
 8662                Color::Disabled
 8663            } else {
 8664                Color::Debugger
 8665            };
 8666
 8667            (color, icon)
 8668        };
 8669
 8670        let breakpoint = Arc::from(breakpoint.clone());
 8671
 8672        let alt_as_text = gpui::Keystroke {
 8673            modifiers: Modifiers::secondary_key(),
 8674            ..Default::default()
 8675        };
 8676        let primary_action_text = if breakpoint.is_disabled() {
 8677            "Enable breakpoint"
 8678        } else if is_phantom && !collides_with_existing {
 8679            "Set breakpoint"
 8680        } else {
 8681            "Unset breakpoint"
 8682        };
 8683        let focus_handle = self.focus_handle.clone();
 8684
 8685        let meta = if is_rejected {
 8686            SharedString::from("No executable code is associated with this line.")
 8687        } else if collides_with_existing && !breakpoint.is_disabled() {
 8688            SharedString::from(format!(
 8689                "{alt_as_text}-click to disable,\nright-click for more options."
 8690            ))
 8691        } else {
 8692            SharedString::from("Right-click for more options.")
 8693        };
 8694        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8695            .icon_size(IconSize::XSmall)
 8696            .size(ui::ButtonSize::None)
 8697            .when(is_rejected, |this| {
 8698                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8699            })
 8700            .icon_color(color)
 8701            .style(ButtonStyle::Transparent)
 8702            .on_click(cx.listener({
 8703                move |editor, event: &ClickEvent, window, cx| {
 8704                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8705                        BreakpointEditAction::InvertState
 8706                    } else {
 8707                        BreakpointEditAction::Toggle
 8708                    };
 8709
 8710                    window.focus(&editor.focus_handle(cx), cx);
 8711                    editor.edit_breakpoint_at_anchor(
 8712                        position,
 8713                        breakpoint.as_ref().clone(),
 8714                        edit_action,
 8715                        cx,
 8716                    );
 8717                }
 8718            }))
 8719            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8720                editor.set_breakpoint_context_menu(
 8721                    row,
 8722                    Some(position),
 8723                    event.position(),
 8724                    window,
 8725                    cx,
 8726                );
 8727            }))
 8728            .tooltip(move |_window, cx| {
 8729                Tooltip::with_meta_in(
 8730                    primary_action_text,
 8731                    Some(&ToggleBreakpoint),
 8732                    meta.clone(),
 8733                    &focus_handle,
 8734                    cx,
 8735                )
 8736            })
 8737    }
 8738
 8739    fn build_tasks_context(
 8740        project: &Entity<Project>,
 8741        buffer: &Entity<Buffer>,
 8742        buffer_row: u32,
 8743        tasks: &Arc<RunnableTasks>,
 8744        cx: &mut Context<Self>,
 8745    ) -> Task<Option<task::TaskContext>> {
 8746        let position = Point::new(buffer_row, tasks.column);
 8747        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8748        let location = Location {
 8749            buffer: buffer.clone(),
 8750            range: range_start..range_start,
 8751        };
 8752        // Fill in the environmental variables from the tree-sitter captures
 8753        let mut captured_task_variables = TaskVariables::default();
 8754        for (capture_name, value) in tasks.extra_variables.clone() {
 8755            captured_task_variables.insert(
 8756                task::VariableName::Custom(capture_name.into()),
 8757                value.clone(),
 8758            );
 8759        }
 8760        project.update(cx, |project, cx| {
 8761            project.task_store().update(cx, |task_store, cx| {
 8762                task_store.task_context_for_location(captured_task_variables, location, cx)
 8763            })
 8764        })
 8765    }
 8766
 8767    pub fn spawn_nearest_task(
 8768        &mut self,
 8769        action: &SpawnNearestTask,
 8770        window: &mut Window,
 8771        cx: &mut Context<Self>,
 8772    ) {
 8773        let Some((workspace, _)) = self.workspace.clone() else {
 8774            return;
 8775        };
 8776        let Some(project) = self.project.clone() else {
 8777            return;
 8778        };
 8779
 8780        // Try to find a closest, enclosing node using tree-sitter that has a task
 8781        let Some((buffer, buffer_row, tasks)) = self
 8782            .find_enclosing_node_task(cx)
 8783            // Or find the task that's closest in row-distance.
 8784            .or_else(|| self.find_closest_task(cx))
 8785        else {
 8786            return;
 8787        };
 8788
 8789        let reveal_strategy = action.reveal;
 8790        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8791        cx.spawn_in(window, async move |_, cx| {
 8792            let context = task_context.await?;
 8793            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8794
 8795            let resolved = &mut resolved_task.resolved;
 8796            resolved.reveal = reveal_strategy;
 8797
 8798            workspace
 8799                .update_in(cx, |workspace, window, cx| {
 8800                    workspace.schedule_resolved_task(
 8801                        task_source_kind,
 8802                        resolved_task,
 8803                        false,
 8804                        window,
 8805                        cx,
 8806                    );
 8807                })
 8808                .ok()
 8809        })
 8810        .detach();
 8811    }
 8812
 8813    fn find_closest_task(
 8814        &mut self,
 8815        cx: &mut Context<Self>,
 8816    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8817        let cursor_row = self
 8818            .selections
 8819            .newest_adjusted(&self.display_snapshot(cx))
 8820            .head()
 8821            .row;
 8822
 8823        let ((buffer_id, row), tasks) = self
 8824            .tasks
 8825            .iter()
 8826            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8827
 8828        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8829        let tasks = Arc::new(tasks.to_owned());
 8830        Some((buffer, *row, tasks))
 8831    }
 8832
 8833    fn find_enclosing_node_task(
 8834        &mut self,
 8835        cx: &mut Context<Self>,
 8836    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8837        let snapshot = self.buffer.read(cx).snapshot(cx);
 8838        let offset = self
 8839            .selections
 8840            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8841            .head();
 8842        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8843        let offset = excerpt.map_offset_to_buffer(offset);
 8844        let buffer_id = excerpt.buffer().remote_id();
 8845
 8846        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8847        let mut cursor = layer.node().walk();
 8848
 8849        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8850            if cursor.node().end_byte() == offset.0 {
 8851                cursor.goto_next_sibling();
 8852            }
 8853        }
 8854
 8855        // Ascend to the smallest ancestor that contains the range and has a task.
 8856        loop {
 8857            let node = cursor.node();
 8858            let node_range = node.byte_range();
 8859            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8860
 8861            // Check if this node contains our offset
 8862            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8863                // If it contains offset, check for task
 8864                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8865                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8866                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8867                }
 8868            }
 8869
 8870            if !cursor.goto_parent() {
 8871                break;
 8872            }
 8873        }
 8874        None
 8875    }
 8876
 8877    fn render_run_indicator(
 8878        &self,
 8879        _style: &EditorStyle,
 8880        is_active: bool,
 8881        row: DisplayRow,
 8882        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8883        cx: &mut Context<Self>,
 8884    ) -> IconButton {
 8885        let color = Color::Muted;
 8886        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8887
 8888        IconButton::new(
 8889            ("run_indicator", row.0 as usize),
 8890            ui::IconName::PlayOutlined,
 8891        )
 8892        .shape(ui::IconButtonShape::Square)
 8893        .icon_size(IconSize::XSmall)
 8894        .icon_color(color)
 8895        .toggle_state(is_active)
 8896        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8897            let quick_launch = match e {
 8898                ClickEvent::Keyboard(_) => true,
 8899                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8900            };
 8901
 8902            window.focus(&editor.focus_handle(cx), cx);
 8903            editor.toggle_code_actions(
 8904                &ToggleCodeActions {
 8905                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8906                    quick_launch,
 8907                },
 8908                window,
 8909                cx,
 8910            );
 8911        }))
 8912        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8913            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8914        }))
 8915    }
 8916
 8917    pub fn context_menu_visible(&self) -> bool {
 8918        !self.edit_prediction_preview_is_active()
 8919            && self
 8920                .context_menu
 8921                .borrow()
 8922                .as_ref()
 8923                .is_some_and(|menu| menu.visible())
 8924    }
 8925
 8926    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8927        self.context_menu
 8928            .borrow()
 8929            .as_ref()
 8930            .map(|menu| menu.origin())
 8931    }
 8932
 8933    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8934        self.context_menu_options = Some(options);
 8935    }
 8936
 8937    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8938    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8939
 8940    fn render_edit_prediction_popover(
 8941        &mut self,
 8942        text_bounds: &Bounds<Pixels>,
 8943        content_origin: gpui::Point<Pixels>,
 8944        right_margin: Pixels,
 8945        editor_snapshot: &EditorSnapshot,
 8946        visible_row_range: Range<DisplayRow>,
 8947        scroll_top: ScrollOffset,
 8948        scroll_bottom: ScrollOffset,
 8949        line_layouts: &[LineWithInvisibles],
 8950        line_height: Pixels,
 8951        scroll_position: gpui::Point<ScrollOffset>,
 8952        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8953        newest_selection_head: Option<DisplayPoint>,
 8954        editor_width: Pixels,
 8955        style: &EditorStyle,
 8956        window: &mut Window,
 8957        cx: &mut App,
 8958    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8959        if self.mode().is_minimap() {
 8960            return None;
 8961        }
 8962        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8963
 8964        if self.edit_prediction_visible_in_cursor_popover(true) {
 8965            return None;
 8966        }
 8967
 8968        match &active_edit_prediction.completion {
 8969            EditPrediction::MoveWithin { target, .. } => {
 8970                let target_display_point = target.to_display_point(editor_snapshot);
 8971
 8972                if self.edit_prediction_requires_modifier() {
 8973                    if !self.edit_prediction_preview_is_active() {
 8974                        return None;
 8975                    }
 8976
 8977                    self.render_edit_prediction_modifier_jump_popover(
 8978                        text_bounds,
 8979                        content_origin,
 8980                        visible_row_range,
 8981                        line_layouts,
 8982                        line_height,
 8983                        scroll_pixel_position,
 8984                        newest_selection_head,
 8985                        target_display_point,
 8986                        window,
 8987                        cx,
 8988                    )
 8989                } else {
 8990                    self.render_edit_prediction_eager_jump_popover(
 8991                        text_bounds,
 8992                        content_origin,
 8993                        editor_snapshot,
 8994                        visible_row_range,
 8995                        scroll_top,
 8996                        scroll_bottom,
 8997                        line_height,
 8998                        scroll_pixel_position,
 8999                        target_display_point,
 9000                        editor_width,
 9001                        window,
 9002                        cx,
 9003                    )
 9004                }
 9005            }
 9006            EditPrediction::Edit {
 9007                display_mode: EditDisplayMode::Inline,
 9008                ..
 9009            } => None,
 9010            EditPrediction::Edit {
 9011                display_mode: EditDisplayMode::TabAccept,
 9012                edits,
 9013                ..
 9014            } => {
 9015                let range = &edits.first()?.0;
 9016                let target_display_point = range.end.to_display_point(editor_snapshot);
 9017
 9018                self.render_edit_prediction_end_of_line_popover(
 9019                    "Accept",
 9020                    editor_snapshot,
 9021                    visible_row_range,
 9022                    target_display_point,
 9023                    line_height,
 9024                    scroll_pixel_position,
 9025                    content_origin,
 9026                    editor_width,
 9027                    window,
 9028                    cx,
 9029                )
 9030            }
 9031            EditPrediction::Edit {
 9032                edits,
 9033                edit_preview,
 9034                display_mode: EditDisplayMode::DiffPopover,
 9035                snapshot,
 9036            } => self.render_edit_prediction_diff_popover(
 9037                text_bounds,
 9038                content_origin,
 9039                right_margin,
 9040                editor_snapshot,
 9041                visible_row_range,
 9042                line_layouts,
 9043                line_height,
 9044                scroll_position,
 9045                scroll_pixel_position,
 9046                newest_selection_head,
 9047                editor_width,
 9048                style,
 9049                edits,
 9050                edit_preview,
 9051                snapshot,
 9052                window,
 9053                cx,
 9054            ),
 9055            EditPrediction::MoveOutside { snapshot, .. } => {
 9056                let mut element = self
 9057                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9058                    .into_any();
 9059
 9060                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9061                let origin_x = text_bounds.size.width - size.width - px(30.);
 9062                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9063                element.prepaint_at(origin, window, cx);
 9064
 9065                Some((element, origin))
 9066            }
 9067        }
 9068    }
 9069
 9070    fn render_edit_prediction_modifier_jump_popover(
 9071        &mut self,
 9072        text_bounds: &Bounds<Pixels>,
 9073        content_origin: gpui::Point<Pixels>,
 9074        visible_row_range: Range<DisplayRow>,
 9075        line_layouts: &[LineWithInvisibles],
 9076        line_height: Pixels,
 9077        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9078        newest_selection_head: Option<DisplayPoint>,
 9079        target_display_point: DisplayPoint,
 9080        window: &mut Window,
 9081        cx: &mut App,
 9082    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9083        let scrolled_content_origin =
 9084            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9085
 9086        const SCROLL_PADDING_Y: Pixels = px(12.);
 9087
 9088        if target_display_point.row() < visible_row_range.start {
 9089            return self.render_edit_prediction_scroll_popover(
 9090                |_| SCROLL_PADDING_Y,
 9091                IconName::ArrowUp,
 9092                visible_row_range,
 9093                line_layouts,
 9094                newest_selection_head,
 9095                scrolled_content_origin,
 9096                window,
 9097                cx,
 9098            );
 9099        } else if target_display_point.row() >= visible_row_range.end {
 9100            return self.render_edit_prediction_scroll_popover(
 9101                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9102                IconName::ArrowDown,
 9103                visible_row_range,
 9104                line_layouts,
 9105                newest_selection_head,
 9106                scrolled_content_origin,
 9107                window,
 9108                cx,
 9109            );
 9110        }
 9111
 9112        const POLE_WIDTH: Pixels = px(2.);
 9113
 9114        let line_layout =
 9115            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9116        let target_column = target_display_point.column() as usize;
 9117
 9118        let target_x = line_layout.x_for_index(target_column);
 9119        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9120            - scroll_pixel_position.y;
 9121
 9122        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9123
 9124        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9125        border_color.l += 0.001;
 9126
 9127        let mut element = v_flex()
 9128            .items_end()
 9129            .when(flag_on_right, |el| el.items_start())
 9130            .child(if flag_on_right {
 9131                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9132                    .rounded_bl(px(0.))
 9133                    .rounded_tl(px(0.))
 9134                    .border_l_2()
 9135                    .border_color(border_color)
 9136            } else {
 9137                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9138                    .rounded_br(px(0.))
 9139                    .rounded_tr(px(0.))
 9140                    .border_r_2()
 9141                    .border_color(border_color)
 9142            })
 9143            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9144            .into_any();
 9145
 9146        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9147
 9148        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9149            - point(
 9150                if flag_on_right {
 9151                    POLE_WIDTH
 9152                } else {
 9153                    size.width - POLE_WIDTH
 9154                },
 9155                size.height - line_height,
 9156            );
 9157
 9158        origin.x = origin.x.max(content_origin.x);
 9159
 9160        element.prepaint_at(origin, window, cx);
 9161
 9162        Some((element, origin))
 9163    }
 9164
 9165    fn render_edit_prediction_scroll_popover(
 9166        &mut self,
 9167        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9168        scroll_icon: IconName,
 9169        visible_row_range: Range<DisplayRow>,
 9170        line_layouts: &[LineWithInvisibles],
 9171        newest_selection_head: Option<DisplayPoint>,
 9172        scrolled_content_origin: gpui::Point<Pixels>,
 9173        window: &mut Window,
 9174        cx: &mut App,
 9175    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9176        let mut element = self
 9177            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9178            .into_any();
 9179
 9180        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9181
 9182        let cursor = newest_selection_head?;
 9183        let cursor_row_layout =
 9184            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9185        let cursor_column = cursor.column() as usize;
 9186
 9187        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9188
 9189        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9190
 9191        element.prepaint_at(origin, window, cx);
 9192        Some((element, origin))
 9193    }
 9194
 9195    fn render_edit_prediction_eager_jump_popover(
 9196        &mut self,
 9197        text_bounds: &Bounds<Pixels>,
 9198        content_origin: gpui::Point<Pixels>,
 9199        editor_snapshot: &EditorSnapshot,
 9200        visible_row_range: Range<DisplayRow>,
 9201        scroll_top: ScrollOffset,
 9202        scroll_bottom: ScrollOffset,
 9203        line_height: Pixels,
 9204        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9205        target_display_point: DisplayPoint,
 9206        editor_width: Pixels,
 9207        window: &mut Window,
 9208        cx: &mut App,
 9209    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9210        if target_display_point.row().as_f64() < scroll_top {
 9211            let mut element = self
 9212                .render_edit_prediction_line_popover(
 9213                    "Jump to Edit",
 9214                    Some(IconName::ArrowUp),
 9215                    window,
 9216                    cx,
 9217                )
 9218                .into_any();
 9219
 9220            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9221            let offset = point(
 9222                (text_bounds.size.width - size.width) / 2.,
 9223                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9224            );
 9225
 9226            let origin = text_bounds.origin + offset;
 9227            element.prepaint_at(origin, window, cx);
 9228            Some((element, origin))
 9229        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9230            let mut element = self
 9231                .render_edit_prediction_line_popover(
 9232                    "Jump to Edit",
 9233                    Some(IconName::ArrowDown),
 9234                    window,
 9235                    cx,
 9236                )
 9237                .into_any();
 9238
 9239            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9240            let offset = point(
 9241                (text_bounds.size.width - size.width) / 2.,
 9242                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9243            );
 9244
 9245            let origin = text_bounds.origin + offset;
 9246            element.prepaint_at(origin, window, cx);
 9247            Some((element, origin))
 9248        } else {
 9249            self.render_edit_prediction_end_of_line_popover(
 9250                "Jump to Edit",
 9251                editor_snapshot,
 9252                visible_row_range,
 9253                target_display_point,
 9254                line_height,
 9255                scroll_pixel_position,
 9256                content_origin,
 9257                editor_width,
 9258                window,
 9259                cx,
 9260            )
 9261        }
 9262    }
 9263
 9264    fn render_edit_prediction_end_of_line_popover(
 9265        self: &mut Editor,
 9266        label: &'static str,
 9267        editor_snapshot: &EditorSnapshot,
 9268        visible_row_range: Range<DisplayRow>,
 9269        target_display_point: DisplayPoint,
 9270        line_height: Pixels,
 9271        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9272        content_origin: gpui::Point<Pixels>,
 9273        editor_width: Pixels,
 9274        window: &mut Window,
 9275        cx: &mut App,
 9276    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9277        let target_line_end = DisplayPoint::new(
 9278            target_display_point.row(),
 9279            editor_snapshot.line_len(target_display_point.row()),
 9280        );
 9281
 9282        let mut element = self
 9283            .render_edit_prediction_line_popover(label, None, window, cx)
 9284            .into_any();
 9285
 9286        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9287
 9288        let line_origin =
 9289            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9290
 9291        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9292        let mut origin = start_point
 9293            + line_origin
 9294            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9295        origin.x = origin.x.max(content_origin.x);
 9296
 9297        let max_x = content_origin.x + editor_width - size.width;
 9298
 9299        if origin.x > max_x {
 9300            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9301
 9302            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9303                origin.y += offset;
 9304                IconName::ArrowUp
 9305            } else {
 9306                origin.y -= offset;
 9307                IconName::ArrowDown
 9308            };
 9309
 9310            element = self
 9311                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9312                .into_any();
 9313
 9314            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9315
 9316            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9317        }
 9318
 9319        element.prepaint_at(origin, window, cx);
 9320        Some((element, origin))
 9321    }
 9322
 9323    fn render_edit_prediction_diff_popover(
 9324        self: &Editor,
 9325        text_bounds: &Bounds<Pixels>,
 9326        content_origin: gpui::Point<Pixels>,
 9327        right_margin: Pixels,
 9328        editor_snapshot: &EditorSnapshot,
 9329        visible_row_range: Range<DisplayRow>,
 9330        line_layouts: &[LineWithInvisibles],
 9331        line_height: Pixels,
 9332        scroll_position: gpui::Point<ScrollOffset>,
 9333        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9334        newest_selection_head: Option<DisplayPoint>,
 9335        editor_width: Pixels,
 9336        style: &EditorStyle,
 9337        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9338        edit_preview: &Option<language::EditPreview>,
 9339        snapshot: &language::BufferSnapshot,
 9340        window: &mut Window,
 9341        cx: &mut App,
 9342    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9343        let edit_start = edits
 9344            .first()
 9345            .unwrap()
 9346            .0
 9347            .start
 9348            .to_display_point(editor_snapshot);
 9349        let edit_end = edits
 9350            .last()
 9351            .unwrap()
 9352            .0
 9353            .end
 9354            .to_display_point(editor_snapshot);
 9355
 9356        let is_visible = visible_row_range.contains(&edit_start.row())
 9357            || visible_row_range.contains(&edit_end.row());
 9358        if !is_visible {
 9359            return None;
 9360        }
 9361
 9362        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9363            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9364        } else {
 9365            // Fallback for providers without edit_preview
 9366            crate::edit_prediction_fallback_text(edits, cx)
 9367        };
 9368
 9369        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9370        let line_count = highlighted_edits.text.lines().count();
 9371
 9372        const BORDER_WIDTH: Pixels = px(1.);
 9373
 9374        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9375        let has_keybind = keybind.is_some();
 9376
 9377        let mut element = h_flex()
 9378            .items_start()
 9379            .child(
 9380                h_flex()
 9381                    .bg(cx.theme().colors().editor_background)
 9382                    .border(BORDER_WIDTH)
 9383                    .shadow_xs()
 9384                    .border_color(cx.theme().colors().border)
 9385                    .rounded_l_lg()
 9386                    .when(line_count > 1, |el| el.rounded_br_lg())
 9387                    .pr_1()
 9388                    .child(styled_text),
 9389            )
 9390            .child(
 9391                h_flex()
 9392                    .h(line_height + BORDER_WIDTH * 2.)
 9393                    .px_1p5()
 9394                    .gap_1()
 9395                    // Workaround: For some reason, there's a gap if we don't do this
 9396                    .ml(-BORDER_WIDTH)
 9397                    .shadow(vec![gpui::BoxShadow {
 9398                        color: gpui::black().opacity(0.05),
 9399                        offset: point(px(1.), px(1.)),
 9400                        blur_radius: px(2.),
 9401                        spread_radius: px(0.),
 9402                    }])
 9403                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9404                    .border(BORDER_WIDTH)
 9405                    .border_color(cx.theme().colors().border)
 9406                    .rounded_r_lg()
 9407                    .id("edit_prediction_diff_popover_keybind")
 9408                    .when(!has_keybind, |el| {
 9409                        let status_colors = cx.theme().status();
 9410
 9411                        el.bg(status_colors.error_background)
 9412                            .border_color(status_colors.error.opacity(0.6))
 9413                            .child(Icon::new(IconName::Info).color(Color::Error))
 9414                            .cursor_default()
 9415                            .hoverable_tooltip(move |_window, cx| {
 9416                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9417                            })
 9418                    })
 9419                    .children(keybind),
 9420            )
 9421            .into_any();
 9422
 9423        let longest_row =
 9424            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9425        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9426            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9427        } else {
 9428            layout_line(
 9429                longest_row,
 9430                editor_snapshot,
 9431                style,
 9432                editor_width,
 9433                |_| false,
 9434                window,
 9435                cx,
 9436            )
 9437            .width
 9438        };
 9439
 9440        let viewport_bounds =
 9441            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9442                right: -right_margin,
 9443                ..Default::default()
 9444            });
 9445
 9446        let x_after_longest = Pixels::from(
 9447            ScrollPixelOffset::from(
 9448                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9449            ) - scroll_pixel_position.x,
 9450        );
 9451
 9452        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9453
 9454        // Fully visible if it can be displayed within the window (allow overlapping other
 9455        // panes). However, this is only allowed if the popover starts within text_bounds.
 9456        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9457            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9458
 9459        let mut origin = if can_position_to_the_right {
 9460            point(
 9461                x_after_longest,
 9462                text_bounds.origin.y
 9463                    + Pixels::from(
 9464                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9465                            - scroll_pixel_position.y,
 9466                    ),
 9467            )
 9468        } else {
 9469            let cursor_row = newest_selection_head.map(|head| head.row());
 9470            let above_edit = edit_start
 9471                .row()
 9472                .0
 9473                .checked_sub(line_count as u32)
 9474                .map(DisplayRow);
 9475            let below_edit = Some(edit_end.row() + 1);
 9476            let above_cursor =
 9477                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9478            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9479
 9480            // Place the edit popover adjacent to the edit if there is a location
 9481            // available that is onscreen and does not obscure the cursor. Otherwise,
 9482            // place it adjacent to the cursor.
 9483            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9484                .into_iter()
 9485                .flatten()
 9486                .find(|&start_row| {
 9487                    let end_row = start_row + line_count as u32;
 9488                    visible_row_range.contains(&start_row)
 9489                        && visible_row_range.contains(&end_row)
 9490                        && cursor_row
 9491                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9492                })?;
 9493
 9494            content_origin
 9495                + point(
 9496                    Pixels::from(-scroll_pixel_position.x),
 9497                    Pixels::from(
 9498                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9499                    ),
 9500                )
 9501        };
 9502
 9503        origin.x -= BORDER_WIDTH;
 9504
 9505        window.defer_draw(element, origin, 1);
 9506
 9507        // Do not return an element, since it will already be drawn due to defer_draw.
 9508        None
 9509    }
 9510
 9511    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9512        px(30.)
 9513    }
 9514
 9515    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9516        if self.read_only(cx) {
 9517            cx.theme().players().read_only()
 9518        } else {
 9519            self.style.as_ref().unwrap().local_player
 9520        }
 9521    }
 9522
 9523    fn render_edit_prediction_accept_keybind(
 9524        &self,
 9525        window: &mut Window,
 9526        cx: &mut App,
 9527    ) -> Option<AnyElement> {
 9528        let accept_binding =
 9529            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9530        let accept_keystroke = accept_binding.keystroke()?;
 9531
 9532        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9533
 9534        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9535            Color::Accent
 9536        } else {
 9537            Color::Muted
 9538        };
 9539
 9540        h_flex()
 9541            .px_0p5()
 9542            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9543            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9544            .text_size(TextSize::XSmall.rems(cx))
 9545            .child(h_flex().children(ui::render_modifiers(
 9546                accept_keystroke.modifiers(),
 9547                PlatformStyle::platform(),
 9548                Some(modifiers_color),
 9549                Some(IconSize::XSmall.rems().into()),
 9550                true,
 9551            )))
 9552            .when(is_platform_style_mac, |parent| {
 9553                parent.child(accept_keystroke.key().to_string())
 9554            })
 9555            .when(!is_platform_style_mac, |parent| {
 9556                parent.child(
 9557                    Key::new(
 9558                        util::capitalize(accept_keystroke.key()),
 9559                        Some(Color::Default),
 9560                    )
 9561                    .size(Some(IconSize::XSmall.rems().into())),
 9562                )
 9563            })
 9564            .into_any()
 9565            .into()
 9566    }
 9567
 9568    fn render_edit_prediction_line_popover(
 9569        &self,
 9570        label: impl Into<SharedString>,
 9571        icon: Option<IconName>,
 9572        window: &mut Window,
 9573        cx: &mut App,
 9574    ) -> Stateful<Div> {
 9575        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9576
 9577        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9578        let has_keybind = keybind.is_some();
 9579
 9580        h_flex()
 9581            .id("ep-line-popover")
 9582            .py_0p5()
 9583            .pl_1()
 9584            .pr(padding_right)
 9585            .gap_1()
 9586            .rounded_md()
 9587            .border_1()
 9588            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9589            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9590            .shadow_xs()
 9591            .when(!has_keybind, |el| {
 9592                let status_colors = cx.theme().status();
 9593
 9594                el.bg(status_colors.error_background)
 9595                    .border_color(status_colors.error.opacity(0.6))
 9596                    .pl_2()
 9597                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9598                    .cursor_default()
 9599                    .hoverable_tooltip(move |_window, cx| {
 9600                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9601                    })
 9602            })
 9603            .children(keybind)
 9604            .child(
 9605                Label::new(label)
 9606                    .size(LabelSize::Small)
 9607                    .when(!has_keybind, |el| {
 9608                        el.color(cx.theme().status().error.into()).strikethrough()
 9609                    }),
 9610            )
 9611            .when(!has_keybind, |el| {
 9612                el.child(
 9613                    h_flex().ml_1().child(
 9614                        Icon::new(IconName::Info)
 9615                            .size(IconSize::Small)
 9616                            .color(cx.theme().status().error.into()),
 9617                    ),
 9618                )
 9619            })
 9620            .when_some(icon, |element, icon| {
 9621                element.child(
 9622                    div()
 9623                        .mt(px(1.5))
 9624                        .child(Icon::new(icon).size(IconSize::Small)),
 9625                )
 9626            })
 9627    }
 9628
 9629    fn render_edit_prediction_jump_outside_popover(
 9630        &self,
 9631        snapshot: &BufferSnapshot,
 9632        window: &mut Window,
 9633        cx: &mut App,
 9634    ) -> Stateful<Div> {
 9635        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9636        let has_keybind = keybind.is_some();
 9637
 9638        let file_name = snapshot
 9639            .file()
 9640            .map(|file| SharedString::new(file.file_name(cx)))
 9641            .unwrap_or(SharedString::new_static("untitled"));
 9642
 9643        h_flex()
 9644            .id("ep-jump-outside-popover")
 9645            .py_1()
 9646            .px_2()
 9647            .gap_1()
 9648            .rounded_md()
 9649            .border_1()
 9650            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9651            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9652            .shadow_xs()
 9653            .when(!has_keybind, |el| {
 9654                let status_colors = cx.theme().status();
 9655
 9656                el.bg(status_colors.error_background)
 9657                    .border_color(status_colors.error.opacity(0.6))
 9658                    .pl_2()
 9659                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9660                    .cursor_default()
 9661                    .hoverable_tooltip(move |_window, cx| {
 9662                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9663                    })
 9664            })
 9665            .children(keybind)
 9666            .child(
 9667                Label::new(file_name)
 9668                    .size(LabelSize::Small)
 9669                    .buffer_font(cx)
 9670                    .when(!has_keybind, |el| {
 9671                        el.color(cx.theme().status().error.into()).strikethrough()
 9672                    }),
 9673            )
 9674            .when(!has_keybind, |el| {
 9675                el.child(
 9676                    h_flex().ml_1().child(
 9677                        Icon::new(IconName::Info)
 9678                            .size(IconSize::Small)
 9679                            .color(cx.theme().status().error.into()),
 9680                    ),
 9681                )
 9682            })
 9683            .child(
 9684                div()
 9685                    .mt(px(1.5))
 9686                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9687            )
 9688    }
 9689
 9690    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9691        let accent_color = cx.theme().colors().text_accent;
 9692        let editor_bg_color = cx.theme().colors().editor_background;
 9693        editor_bg_color.blend(accent_color.opacity(0.1))
 9694    }
 9695
 9696    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9697        let accent_color = cx.theme().colors().text_accent;
 9698        let editor_bg_color = cx.theme().colors().editor_background;
 9699        editor_bg_color.blend(accent_color.opacity(0.6))
 9700    }
 9701    fn get_prediction_provider_icon_name(
 9702        provider: &Option<RegisteredEditPredictionDelegate>,
 9703    ) -> IconName {
 9704        match provider {
 9705            Some(provider) => match provider.provider.name() {
 9706                "copilot" => IconName::Copilot,
 9707                "supermaven" => IconName::Supermaven,
 9708                _ => IconName::ZedPredict,
 9709            },
 9710            None => IconName::ZedPredict,
 9711        }
 9712    }
 9713
 9714    fn render_edit_prediction_cursor_popover(
 9715        &self,
 9716        min_width: Pixels,
 9717        max_width: Pixels,
 9718        cursor_point: Point,
 9719        style: &EditorStyle,
 9720        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9721        _window: &Window,
 9722        cx: &mut Context<Editor>,
 9723    ) -> Option<AnyElement> {
 9724        let provider = self.edit_prediction_provider.as_ref()?;
 9725        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9726
 9727        let is_refreshing = provider.provider.is_refreshing(cx);
 9728
 9729        fn pending_completion_container(icon: IconName) -> Div {
 9730            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9731        }
 9732
 9733        let completion = match &self.active_edit_prediction {
 9734            Some(prediction) => {
 9735                if !self.has_visible_completions_menu() {
 9736                    const RADIUS: Pixels = px(6.);
 9737                    const BORDER_WIDTH: Pixels = px(1.);
 9738
 9739                    return Some(
 9740                        h_flex()
 9741                            .elevation_2(cx)
 9742                            .border(BORDER_WIDTH)
 9743                            .border_color(cx.theme().colors().border)
 9744                            .when(accept_keystroke.is_none(), |el| {
 9745                                el.border_color(cx.theme().status().error)
 9746                            })
 9747                            .rounded(RADIUS)
 9748                            .rounded_tl(px(0.))
 9749                            .overflow_hidden()
 9750                            .child(div().px_1p5().child(match &prediction.completion {
 9751                                EditPrediction::MoveWithin { target, snapshot } => {
 9752                                    use text::ToPoint as _;
 9753                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9754                                    {
 9755                                        Icon::new(IconName::ZedPredictDown)
 9756                                    } else {
 9757                                        Icon::new(IconName::ZedPredictUp)
 9758                                    }
 9759                                }
 9760                                EditPrediction::MoveOutside { .. } => {
 9761                                    // TODO [zeta2] custom icon for external jump?
 9762                                    Icon::new(provider_icon)
 9763                                }
 9764                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9765                            }))
 9766                            .child(
 9767                                h_flex()
 9768                                    .gap_1()
 9769                                    .py_1()
 9770                                    .px_2()
 9771                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9772                                    .border_l_1()
 9773                                    .border_color(cx.theme().colors().border)
 9774                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9775                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9776                                        el.child(
 9777                                            Label::new("Hold")
 9778                                                .size(LabelSize::Small)
 9779                                                .when(accept_keystroke.is_none(), |el| {
 9780                                                    el.strikethrough()
 9781                                                })
 9782                                                .line_height_style(LineHeightStyle::UiLabel),
 9783                                        )
 9784                                    })
 9785                                    .id("edit_prediction_cursor_popover_keybind")
 9786                                    .when(accept_keystroke.is_none(), |el| {
 9787                                        let status_colors = cx.theme().status();
 9788
 9789                                        el.bg(status_colors.error_background)
 9790                                            .border_color(status_colors.error.opacity(0.6))
 9791                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9792                                            .cursor_default()
 9793                                            .hoverable_tooltip(move |_window, cx| {
 9794                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9795                                                    .into()
 9796                                            })
 9797                                    })
 9798                                    .when_some(
 9799                                        accept_keystroke.as_ref(),
 9800                                        |el, accept_keystroke| {
 9801                                            el.child(h_flex().children(ui::render_modifiers(
 9802                                                accept_keystroke.modifiers(),
 9803                                                PlatformStyle::platform(),
 9804                                                Some(Color::Default),
 9805                                                Some(IconSize::XSmall.rems().into()),
 9806                                                false,
 9807                                            )))
 9808                                        },
 9809                                    ),
 9810                            )
 9811                            .into_any(),
 9812                    );
 9813                }
 9814
 9815                self.render_edit_prediction_cursor_popover_preview(
 9816                    prediction,
 9817                    cursor_point,
 9818                    style,
 9819                    cx,
 9820                )?
 9821            }
 9822
 9823            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9824                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9825                    stale_completion,
 9826                    cursor_point,
 9827                    style,
 9828                    cx,
 9829                )?,
 9830
 9831                None => pending_completion_container(provider_icon)
 9832                    .child(Label::new("...").size(LabelSize::Small)),
 9833            },
 9834
 9835            None => pending_completion_container(provider_icon)
 9836                .child(Label::new("...").size(LabelSize::Small)),
 9837        };
 9838
 9839        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9840            completion
 9841                .with_animation(
 9842                    "loading-completion",
 9843                    Animation::new(Duration::from_secs(2))
 9844                        .repeat()
 9845                        .with_easing(pulsating_between(0.4, 0.8)),
 9846                    |label, delta| label.opacity(delta),
 9847                )
 9848                .into_any_element()
 9849        } else {
 9850            completion.into_any_element()
 9851        };
 9852
 9853        let has_completion = self.active_edit_prediction.is_some();
 9854
 9855        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9856        Some(
 9857            h_flex()
 9858                .min_w(min_width)
 9859                .max_w(max_width)
 9860                .flex_1()
 9861                .elevation_2(cx)
 9862                .border_color(cx.theme().colors().border)
 9863                .child(
 9864                    div()
 9865                        .flex_1()
 9866                        .py_1()
 9867                        .px_2()
 9868                        .overflow_hidden()
 9869                        .child(completion),
 9870                )
 9871                .when_some(accept_keystroke, |el, accept_keystroke| {
 9872                    if !accept_keystroke.modifiers().modified() {
 9873                        return el;
 9874                    }
 9875
 9876                    el.child(
 9877                        h_flex()
 9878                            .h_full()
 9879                            .border_l_1()
 9880                            .rounded_r_lg()
 9881                            .border_color(cx.theme().colors().border)
 9882                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9883                            .gap_1()
 9884                            .py_1()
 9885                            .px_2()
 9886                            .child(
 9887                                h_flex()
 9888                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9889                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9890                                    .child(h_flex().children(ui::render_modifiers(
 9891                                        accept_keystroke.modifiers(),
 9892                                        PlatformStyle::platform(),
 9893                                        Some(if !has_completion {
 9894                                            Color::Muted
 9895                                        } else {
 9896                                            Color::Default
 9897                                        }),
 9898                                        None,
 9899                                        false,
 9900                                    ))),
 9901                            )
 9902                            .child(Label::new("Preview").into_any_element())
 9903                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9904                    )
 9905                })
 9906                .into_any(),
 9907        )
 9908    }
 9909
 9910    fn render_edit_prediction_cursor_popover_preview(
 9911        &self,
 9912        completion: &EditPredictionState,
 9913        cursor_point: Point,
 9914        style: &EditorStyle,
 9915        cx: &mut Context<Editor>,
 9916    ) -> Option<Div> {
 9917        use text::ToPoint as _;
 9918
 9919        fn render_relative_row_jump(
 9920            prefix: impl Into<String>,
 9921            current_row: u32,
 9922            target_row: u32,
 9923        ) -> Div {
 9924            let (row_diff, arrow) = if target_row < current_row {
 9925                (current_row - target_row, IconName::ArrowUp)
 9926            } else {
 9927                (target_row - current_row, IconName::ArrowDown)
 9928            };
 9929
 9930            h_flex()
 9931                .child(
 9932                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9933                        .color(Color::Muted)
 9934                        .size(LabelSize::Small),
 9935                )
 9936                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9937        }
 9938
 9939        let supports_jump = self
 9940            .edit_prediction_provider
 9941            .as_ref()
 9942            .map(|provider| provider.provider.supports_jump_to_edit())
 9943            .unwrap_or(true);
 9944
 9945        match &completion.completion {
 9946            EditPrediction::MoveWithin {
 9947                target, snapshot, ..
 9948            } => {
 9949                if !supports_jump {
 9950                    return None;
 9951                }
 9952
 9953                Some(
 9954                    h_flex()
 9955                        .px_2()
 9956                        .gap_2()
 9957                        .flex_1()
 9958                        .child(
 9959                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9960                                Icon::new(IconName::ZedPredictDown)
 9961                            } else {
 9962                                Icon::new(IconName::ZedPredictUp)
 9963                            },
 9964                        )
 9965                        .child(Label::new("Jump to Edit")),
 9966                )
 9967            }
 9968            EditPrediction::MoveOutside { snapshot, .. } => {
 9969                let file_name = snapshot
 9970                    .file()
 9971                    .map(|file| file.file_name(cx))
 9972                    .unwrap_or("untitled");
 9973                Some(
 9974                    h_flex()
 9975                        .px_2()
 9976                        .gap_2()
 9977                        .flex_1()
 9978                        .child(Icon::new(IconName::ZedPredict))
 9979                        .child(Label::new(format!("Jump to {file_name}"))),
 9980                )
 9981            }
 9982            EditPrediction::Edit {
 9983                edits,
 9984                edit_preview,
 9985                snapshot,
 9986                display_mode: _,
 9987            } => {
 9988                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9989
 9990                let (highlighted_edits, has_more_lines) =
 9991                    if let Some(edit_preview) = edit_preview.as_ref() {
 9992                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9993                            .first_line_preview()
 9994                    } else {
 9995                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9996                    };
 9997
 9998                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9999                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10000
10001                let preview = h_flex()
10002                    .gap_1()
10003                    .min_w_16()
10004                    .child(styled_text)
10005                    .when(has_more_lines, |parent| parent.child(""));
10006
10007                let left = if supports_jump && first_edit_row != cursor_point.row {
10008                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10009                        .into_any_element()
10010                } else {
10011                    let icon_name =
10012                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10013                    Icon::new(icon_name).into_any_element()
10014                };
10015
10016                Some(
10017                    h_flex()
10018                        .h_full()
10019                        .flex_1()
10020                        .gap_2()
10021                        .pr_1()
10022                        .overflow_x_hidden()
10023                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10024                        .child(left)
10025                        .child(preview),
10026                )
10027            }
10028        }
10029    }
10030
10031    pub fn render_context_menu(
10032        &mut self,
10033        max_height_in_lines: u32,
10034        window: &mut Window,
10035        cx: &mut Context<Editor>,
10036    ) -> Option<AnyElement> {
10037        let menu = self.context_menu.borrow();
10038        let menu = menu.as_ref()?;
10039        if !menu.visible() {
10040            return None;
10041        };
10042        self.style
10043            .as_ref()
10044            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10045    }
10046
10047    fn render_context_menu_aside(
10048        &mut self,
10049        max_size: Size<Pixels>,
10050        window: &mut Window,
10051        cx: &mut Context<Editor>,
10052    ) -> Option<AnyElement> {
10053        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10054            if menu.visible() {
10055                menu.render_aside(max_size, window, cx)
10056            } else {
10057                None
10058            }
10059        })
10060    }
10061
10062    fn hide_context_menu(
10063        &mut self,
10064        window: &mut Window,
10065        cx: &mut Context<Self>,
10066    ) -> Option<CodeContextMenu> {
10067        cx.notify();
10068        self.completion_tasks.clear();
10069        let context_menu = self.context_menu.borrow_mut().take();
10070        self.stale_edit_prediction_in_menu.take();
10071        self.update_visible_edit_prediction(window, cx);
10072        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10073            && let Some(completion_provider) = &self.completion_provider
10074        {
10075            completion_provider.selection_changed(None, window, cx);
10076        }
10077        context_menu
10078    }
10079
10080    fn show_snippet_choices(
10081        &mut self,
10082        choices: &Vec<String>,
10083        selection: Range<Anchor>,
10084        cx: &mut Context<Self>,
10085    ) {
10086        let Some((_, buffer, _)) = self
10087            .buffer()
10088            .read(cx)
10089            .excerpt_containing(selection.start, cx)
10090        else {
10091            return;
10092        };
10093        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10094        else {
10095            return;
10096        };
10097        if buffer != end_buffer {
10098            log::error!("expected anchor range to have matching buffer IDs");
10099            return;
10100        }
10101
10102        let id = post_inc(&mut self.next_completion_id);
10103        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10104        let mut context_menu = self.context_menu.borrow_mut();
10105        let old_menu = context_menu.take();
10106        *context_menu = Some(CodeContextMenu::Completions(
10107            CompletionsMenu::new_snippet_choices(
10108                id,
10109                true,
10110                choices,
10111                selection,
10112                buffer,
10113                old_menu.map(|menu| menu.primary_scroll_handle()),
10114                snippet_sort_order,
10115            ),
10116        ));
10117    }
10118
10119    pub fn insert_snippet(
10120        &mut self,
10121        insertion_ranges: &[Range<MultiBufferOffset>],
10122        snippet: Snippet,
10123        window: &mut Window,
10124        cx: &mut Context<Self>,
10125    ) -> Result<()> {
10126        struct Tabstop<T> {
10127            is_end_tabstop: bool,
10128            ranges: Vec<Range<T>>,
10129            choices: Option<Vec<String>>,
10130        }
10131
10132        let tabstops = self.buffer.update(cx, |buffer, cx| {
10133            let snippet_text: Arc<str> = snippet.text.clone().into();
10134            let edits = insertion_ranges
10135                .iter()
10136                .cloned()
10137                .map(|range| (range, snippet_text.clone()));
10138            let autoindent_mode = AutoindentMode::Block {
10139                original_indent_columns: Vec::new(),
10140            };
10141            buffer.edit(edits, Some(autoindent_mode), cx);
10142
10143            let snapshot = &*buffer.read(cx);
10144            let snippet = &snippet;
10145            snippet
10146                .tabstops
10147                .iter()
10148                .map(|tabstop| {
10149                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10150                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10151                    });
10152                    let mut tabstop_ranges = tabstop
10153                        .ranges
10154                        .iter()
10155                        .flat_map(|tabstop_range| {
10156                            let mut delta = 0_isize;
10157                            insertion_ranges.iter().map(move |insertion_range| {
10158                                let insertion_start = insertion_range.start + delta;
10159                                delta += snippet.text.len() as isize
10160                                    - (insertion_range.end - insertion_range.start) as isize;
10161
10162                                let start =
10163                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10164                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10165                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10166                            })
10167                        })
10168                        .collect::<Vec<_>>();
10169                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10170
10171                    Tabstop {
10172                        is_end_tabstop,
10173                        ranges: tabstop_ranges,
10174                        choices: tabstop.choices.clone(),
10175                    }
10176                })
10177                .collect::<Vec<_>>()
10178        });
10179        if let Some(tabstop) = tabstops.first() {
10180            self.change_selections(Default::default(), window, cx, |s| {
10181                // Reverse order so that the first range is the newest created selection.
10182                // Completions will use it and autoscroll will prioritize it.
10183                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10184            });
10185
10186            if let Some(choices) = &tabstop.choices
10187                && let Some(selection) = tabstop.ranges.first()
10188            {
10189                self.show_snippet_choices(choices, selection.clone(), cx)
10190            }
10191
10192            // If we're already at the last tabstop and it's at the end of the snippet,
10193            // we're done, we don't need to keep the state around.
10194            if !tabstop.is_end_tabstop {
10195                let choices = tabstops
10196                    .iter()
10197                    .map(|tabstop| tabstop.choices.clone())
10198                    .collect();
10199
10200                let ranges = tabstops
10201                    .into_iter()
10202                    .map(|tabstop| tabstop.ranges)
10203                    .collect::<Vec<_>>();
10204
10205                self.snippet_stack.push(SnippetState {
10206                    active_index: 0,
10207                    ranges,
10208                    choices,
10209                });
10210            }
10211
10212            // Check whether the just-entered snippet ends with an auto-closable bracket.
10213            if self.autoclose_regions.is_empty() {
10214                let snapshot = self.buffer.read(cx).snapshot(cx);
10215                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10216                    let selection_head = selection.head();
10217                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10218                        continue;
10219                    };
10220
10221                    let mut bracket_pair = None;
10222                    let max_lookup_length = scope
10223                        .brackets()
10224                        .map(|(pair, _)| {
10225                            pair.start
10226                                .as_str()
10227                                .chars()
10228                                .count()
10229                                .max(pair.end.as_str().chars().count())
10230                        })
10231                        .max();
10232                    if let Some(max_lookup_length) = max_lookup_length {
10233                        let next_text = snapshot
10234                            .chars_at(selection_head)
10235                            .take(max_lookup_length)
10236                            .collect::<String>();
10237                        let prev_text = snapshot
10238                            .reversed_chars_at(selection_head)
10239                            .take(max_lookup_length)
10240                            .collect::<String>();
10241
10242                        for (pair, enabled) in scope.brackets() {
10243                            if enabled
10244                                && pair.close
10245                                && prev_text.starts_with(pair.start.as_str())
10246                                && next_text.starts_with(pair.end.as_str())
10247                            {
10248                                bracket_pair = Some(pair.clone());
10249                                break;
10250                            }
10251                        }
10252                    }
10253
10254                    if let Some(pair) = bracket_pair {
10255                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10256                        let autoclose_enabled =
10257                            self.use_autoclose && snapshot_settings.use_autoclose;
10258                        if autoclose_enabled {
10259                            let start = snapshot.anchor_after(selection_head);
10260                            let end = snapshot.anchor_after(selection_head);
10261                            self.autoclose_regions.push(AutocloseRegion {
10262                                selection_id: selection.id,
10263                                range: start..end,
10264                                pair,
10265                            });
10266                        }
10267                    }
10268                }
10269            }
10270        }
10271        Ok(())
10272    }
10273
10274    pub fn move_to_next_snippet_tabstop(
10275        &mut self,
10276        window: &mut Window,
10277        cx: &mut Context<Self>,
10278    ) -> bool {
10279        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10280    }
10281
10282    pub fn move_to_prev_snippet_tabstop(
10283        &mut self,
10284        window: &mut Window,
10285        cx: &mut Context<Self>,
10286    ) -> bool {
10287        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10288    }
10289
10290    pub fn move_to_snippet_tabstop(
10291        &mut self,
10292        bias: Bias,
10293        window: &mut Window,
10294        cx: &mut Context<Self>,
10295    ) -> bool {
10296        if let Some(mut snippet) = self.snippet_stack.pop() {
10297            match bias {
10298                Bias::Left => {
10299                    if snippet.active_index > 0 {
10300                        snippet.active_index -= 1;
10301                    } else {
10302                        self.snippet_stack.push(snippet);
10303                        return false;
10304                    }
10305                }
10306                Bias::Right => {
10307                    if snippet.active_index + 1 < snippet.ranges.len() {
10308                        snippet.active_index += 1;
10309                    } else {
10310                        self.snippet_stack.push(snippet);
10311                        return false;
10312                    }
10313                }
10314            }
10315            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10316                self.change_selections(Default::default(), window, cx, |s| {
10317                    // Reverse order so that the first range is the newest created selection.
10318                    // Completions will use it and autoscroll will prioritize it.
10319                    s.select_ranges(current_ranges.iter().rev().cloned())
10320                });
10321
10322                if let Some(choices) = &snippet.choices[snippet.active_index]
10323                    && let Some(selection) = current_ranges.first()
10324                {
10325                    self.show_snippet_choices(choices, selection.clone(), cx);
10326                }
10327
10328                // If snippet state is not at the last tabstop, push it back on the stack
10329                if snippet.active_index + 1 < snippet.ranges.len() {
10330                    self.snippet_stack.push(snippet);
10331                }
10332                return true;
10333            }
10334        }
10335
10336        false
10337    }
10338
10339    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10340        self.transact(window, cx, |this, window, cx| {
10341            this.select_all(&SelectAll, window, cx);
10342            this.insert("", window, cx);
10343        });
10344    }
10345
10346    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10347        if self.read_only(cx) {
10348            return;
10349        }
10350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10351        self.transact(window, cx, |this, window, cx| {
10352            this.select_autoclose_pair(window, cx);
10353
10354            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10355
10356            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10357            if !this.linked_edit_ranges.is_empty() {
10358                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10359                let snapshot = this.buffer.read(cx).snapshot(cx);
10360
10361                for selection in selections.iter() {
10362                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10363                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10364                    if selection_start.buffer_id != selection_end.buffer_id {
10365                        continue;
10366                    }
10367                    if let Some(ranges) =
10368                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10369                    {
10370                        for (buffer, entries) in ranges {
10371                            linked_ranges.entry(buffer).or_default().extend(entries);
10372                        }
10373                    }
10374                }
10375            }
10376
10377            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10378            for selection in &mut selections {
10379                if selection.is_empty() {
10380                    let old_head = selection.head();
10381                    let mut new_head =
10382                        movement::left(&display_map, old_head.to_display_point(&display_map))
10383                            .to_point(&display_map);
10384                    if let Some((buffer, line_buffer_range)) = display_map
10385                        .buffer_snapshot()
10386                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10387                    {
10388                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10389                        let indent_len = match indent_size.kind {
10390                            IndentKind::Space => {
10391                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10392                            }
10393                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10394                        };
10395                        if old_head.column <= indent_size.len && old_head.column > 0 {
10396                            let indent_len = indent_len.get();
10397                            new_head = cmp::min(
10398                                new_head,
10399                                MultiBufferPoint::new(
10400                                    old_head.row,
10401                                    ((old_head.column - 1) / indent_len) * indent_len,
10402                                ),
10403                            );
10404                        }
10405                    }
10406
10407                    selection.set_head(new_head, SelectionGoal::None);
10408                }
10409            }
10410
10411            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10412            this.insert("", window, cx);
10413            let empty_str: Arc<str> = Arc::from("");
10414            for (buffer, edits) in linked_ranges {
10415                let snapshot = buffer.read(cx).snapshot();
10416                use text::ToPoint as TP;
10417
10418                let edits = edits
10419                    .into_iter()
10420                    .map(|range| {
10421                        let end_point = TP::to_point(&range.end, &snapshot);
10422                        let mut start_point = TP::to_point(&range.start, &snapshot);
10423
10424                        if end_point == start_point {
10425                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10426                                .saturating_sub(1);
10427                            start_point =
10428                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10429                        };
10430
10431                        (start_point..end_point, empty_str.clone())
10432                    })
10433                    .sorted_by_key(|(range, _)| range.start)
10434                    .collect::<Vec<_>>();
10435                buffer.update(cx, |this, cx| {
10436                    this.edit(edits, None, cx);
10437                })
10438            }
10439            this.refresh_edit_prediction(true, false, window, cx);
10440            refresh_linked_ranges(this, window, cx);
10441        });
10442    }
10443
10444    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10445        if self.read_only(cx) {
10446            return;
10447        }
10448        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10449        self.transact(window, cx, |this, window, cx| {
10450            this.change_selections(Default::default(), window, cx, |s| {
10451                s.move_with(|map, selection| {
10452                    if selection.is_empty() {
10453                        let cursor = movement::right(map, selection.head());
10454                        selection.end = cursor;
10455                        selection.reversed = true;
10456                        selection.goal = SelectionGoal::None;
10457                    }
10458                })
10459            });
10460            this.insert("", window, cx);
10461            this.refresh_edit_prediction(true, false, window, cx);
10462        });
10463    }
10464
10465    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10466        if self.mode.is_single_line() {
10467            cx.propagate();
10468            return;
10469        }
10470
10471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10472        if self.move_to_prev_snippet_tabstop(window, cx) {
10473            return;
10474        }
10475        self.outdent(&Outdent, window, cx);
10476    }
10477
10478    pub fn next_snippet_tabstop(
10479        &mut self,
10480        _: &NextSnippetTabstop,
10481        window: &mut Window,
10482        cx: &mut Context<Self>,
10483    ) {
10484        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10485            cx.propagate();
10486            return;
10487        }
10488
10489        if self.move_to_next_snippet_tabstop(window, cx) {
10490            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10491            return;
10492        }
10493        cx.propagate();
10494    }
10495
10496    pub fn previous_snippet_tabstop(
10497        &mut self,
10498        _: &PreviousSnippetTabstop,
10499        window: &mut Window,
10500        cx: &mut Context<Self>,
10501    ) {
10502        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10503            cx.propagate();
10504            return;
10505        }
10506
10507        if self.move_to_prev_snippet_tabstop(window, cx) {
10508            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10509            return;
10510        }
10511        cx.propagate();
10512    }
10513
10514    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10515        if self.mode.is_single_line() {
10516            cx.propagate();
10517            return;
10518        }
10519
10520        if self.move_to_next_snippet_tabstop(window, cx) {
10521            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10522            return;
10523        }
10524        if self.read_only(cx) {
10525            return;
10526        }
10527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10528        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10529        let buffer = self.buffer.read(cx);
10530        let snapshot = buffer.snapshot(cx);
10531        let rows_iter = selections.iter().map(|s| s.head().row);
10532        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10533
10534        let has_some_cursor_in_whitespace = selections
10535            .iter()
10536            .filter(|selection| selection.is_empty())
10537            .any(|selection| {
10538                let cursor = selection.head();
10539                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10540                cursor.column < current_indent.len
10541            });
10542
10543        let mut edits = Vec::new();
10544        let mut prev_edited_row = 0;
10545        let mut row_delta = 0;
10546        for selection in &mut selections {
10547            if selection.start.row != prev_edited_row {
10548                row_delta = 0;
10549            }
10550            prev_edited_row = selection.end.row;
10551
10552            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10553            if selection.is_empty() {
10554                let cursor = selection.head();
10555                let settings = buffer.language_settings_at(cursor, cx);
10556                if settings.indent_list_on_tab {
10557                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10558                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10559                            row_delta = Self::indent_selection(
10560                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10561                            );
10562                            continue;
10563                        }
10564                    }
10565                }
10566            }
10567
10568            // If the selection is non-empty, then increase the indentation of the selected lines.
10569            if !selection.is_empty() {
10570                row_delta =
10571                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10572                continue;
10573            }
10574
10575            let cursor = selection.head();
10576            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10577            if let Some(suggested_indent) =
10578                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10579            {
10580                // Don't do anything if already at suggested indent
10581                // and there is any other cursor which is not
10582                if has_some_cursor_in_whitespace
10583                    && cursor.column == current_indent.len
10584                    && current_indent.len == suggested_indent.len
10585                {
10586                    continue;
10587                }
10588
10589                // Adjust line and move cursor to suggested indent
10590                // if cursor is not at suggested indent
10591                if cursor.column < suggested_indent.len
10592                    && cursor.column <= current_indent.len
10593                    && current_indent.len <= suggested_indent.len
10594                {
10595                    selection.start = Point::new(cursor.row, suggested_indent.len);
10596                    selection.end = selection.start;
10597                    if row_delta == 0 {
10598                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10599                            cursor.row,
10600                            current_indent,
10601                            suggested_indent,
10602                        ));
10603                        row_delta = suggested_indent.len - current_indent.len;
10604                    }
10605                    continue;
10606                }
10607
10608                // If current indent is more than suggested indent
10609                // only move cursor to current indent and skip indent
10610                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10611                    selection.start = Point::new(cursor.row, current_indent.len);
10612                    selection.end = selection.start;
10613                    continue;
10614                }
10615            }
10616
10617            // Otherwise, insert a hard or soft tab.
10618            let settings = buffer.language_settings_at(cursor, cx);
10619            let tab_size = if settings.hard_tabs {
10620                IndentSize::tab()
10621            } else {
10622                let tab_size = settings.tab_size.get();
10623                let indent_remainder = snapshot
10624                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10625                    .flat_map(str::chars)
10626                    .fold(row_delta % tab_size, |counter: u32, c| {
10627                        if c == '\t' {
10628                            0
10629                        } else {
10630                            (counter + 1) % tab_size
10631                        }
10632                    });
10633
10634                let chars_to_next_tab_stop = tab_size - indent_remainder;
10635                IndentSize::spaces(chars_to_next_tab_stop)
10636            };
10637            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10638            selection.end = selection.start;
10639            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10640            row_delta += tab_size.len;
10641        }
10642
10643        self.transact(window, cx, |this, window, cx| {
10644            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10645            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10646            this.refresh_edit_prediction(true, false, window, cx);
10647        });
10648    }
10649
10650    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10651        if self.read_only(cx) {
10652            return;
10653        }
10654        if self.mode.is_single_line() {
10655            cx.propagate();
10656            return;
10657        }
10658
10659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10660        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10661        let mut prev_edited_row = 0;
10662        let mut row_delta = 0;
10663        let mut edits = Vec::new();
10664        let buffer = self.buffer.read(cx);
10665        let snapshot = buffer.snapshot(cx);
10666        for selection in &mut selections {
10667            if selection.start.row != prev_edited_row {
10668                row_delta = 0;
10669            }
10670            prev_edited_row = selection.end.row;
10671
10672            row_delta =
10673                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10674        }
10675
10676        self.transact(window, cx, |this, window, cx| {
10677            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10678            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10679        });
10680    }
10681
10682    fn indent_selection(
10683        buffer: &MultiBuffer,
10684        snapshot: &MultiBufferSnapshot,
10685        selection: &mut Selection<Point>,
10686        edits: &mut Vec<(Range<Point>, String)>,
10687        delta_for_start_row: u32,
10688        cx: &App,
10689    ) -> u32 {
10690        let settings = buffer.language_settings_at(selection.start, cx);
10691        let tab_size = settings.tab_size.get();
10692        let indent_kind = if settings.hard_tabs {
10693            IndentKind::Tab
10694        } else {
10695            IndentKind::Space
10696        };
10697        let mut start_row = selection.start.row;
10698        let mut end_row = selection.end.row + 1;
10699
10700        // If a selection ends at the beginning of a line, don't indent
10701        // that last line.
10702        if selection.end.column == 0 && selection.end.row > selection.start.row {
10703            end_row -= 1;
10704        }
10705
10706        // Avoid re-indenting a row that has already been indented by a
10707        // previous selection, but still update this selection's column
10708        // to reflect that indentation.
10709        if delta_for_start_row > 0 {
10710            start_row += 1;
10711            selection.start.column += delta_for_start_row;
10712            if selection.end.row == selection.start.row {
10713                selection.end.column += delta_for_start_row;
10714            }
10715        }
10716
10717        let mut delta_for_end_row = 0;
10718        let has_multiple_rows = start_row + 1 != end_row;
10719        for row in start_row..end_row {
10720            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10721            let indent_delta = match (current_indent.kind, indent_kind) {
10722                (IndentKind::Space, IndentKind::Space) => {
10723                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10724                    IndentSize::spaces(columns_to_next_tab_stop)
10725                }
10726                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10727                (_, IndentKind::Tab) => IndentSize::tab(),
10728            };
10729
10730            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10731                0
10732            } else {
10733                selection.start.column
10734            };
10735            let row_start = Point::new(row, start);
10736            edits.push((
10737                row_start..row_start,
10738                indent_delta.chars().collect::<String>(),
10739            ));
10740
10741            // Update this selection's endpoints to reflect the indentation.
10742            if row == selection.start.row {
10743                selection.start.column += indent_delta.len;
10744            }
10745            if row == selection.end.row {
10746                selection.end.column += indent_delta.len;
10747                delta_for_end_row = indent_delta.len;
10748            }
10749        }
10750
10751        if selection.start.row == selection.end.row {
10752            delta_for_start_row + delta_for_end_row
10753        } else {
10754            delta_for_end_row
10755        }
10756    }
10757
10758    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10759        if self.read_only(cx) {
10760            return;
10761        }
10762        if self.mode.is_single_line() {
10763            cx.propagate();
10764            return;
10765        }
10766
10767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10768        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10769        let selections = self.selections.all::<Point>(&display_map);
10770        let mut deletion_ranges = Vec::new();
10771        let mut last_outdent = None;
10772        {
10773            let buffer = self.buffer.read(cx);
10774            let snapshot = buffer.snapshot(cx);
10775            for selection in &selections {
10776                let settings = buffer.language_settings_at(selection.start, cx);
10777                let tab_size = settings.tab_size.get();
10778                let mut rows = selection.spanned_rows(false, &display_map);
10779
10780                // Avoid re-outdenting a row that has already been outdented by a
10781                // previous selection.
10782                if let Some(last_row) = last_outdent
10783                    && last_row == rows.start
10784                {
10785                    rows.start = rows.start.next_row();
10786                }
10787                let has_multiple_rows = rows.len() > 1;
10788                for row in rows.iter_rows() {
10789                    let indent_size = snapshot.indent_size_for_line(row);
10790                    if indent_size.len > 0 {
10791                        let deletion_len = match indent_size.kind {
10792                            IndentKind::Space => {
10793                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10794                                if columns_to_prev_tab_stop == 0 {
10795                                    tab_size
10796                                } else {
10797                                    columns_to_prev_tab_stop
10798                                }
10799                            }
10800                            IndentKind::Tab => 1,
10801                        };
10802                        let start = if has_multiple_rows
10803                            || deletion_len > selection.start.column
10804                            || indent_size.len < selection.start.column
10805                        {
10806                            0
10807                        } else {
10808                            selection.start.column - deletion_len
10809                        };
10810                        deletion_ranges.push(
10811                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10812                        );
10813                        last_outdent = Some(row);
10814                    }
10815                }
10816            }
10817        }
10818
10819        self.transact(window, cx, |this, window, cx| {
10820            this.buffer.update(cx, |buffer, cx| {
10821                let empty_str: Arc<str> = Arc::default();
10822                buffer.edit(
10823                    deletion_ranges
10824                        .into_iter()
10825                        .map(|range| (range, empty_str.clone())),
10826                    None,
10827                    cx,
10828                );
10829            });
10830            let selections = this
10831                .selections
10832                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10833            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10834        });
10835    }
10836
10837    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10838        if self.read_only(cx) {
10839            return;
10840        }
10841        if self.mode.is_single_line() {
10842            cx.propagate();
10843            return;
10844        }
10845
10846        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10847        let selections = self
10848            .selections
10849            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10850            .into_iter()
10851            .map(|s| s.range());
10852
10853        self.transact(window, cx, |this, window, cx| {
10854            this.buffer.update(cx, |buffer, cx| {
10855                buffer.autoindent_ranges(selections, cx);
10856            });
10857            let selections = this
10858                .selections
10859                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10860            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10861        });
10862    }
10863
10864    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10866        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10867        let selections = self.selections.all::<Point>(&display_map);
10868
10869        let mut new_cursors = Vec::new();
10870        let mut edit_ranges = Vec::new();
10871        let mut selections = selections.iter().peekable();
10872        while let Some(selection) = selections.next() {
10873            let mut rows = selection.spanned_rows(false, &display_map);
10874
10875            // Accumulate contiguous regions of rows that we want to delete.
10876            while let Some(next_selection) = selections.peek() {
10877                let next_rows = next_selection.spanned_rows(false, &display_map);
10878                if next_rows.start <= rows.end {
10879                    rows.end = next_rows.end;
10880                    selections.next().unwrap();
10881                } else {
10882                    break;
10883                }
10884            }
10885
10886            let buffer = display_map.buffer_snapshot();
10887            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10888            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10889                // If there's a line after the range, delete the \n from the end of the row range
10890                (
10891                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10892                    rows.end,
10893                )
10894            } else {
10895                // If there isn't a line after the range, delete the \n from the line before the
10896                // start of the row range
10897                edit_start = edit_start.saturating_sub_usize(1);
10898                (buffer.len(), rows.start.previous_row())
10899            };
10900
10901            let text_layout_details = self.text_layout_details(window);
10902            let x = display_map.x_for_display_point(
10903                selection.head().to_display_point(&display_map),
10904                &text_layout_details,
10905            );
10906            let row = Point::new(target_row.0, 0)
10907                .to_display_point(&display_map)
10908                .row();
10909            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10910
10911            new_cursors.push((
10912                selection.id,
10913                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10914                SelectionGoal::None,
10915            ));
10916            edit_ranges.push(edit_start..edit_end);
10917        }
10918
10919        self.transact(window, cx, |this, window, cx| {
10920            let buffer = this.buffer.update(cx, |buffer, cx| {
10921                let empty_str: Arc<str> = Arc::default();
10922                buffer.edit(
10923                    edit_ranges
10924                        .into_iter()
10925                        .map(|range| (range, empty_str.clone())),
10926                    None,
10927                    cx,
10928                );
10929                buffer.snapshot(cx)
10930            });
10931            let new_selections = new_cursors
10932                .into_iter()
10933                .map(|(id, cursor, goal)| {
10934                    let cursor = cursor.to_point(&buffer);
10935                    Selection {
10936                        id,
10937                        start: cursor,
10938                        end: cursor,
10939                        reversed: false,
10940                        goal,
10941                    }
10942                })
10943                .collect();
10944
10945            this.change_selections(Default::default(), window, cx, |s| {
10946                s.select(new_selections);
10947            });
10948        });
10949    }
10950
10951    pub fn join_lines_impl(
10952        &mut self,
10953        insert_whitespace: bool,
10954        window: &mut Window,
10955        cx: &mut Context<Self>,
10956    ) {
10957        if self.read_only(cx) {
10958            return;
10959        }
10960        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10961        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10962            let start = MultiBufferRow(selection.start.row);
10963            // Treat single line selections as if they include the next line. Otherwise this action
10964            // would do nothing for single line selections individual cursors.
10965            let end = if selection.start.row == selection.end.row {
10966                MultiBufferRow(selection.start.row + 1)
10967            } else {
10968                MultiBufferRow(selection.end.row)
10969            };
10970
10971            if let Some(last_row_range) = row_ranges.last_mut()
10972                && start <= last_row_range.end
10973            {
10974                last_row_range.end = end;
10975                continue;
10976            }
10977            row_ranges.push(start..end);
10978        }
10979
10980        let snapshot = self.buffer.read(cx).snapshot(cx);
10981        let mut cursor_positions = Vec::new();
10982        for row_range in &row_ranges {
10983            let anchor = snapshot.anchor_before(Point::new(
10984                row_range.end.previous_row().0,
10985                snapshot.line_len(row_range.end.previous_row()),
10986            ));
10987            cursor_positions.push(anchor..anchor);
10988        }
10989
10990        self.transact(window, cx, |this, window, cx| {
10991            for row_range in row_ranges.into_iter().rev() {
10992                for row in row_range.iter_rows().rev() {
10993                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10994                    let next_line_row = row.next_row();
10995                    let indent = snapshot.indent_size_for_line(next_line_row);
10996                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10997
10998                    let replace =
10999                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11000                            " "
11001                        } else {
11002                            ""
11003                        };
11004
11005                    this.buffer.update(cx, |buffer, cx| {
11006                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11007                    });
11008                }
11009            }
11010
11011            this.change_selections(Default::default(), window, cx, |s| {
11012                s.select_anchor_ranges(cursor_positions)
11013            });
11014        });
11015    }
11016
11017    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11019        self.join_lines_impl(true, window, cx);
11020    }
11021
11022    pub fn sort_lines_case_sensitive(
11023        &mut self,
11024        _: &SortLinesCaseSensitive,
11025        window: &mut Window,
11026        cx: &mut Context<Self>,
11027    ) {
11028        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11029    }
11030
11031    pub fn sort_lines_by_length(
11032        &mut self,
11033        _: &SortLinesByLength,
11034        window: &mut Window,
11035        cx: &mut Context<Self>,
11036    ) {
11037        self.manipulate_immutable_lines(window, cx, |lines| {
11038            lines.sort_by_key(|&line| line.chars().count())
11039        })
11040    }
11041
11042    pub fn sort_lines_case_insensitive(
11043        &mut self,
11044        _: &SortLinesCaseInsensitive,
11045        window: &mut Window,
11046        cx: &mut Context<Self>,
11047    ) {
11048        self.manipulate_immutable_lines(window, cx, |lines| {
11049            lines.sort_by_key(|line| line.to_lowercase())
11050        })
11051    }
11052
11053    pub fn unique_lines_case_insensitive(
11054        &mut self,
11055        _: &UniqueLinesCaseInsensitive,
11056        window: &mut Window,
11057        cx: &mut Context<Self>,
11058    ) {
11059        self.manipulate_immutable_lines(window, cx, |lines| {
11060            let mut seen = HashSet::default();
11061            lines.retain(|line| seen.insert(line.to_lowercase()));
11062        })
11063    }
11064
11065    pub fn unique_lines_case_sensitive(
11066        &mut self,
11067        _: &UniqueLinesCaseSensitive,
11068        window: &mut Window,
11069        cx: &mut Context<Self>,
11070    ) {
11071        self.manipulate_immutable_lines(window, cx, |lines| {
11072            let mut seen = HashSet::default();
11073            lines.retain(|line| seen.insert(*line));
11074        })
11075    }
11076
11077    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11078        let snapshot = self.buffer.read(cx).snapshot(cx);
11079        for selection in self.selections.disjoint_anchors_arc().iter() {
11080            if snapshot
11081                .language_at(selection.start)
11082                .and_then(|lang| lang.config().wrap_characters.as_ref())
11083                .is_some()
11084            {
11085                return true;
11086            }
11087        }
11088        false
11089    }
11090
11091    fn wrap_selections_in_tag(
11092        &mut self,
11093        _: &WrapSelectionsInTag,
11094        window: &mut Window,
11095        cx: &mut Context<Self>,
11096    ) {
11097        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11098
11099        let snapshot = self.buffer.read(cx).snapshot(cx);
11100
11101        let mut edits = Vec::new();
11102        let mut boundaries = Vec::new();
11103
11104        for selection in self
11105            .selections
11106            .all_adjusted(&self.display_snapshot(cx))
11107            .iter()
11108        {
11109            let Some(wrap_config) = snapshot
11110                .language_at(selection.start)
11111                .and_then(|lang| lang.config().wrap_characters.clone())
11112            else {
11113                continue;
11114            };
11115
11116            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11117            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11118
11119            let start_before = snapshot.anchor_before(selection.start);
11120            let end_after = snapshot.anchor_after(selection.end);
11121
11122            edits.push((start_before..start_before, open_tag));
11123            edits.push((end_after..end_after, close_tag));
11124
11125            boundaries.push((
11126                start_before,
11127                end_after,
11128                wrap_config.start_prefix.len(),
11129                wrap_config.end_suffix.len(),
11130            ));
11131        }
11132
11133        if edits.is_empty() {
11134            return;
11135        }
11136
11137        self.transact(window, cx, |this, window, cx| {
11138            let buffer = this.buffer.update(cx, |buffer, cx| {
11139                buffer.edit(edits, None, cx);
11140                buffer.snapshot(cx)
11141            });
11142
11143            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11144            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11145                boundaries.into_iter()
11146            {
11147                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11148                let close_offset = end_after
11149                    .to_offset(&buffer)
11150                    .saturating_sub_usize(end_suffix_len);
11151                new_selections.push(open_offset..open_offset);
11152                new_selections.push(close_offset..close_offset);
11153            }
11154
11155            this.change_selections(Default::default(), window, cx, |s| {
11156                s.select_ranges(new_selections);
11157            });
11158
11159            this.request_autoscroll(Autoscroll::fit(), cx);
11160        });
11161    }
11162
11163    pub fn toggle_read_only(
11164        &mut self,
11165        _: &workspace::ToggleReadOnlyFile,
11166        _: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) {
11169        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11170            buffer.update(cx, |buffer, cx| {
11171                buffer.set_capability(
11172                    match buffer.capability() {
11173                        Capability::ReadWrite => Capability::Read,
11174                        Capability::Read => Capability::ReadWrite,
11175                        Capability::ReadOnly => Capability::ReadOnly,
11176                    },
11177                    cx,
11178                );
11179            })
11180        }
11181    }
11182
11183    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11184        let Some(project) = self.project.clone() else {
11185            return;
11186        };
11187        self.reload(project, window, cx)
11188            .detach_and_notify_err(window, cx);
11189    }
11190
11191    pub fn restore_file(
11192        &mut self,
11193        _: &::git::RestoreFile,
11194        window: &mut Window,
11195        cx: &mut Context<Self>,
11196    ) {
11197        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11198        let mut buffer_ids = HashSet::default();
11199        let snapshot = self.buffer().read(cx).snapshot(cx);
11200        for selection in self
11201            .selections
11202            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11203        {
11204            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11205        }
11206
11207        let buffer = self.buffer().read(cx);
11208        let ranges = buffer_ids
11209            .into_iter()
11210            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11211            .collect::<Vec<_>>();
11212
11213        self.restore_hunks_in_ranges(ranges, window, cx);
11214    }
11215
11216    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11217        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11218        let selections = self
11219            .selections
11220            .all(&self.display_snapshot(cx))
11221            .into_iter()
11222            .map(|s| s.range())
11223            .collect();
11224        self.restore_hunks_in_ranges(selections, window, cx);
11225    }
11226
11227    pub fn restore_hunks_in_ranges(
11228        &mut self,
11229        ranges: Vec<Range<Point>>,
11230        window: &mut Window,
11231        cx: &mut Context<Editor>,
11232    ) {
11233        let mut revert_changes = HashMap::default();
11234        let chunk_by = self
11235            .snapshot(window, cx)
11236            .hunks_for_ranges(ranges)
11237            .into_iter()
11238            .chunk_by(|hunk| hunk.buffer_id);
11239        for (buffer_id, hunks) in &chunk_by {
11240            let hunks = hunks.collect::<Vec<_>>();
11241            for hunk in &hunks {
11242                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11243            }
11244            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11245        }
11246        drop(chunk_by);
11247        if !revert_changes.is_empty() {
11248            self.transact(window, cx, |editor, window, cx| {
11249                editor.restore(revert_changes, window, cx);
11250            });
11251        }
11252    }
11253
11254    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11255        if let Some(status) = self
11256            .addons
11257            .iter()
11258            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11259        {
11260            return Some(status);
11261        }
11262        self.project
11263            .as_ref()?
11264            .read(cx)
11265            .status_for_buffer_id(buffer_id, cx)
11266    }
11267
11268    pub fn open_active_item_in_terminal(
11269        &mut self,
11270        _: &OpenInTerminal,
11271        window: &mut Window,
11272        cx: &mut Context<Self>,
11273    ) {
11274        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11275            let project_path = buffer.read(cx).project_path(cx)?;
11276            let project = self.project()?.read(cx);
11277            let entry = project.entry_for_path(&project_path, cx)?;
11278            let parent = match &entry.canonical_path {
11279                Some(canonical_path) => canonical_path.to_path_buf(),
11280                None => project.absolute_path(&project_path, cx)?,
11281            }
11282            .parent()?
11283            .to_path_buf();
11284            Some(parent)
11285        }) {
11286            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11287        }
11288    }
11289
11290    fn set_breakpoint_context_menu(
11291        &mut self,
11292        display_row: DisplayRow,
11293        position: Option<Anchor>,
11294        clicked_point: gpui::Point<Pixels>,
11295        window: &mut Window,
11296        cx: &mut Context<Self>,
11297    ) {
11298        let source = self
11299            .buffer
11300            .read(cx)
11301            .snapshot(cx)
11302            .anchor_before(Point::new(display_row.0, 0u32));
11303
11304        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11305
11306        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11307            self,
11308            source,
11309            clicked_point,
11310            context_menu,
11311            window,
11312            cx,
11313        );
11314    }
11315
11316    fn add_edit_breakpoint_block(
11317        &mut self,
11318        anchor: Anchor,
11319        breakpoint: &Breakpoint,
11320        edit_action: BreakpointPromptEditAction,
11321        window: &mut Window,
11322        cx: &mut Context<Self>,
11323    ) {
11324        let weak_editor = cx.weak_entity();
11325        let bp_prompt = cx.new(|cx| {
11326            BreakpointPromptEditor::new(
11327                weak_editor,
11328                anchor,
11329                breakpoint.clone(),
11330                edit_action,
11331                window,
11332                cx,
11333            )
11334        });
11335
11336        let height = bp_prompt.update(cx, |this, cx| {
11337            this.prompt
11338                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11339        });
11340        let cloned_prompt = bp_prompt.clone();
11341        let blocks = vec![BlockProperties {
11342            style: BlockStyle::Sticky,
11343            placement: BlockPlacement::Above(anchor),
11344            height: Some(height),
11345            render: Arc::new(move |cx| {
11346                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11347                cloned_prompt.clone().into_any_element()
11348            }),
11349            priority: 0,
11350        }];
11351
11352        let focus_handle = bp_prompt.focus_handle(cx);
11353        window.focus(&focus_handle, cx);
11354
11355        let block_ids = self.insert_blocks(blocks, None, cx);
11356        bp_prompt.update(cx, |prompt, _| {
11357            prompt.add_block_ids(block_ids);
11358        });
11359    }
11360
11361    pub(crate) fn breakpoint_at_row(
11362        &self,
11363        row: u32,
11364        window: &mut Window,
11365        cx: &mut Context<Self>,
11366    ) -> Option<(Anchor, Breakpoint)> {
11367        let snapshot = self.snapshot(window, cx);
11368        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11369
11370        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11371    }
11372
11373    pub(crate) fn breakpoint_at_anchor(
11374        &self,
11375        breakpoint_position: Anchor,
11376        snapshot: &EditorSnapshot,
11377        cx: &mut Context<Self>,
11378    ) -> Option<(Anchor, Breakpoint)> {
11379        let buffer = self
11380            .buffer
11381            .read(cx)
11382            .buffer_for_anchor(breakpoint_position, cx)?;
11383
11384        let enclosing_excerpt = breakpoint_position.excerpt_id;
11385        let buffer_snapshot = buffer.read(cx).snapshot();
11386
11387        let row = buffer_snapshot
11388            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11389            .row;
11390
11391        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11392        let anchor_end = snapshot
11393            .buffer_snapshot()
11394            .anchor_after(Point::new(row, line_len));
11395
11396        self.breakpoint_store
11397            .as_ref()?
11398            .read_with(cx, |breakpoint_store, cx| {
11399                breakpoint_store
11400                    .breakpoints(
11401                        &buffer,
11402                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11403                        &buffer_snapshot,
11404                        cx,
11405                    )
11406                    .next()
11407                    .and_then(|(bp, _)| {
11408                        let breakpoint_row = buffer_snapshot
11409                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11410                            .row;
11411
11412                        if breakpoint_row == row {
11413                            snapshot
11414                                .buffer_snapshot()
11415                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11416                                .map(|position| (position, bp.bp.clone()))
11417                        } else {
11418                            None
11419                        }
11420                    })
11421            })
11422    }
11423
11424    pub fn edit_log_breakpoint(
11425        &mut self,
11426        _: &EditLogBreakpoint,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) {
11430        if self.breakpoint_store.is_none() {
11431            return;
11432        }
11433
11434        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11435            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11436                message: None,
11437                state: BreakpointState::Enabled,
11438                condition: None,
11439                hit_condition: None,
11440            });
11441
11442            self.add_edit_breakpoint_block(
11443                anchor,
11444                &breakpoint,
11445                BreakpointPromptEditAction::Log,
11446                window,
11447                cx,
11448            );
11449        }
11450    }
11451
11452    fn breakpoints_at_cursors(
11453        &self,
11454        window: &mut Window,
11455        cx: &mut Context<Self>,
11456    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11457        let snapshot = self.snapshot(window, cx);
11458        let cursors = self
11459            .selections
11460            .disjoint_anchors_arc()
11461            .iter()
11462            .map(|selection| {
11463                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11464
11465                let breakpoint_position = self
11466                    .breakpoint_at_row(cursor_position.row, window, cx)
11467                    .map(|bp| bp.0)
11468                    .unwrap_or_else(|| {
11469                        snapshot
11470                            .display_snapshot
11471                            .buffer_snapshot()
11472                            .anchor_after(Point::new(cursor_position.row, 0))
11473                    });
11474
11475                let breakpoint = self
11476                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11477                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11478
11479                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11480            })
11481            // 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.
11482            .collect::<HashMap<Anchor, _>>();
11483
11484        cursors.into_iter().collect()
11485    }
11486
11487    pub fn enable_breakpoint(
11488        &mut self,
11489        _: &crate::actions::EnableBreakpoint,
11490        window: &mut Window,
11491        cx: &mut Context<Self>,
11492    ) {
11493        if self.breakpoint_store.is_none() {
11494            return;
11495        }
11496
11497        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11498            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11499                continue;
11500            };
11501            self.edit_breakpoint_at_anchor(
11502                anchor,
11503                breakpoint,
11504                BreakpointEditAction::InvertState,
11505                cx,
11506            );
11507        }
11508    }
11509
11510    pub fn disable_breakpoint(
11511        &mut self,
11512        _: &crate::actions::DisableBreakpoint,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        if self.breakpoint_store.is_none() {
11517            return;
11518        }
11519
11520        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11521            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11522                continue;
11523            };
11524            self.edit_breakpoint_at_anchor(
11525                anchor,
11526                breakpoint,
11527                BreakpointEditAction::InvertState,
11528                cx,
11529            );
11530        }
11531    }
11532
11533    pub fn toggle_breakpoint(
11534        &mut self,
11535        _: &crate::actions::ToggleBreakpoint,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        if self.breakpoint_store.is_none() {
11540            return;
11541        }
11542
11543        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11544            if let Some(breakpoint) = breakpoint {
11545                self.edit_breakpoint_at_anchor(
11546                    anchor,
11547                    breakpoint,
11548                    BreakpointEditAction::Toggle,
11549                    cx,
11550                );
11551            } else {
11552                self.edit_breakpoint_at_anchor(
11553                    anchor,
11554                    Breakpoint::new_standard(),
11555                    BreakpointEditAction::Toggle,
11556                    cx,
11557                );
11558            }
11559        }
11560    }
11561
11562    pub fn edit_breakpoint_at_anchor(
11563        &mut self,
11564        breakpoint_position: Anchor,
11565        breakpoint: Breakpoint,
11566        edit_action: BreakpointEditAction,
11567        cx: &mut Context<Self>,
11568    ) {
11569        let Some(breakpoint_store) = &self.breakpoint_store else {
11570            return;
11571        };
11572
11573        let Some(buffer) = self
11574            .buffer
11575            .read(cx)
11576            .buffer_for_anchor(breakpoint_position, cx)
11577        else {
11578            return;
11579        };
11580
11581        breakpoint_store.update(cx, |breakpoint_store, cx| {
11582            breakpoint_store.toggle_breakpoint(
11583                buffer,
11584                BreakpointWithPosition {
11585                    position: breakpoint_position.text_anchor,
11586                    bp: breakpoint,
11587                },
11588                edit_action,
11589                cx,
11590            );
11591        });
11592
11593        cx.notify();
11594    }
11595
11596    #[cfg(any(test, feature = "test-support"))]
11597    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11598        self.breakpoint_store.clone()
11599    }
11600
11601    pub fn prepare_restore_change(
11602        &self,
11603        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11604        hunk: &MultiBufferDiffHunk,
11605        cx: &mut App,
11606    ) -> Option<()> {
11607        if hunk.is_created_file() {
11608            return None;
11609        }
11610        let buffer = self.buffer.read(cx);
11611        let diff = buffer.diff_for(hunk.buffer_id)?;
11612        let buffer = buffer.buffer(hunk.buffer_id)?;
11613        let buffer = buffer.read(cx);
11614        let original_text = diff
11615            .read(cx)
11616            .base_text(cx)
11617            .as_rope()
11618            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11619        let buffer_snapshot = buffer.snapshot();
11620        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11621        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11622            probe
11623                .0
11624                .start
11625                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11626                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11627        }) {
11628            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11629            Some(())
11630        } else {
11631            None
11632        }
11633    }
11634
11635    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11636        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11637    }
11638
11639    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11640        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11641    }
11642
11643    pub fn rotate_selections_forward(
11644        &mut self,
11645        _: &RotateSelectionsForward,
11646        window: &mut Window,
11647        cx: &mut Context<Self>,
11648    ) {
11649        self.rotate_selections(window, cx, false)
11650    }
11651
11652    pub fn rotate_selections_backward(
11653        &mut self,
11654        _: &RotateSelectionsBackward,
11655        window: &mut Window,
11656        cx: &mut Context<Self>,
11657    ) {
11658        self.rotate_selections(window, cx, true)
11659    }
11660
11661    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11663        let display_snapshot = self.display_snapshot(cx);
11664        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11665
11666        if selections.len() < 2 {
11667            return;
11668        }
11669
11670        let (edits, new_selections) = {
11671            let buffer = self.buffer.read(cx).read(cx);
11672            let has_selections = selections.iter().any(|s| !s.is_empty());
11673            if has_selections {
11674                let mut selected_texts: Vec<String> = selections
11675                    .iter()
11676                    .map(|selection| {
11677                        buffer
11678                            .text_for_range(selection.start..selection.end)
11679                            .collect()
11680                    })
11681                    .collect();
11682
11683                if reverse {
11684                    selected_texts.rotate_left(1);
11685                } else {
11686                    selected_texts.rotate_right(1);
11687                }
11688
11689                let mut offset_delta: i64 = 0;
11690                let mut new_selections = Vec::new();
11691                let edits: Vec<_> = selections
11692                    .iter()
11693                    .zip(selected_texts.iter())
11694                    .map(|(selection, new_text)| {
11695                        let old_len = (selection.end.0 - selection.start.0) as i64;
11696                        let new_len = new_text.len() as i64;
11697                        let adjusted_start =
11698                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11699                        let adjusted_end =
11700                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11701
11702                        new_selections.push(Selection {
11703                            id: selection.id,
11704                            start: adjusted_start,
11705                            end: adjusted_end,
11706                            reversed: selection.reversed,
11707                            goal: selection.goal,
11708                        });
11709
11710                        offset_delta += new_len - old_len;
11711                        (selection.start..selection.end, new_text.clone())
11712                    })
11713                    .collect();
11714                (edits, new_selections)
11715            } else {
11716                let mut all_rows: Vec<u32> = selections
11717                    .iter()
11718                    .map(|selection| buffer.offset_to_point(selection.start).row)
11719                    .collect();
11720                all_rows.sort_unstable();
11721                all_rows.dedup();
11722
11723                if all_rows.len() < 2 {
11724                    return;
11725                }
11726
11727                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11728                    .iter()
11729                    .map(|&row| {
11730                        let start = Point::new(row, 0);
11731                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11732                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11733                    })
11734                    .collect();
11735
11736                let mut line_texts: Vec<String> = line_ranges
11737                    .iter()
11738                    .map(|range| buffer.text_for_range(range.clone()).collect())
11739                    .collect();
11740
11741                if reverse {
11742                    line_texts.rotate_left(1);
11743                } else {
11744                    line_texts.rotate_right(1);
11745                }
11746
11747                let edits = line_ranges
11748                    .iter()
11749                    .zip(line_texts.iter())
11750                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11751                    .collect();
11752
11753                let num_rows = all_rows.len();
11754                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11755                    .iter()
11756                    .enumerate()
11757                    .map(|(i, &row)| (row, i))
11758                    .collect();
11759
11760                // Compute new line start offsets after rotation (handles CRLF)
11761                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11762                let first_line_start = line_ranges[0].start.0;
11763                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11764                for text in line_texts.iter().take(num_rows - 1) {
11765                    let prev_start = *new_line_starts.last().unwrap();
11766                    new_line_starts.push(prev_start + text.len() + newline_len);
11767                }
11768
11769                let new_selections = selections
11770                    .iter()
11771                    .map(|selection| {
11772                        let point = buffer.offset_to_point(selection.start);
11773                        let old_index = row_to_index[&point.row];
11774                        let new_index = if reverse {
11775                            (old_index + num_rows - 1) % num_rows
11776                        } else {
11777                            (old_index + 1) % num_rows
11778                        };
11779                        let new_offset =
11780                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11781                        Selection {
11782                            id: selection.id,
11783                            start: new_offset,
11784                            end: new_offset,
11785                            reversed: selection.reversed,
11786                            goal: selection.goal,
11787                        }
11788                    })
11789                    .collect();
11790
11791                (edits, new_selections)
11792            }
11793        };
11794
11795        self.transact(window, cx, |this, window, cx| {
11796            this.buffer.update(cx, |buffer, cx| {
11797                buffer.edit(edits, None, cx);
11798            });
11799            this.change_selections(Default::default(), window, cx, |s| {
11800                s.select(new_selections);
11801            });
11802        });
11803    }
11804
11805    fn manipulate_lines<M>(
11806        &mut self,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809        mut manipulate: M,
11810    ) where
11811        M: FnMut(&str) -> LineManipulationResult,
11812    {
11813        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11814
11815        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11816        let buffer = self.buffer.read(cx).snapshot(cx);
11817
11818        let mut edits = Vec::new();
11819
11820        let selections = self.selections.all::<Point>(&display_map);
11821        let mut selections = selections.iter().peekable();
11822        let mut contiguous_row_selections = Vec::new();
11823        let mut new_selections = Vec::new();
11824        let mut added_lines = 0;
11825        let mut removed_lines = 0;
11826
11827        while let Some(selection) = selections.next() {
11828            let (start_row, end_row) = consume_contiguous_rows(
11829                &mut contiguous_row_selections,
11830                selection,
11831                &display_map,
11832                &mut selections,
11833            );
11834
11835            let start_point = Point::new(start_row.0, 0);
11836            let end_point = Point::new(
11837                end_row.previous_row().0,
11838                buffer.line_len(end_row.previous_row()),
11839            );
11840            let text = buffer
11841                .text_for_range(start_point..end_point)
11842                .collect::<String>();
11843
11844            let LineManipulationResult {
11845                new_text,
11846                line_count_before,
11847                line_count_after,
11848            } = manipulate(&text);
11849
11850            edits.push((start_point..end_point, new_text));
11851
11852            // Selections must change based on added and removed line count
11853            let start_row =
11854                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11855            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11856            new_selections.push(Selection {
11857                id: selection.id,
11858                start: start_row,
11859                end: end_row,
11860                goal: SelectionGoal::None,
11861                reversed: selection.reversed,
11862            });
11863
11864            if line_count_after > line_count_before {
11865                added_lines += line_count_after - line_count_before;
11866            } else if line_count_before > line_count_after {
11867                removed_lines += line_count_before - line_count_after;
11868            }
11869        }
11870
11871        self.transact(window, cx, |this, window, cx| {
11872            let buffer = this.buffer.update(cx, |buffer, cx| {
11873                buffer.edit(edits, None, cx);
11874                buffer.snapshot(cx)
11875            });
11876
11877            // Recalculate offsets on newly edited buffer
11878            let new_selections = new_selections
11879                .iter()
11880                .map(|s| {
11881                    let start_point = Point::new(s.start.0, 0);
11882                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11883                    Selection {
11884                        id: s.id,
11885                        start: buffer.point_to_offset(start_point),
11886                        end: buffer.point_to_offset(end_point),
11887                        goal: s.goal,
11888                        reversed: s.reversed,
11889                    }
11890                })
11891                .collect();
11892
11893            this.change_selections(Default::default(), window, cx, |s| {
11894                s.select(new_selections);
11895            });
11896
11897            this.request_autoscroll(Autoscroll::fit(), cx);
11898        });
11899    }
11900
11901    fn manipulate_immutable_lines<Fn>(
11902        &mut self,
11903        window: &mut Window,
11904        cx: &mut Context<Self>,
11905        mut callback: Fn,
11906    ) where
11907        Fn: FnMut(&mut Vec<&str>),
11908    {
11909        self.manipulate_lines(window, cx, |text| {
11910            let mut lines: Vec<&str> = text.split('\n').collect();
11911            let line_count_before = lines.len();
11912
11913            callback(&mut lines);
11914
11915            LineManipulationResult {
11916                new_text: lines.join("\n"),
11917                line_count_before,
11918                line_count_after: lines.len(),
11919            }
11920        });
11921    }
11922
11923    fn manipulate_mutable_lines<Fn>(
11924        &mut self,
11925        window: &mut Window,
11926        cx: &mut Context<Self>,
11927        mut callback: Fn,
11928    ) where
11929        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11930    {
11931        self.manipulate_lines(window, cx, |text| {
11932            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11933            let line_count_before = lines.len();
11934
11935            callback(&mut lines);
11936
11937            LineManipulationResult {
11938                new_text: lines.join("\n"),
11939                line_count_before,
11940                line_count_after: lines.len(),
11941            }
11942        });
11943    }
11944
11945    pub fn convert_indentation_to_spaces(
11946        &mut self,
11947        _: &ConvertIndentationToSpaces,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        let settings = self.buffer.read(cx).language_settings(cx);
11952        let tab_size = settings.tab_size.get() as usize;
11953
11954        self.manipulate_mutable_lines(window, cx, |lines| {
11955            // Allocates a reasonably sized scratch buffer once for the whole loop
11956            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11957            // Avoids recomputing spaces that could be inserted many times
11958            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11959                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11960                .collect();
11961
11962            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11963                let mut chars = line.as_ref().chars();
11964                let mut col = 0;
11965                let mut changed = false;
11966
11967                for ch in chars.by_ref() {
11968                    match ch {
11969                        ' ' => {
11970                            reindented_line.push(' ');
11971                            col += 1;
11972                        }
11973                        '\t' => {
11974                            // \t are converted to spaces depending on the current column
11975                            let spaces_len = tab_size - (col % tab_size);
11976                            reindented_line.extend(&space_cache[spaces_len - 1]);
11977                            col += spaces_len;
11978                            changed = true;
11979                        }
11980                        _ => {
11981                            // If we dont append before break, the character is consumed
11982                            reindented_line.push(ch);
11983                            break;
11984                        }
11985                    }
11986                }
11987
11988                if !changed {
11989                    reindented_line.clear();
11990                    continue;
11991                }
11992                // Append the rest of the line and replace old reference with new one
11993                reindented_line.extend(chars);
11994                *line = Cow::Owned(reindented_line.clone());
11995                reindented_line.clear();
11996            }
11997        });
11998    }
11999
12000    pub fn convert_indentation_to_tabs(
12001        &mut self,
12002        _: &ConvertIndentationToTabs,
12003        window: &mut Window,
12004        cx: &mut Context<Self>,
12005    ) {
12006        let settings = self.buffer.read(cx).language_settings(cx);
12007        let tab_size = settings.tab_size.get() as usize;
12008
12009        self.manipulate_mutable_lines(window, cx, |lines| {
12010            // Allocates a reasonably sized buffer once for the whole loop
12011            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12012            // Avoids recomputing spaces that could be inserted many times
12013            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12014                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12015                .collect();
12016
12017            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12018                let mut chars = line.chars();
12019                let mut spaces_count = 0;
12020                let mut first_non_indent_char = None;
12021                let mut changed = false;
12022
12023                for ch in chars.by_ref() {
12024                    match ch {
12025                        ' ' => {
12026                            // Keep track of spaces. Append \t when we reach tab_size
12027                            spaces_count += 1;
12028                            changed = true;
12029                            if spaces_count == tab_size {
12030                                reindented_line.push('\t');
12031                                spaces_count = 0;
12032                            }
12033                        }
12034                        '\t' => {
12035                            reindented_line.push('\t');
12036                            spaces_count = 0;
12037                        }
12038                        _ => {
12039                            // Dont append it yet, we might have remaining spaces
12040                            first_non_indent_char = Some(ch);
12041                            break;
12042                        }
12043                    }
12044                }
12045
12046                if !changed {
12047                    reindented_line.clear();
12048                    continue;
12049                }
12050                // Remaining spaces that didn't make a full tab stop
12051                if spaces_count > 0 {
12052                    reindented_line.extend(&space_cache[spaces_count - 1]);
12053                }
12054                // If we consume an extra character that was not indentation, add it back
12055                if let Some(extra_char) = first_non_indent_char {
12056                    reindented_line.push(extra_char);
12057                }
12058                // Append the rest of the line and replace old reference with new one
12059                reindented_line.extend(chars);
12060                *line = Cow::Owned(reindented_line.clone());
12061                reindented_line.clear();
12062            }
12063        });
12064    }
12065
12066    pub fn convert_to_upper_case(
12067        &mut self,
12068        _: &ConvertToUpperCase,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.manipulate_text(window, cx, |text| text.to_uppercase())
12073    }
12074
12075    pub fn convert_to_lower_case(
12076        &mut self,
12077        _: &ConvertToLowerCase,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        self.manipulate_text(window, cx, |text| text.to_lowercase())
12082    }
12083
12084    pub fn convert_to_title_case(
12085        &mut self,
12086        _: &ConvertToTitleCase,
12087        window: &mut Window,
12088        cx: &mut Context<Self>,
12089    ) {
12090        self.manipulate_text(window, cx, |text| {
12091            text.split('\n')
12092                .map(|line| line.to_case(Case::Title))
12093                .join("\n")
12094        })
12095    }
12096
12097    pub fn convert_to_snake_case(
12098        &mut self,
12099        _: &ConvertToSnakeCase,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12104    }
12105
12106    pub fn convert_to_kebab_case(
12107        &mut self,
12108        _: &ConvertToKebabCase,
12109        window: &mut Window,
12110        cx: &mut Context<Self>,
12111    ) {
12112        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12113    }
12114
12115    pub fn convert_to_upper_camel_case(
12116        &mut self,
12117        _: &ConvertToUpperCamelCase,
12118        window: &mut Window,
12119        cx: &mut Context<Self>,
12120    ) {
12121        self.manipulate_text(window, cx, |text| {
12122            text.split('\n')
12123                .map(|line| line.to_case(Case::UpperCamel))
12124                .join("\n")
12125        })
12126    }
12127
12128    pub fn convert_to_lower_camel_case(
12129        &mut self,
12130        _: &ConvertToLowerCamelCase,
12131        window: &mut Window,
12132        cx: &mut Context<Self>,
12133    ) {
12134        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12135    }
12136
12137    pub fn convert_to_opposite_case(
12138        &mut self,
12139        _: &ConvertToOppositeCase,
12140        window: &mut Window,
12141        cx: &mut Context<Self>,
12142    ) {
12143        self.manipulate_text(window, cx, |text| {
12144            text.chars()
12145                .fold(String::with_capacity(text.len()), |mut t, c| {
12146                    if c.is_uppercase() {
12147                        t.extend(c.to_lowercase());
12148                    } else {
12149                        t.extend(c.to_uppercase());
12150                    }
12151                    t
12152                })
12153        })
12154    }
12155
12156    pub fn convert_to_sentence_case(
12157        &mut self,
12158        _: &ConvertToSentenceCase,
12159        window: &mut Window,
12160        cx: &mut Context<Self>,
12161    ) {
12162        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12163    }
12164
12165    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12166        self.manipulate_text(window, cx, |text| {
12167            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12168            if has_upper_case_characters {
12169                text.to_lowercase()
12170            } else {
12171                text.to_uppercase()
12172            }
12173        })
12174    }
12175
12176    pub fn convert_to_rot13(
12177        &mut self,
12178        _: &ConvertToRot13,
12179        window: &mut Window,
12180        cx: &mut Context<Self>,
12181    ) {
12182        self.manipulate_text(window, cx, |text| {
12183            text.chars()
12184                .map(|c| match c {
12185                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12186                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12187                    _ => c,
12188                })
12189                .collect()
12190        })
12191    }
12192
12193    pub fn convert_to_rot47(
12194        &mut self,
12195        _: &ConvertToRot47,
12196        window: &mut Window,
12197        cx: &mut Context<Self>,
12198    ) {
12199        self.manipulate_text(window, cx, |text| {
12200            text.chars()
12201                .map(|c| {
12202                    let code_point = c as u32;
12203                    if code_point >= 33 && code_point <= 126 {
12204                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12205                    }
12206                    c
12207                })
12208                .collect()
12209        })
12210    }
12211
12212    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12213    where
12214        Fn: FnMut(&str) -> String,
12215    {
12216        let buffer = self.buffer.read(cx).snapshot(cx);
12217
12218        let mut new_selections = Vec::new();
12219        let mut edits = Vec::new();
12220        let mut selection_adjustment = 0isize;
12221
12222        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12223            let selection_is_empty = selection.is_empty();
12224
12225            let (start, end) = if selection_is_empty {
12226                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12227                (word_range.start, word_range.end)
12228            } else {
12229                (
12230                    buffer.point_to_offset(selection.start),
12231                    buffer.point_to_offset(selection.end),
12232                )
12233            };
12234
12235            let text = buffer.text_for_range(start..end).collect::<String>();
12236            let old_length = text.len() as isize;
12237            let text = callback(&text);
12238
12239            new_selections.push(Selection {
12240                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12241                end: MultiBufferOffset(
12242                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12243                ),
12244                goal: SelectionGoal::None,
12245                id: selection.id,
12246                reversed: selection.reversed,
12247            });
12248
12249            selection_adjustment += old_length - text.len() as isize;
12250
12251            edits.push((start..end, text));
12252        }
12253
12254        self.transact(window, cx, |this, window, cx| {
12255            this.buffer.update(cx, |buffer, cx| {
12256                buffer.edit(edits, None, cx);
12257            });
12258
12259            this.change_selections(Default::default(), window, cx, |s| {
12260                s.select(new_selections);
12261            });
12262
12263            this.request_autoscroll(Autoscroll::fit(), cx);
12264        });
12265    }
12266
12267    pub fn move_selection_on_drop(
12268        &mut self,
12269        selection: &Selection<Anchor>,
12270        target: DisplayPoint,
12271        is_cut: bool,
12272        window: &mut Window,
12273        cx: &mut Context<Self>,
12274    ) {
12275        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12276        let buffer = display_map.buffer_snapshot();
12277        let mut edits = Vec::new();
12278        let insert_point = display_map
12279            .clip_point(target, Bias::Left)
12280            .to_point(&display_map);
12281        let text = buffer
12282            .text_for_range(selection.start..selection.end)
12283            .collect::<String>();
12284        if is_cut {
12285            edits.push(((selection.start..selection.end), String::new()));
12286        }
12287        let insert_anchor = buffer.anchor_before(insert_point);
12288        edits.push(((insert_anchor..insert_anchor), text));
12289        let last_edit_start = insert_anchor.bias_left(buffer);
12290        let last_edit_end = insert_anchor.bias_right(buffer);
12291        self.transact(window, cx, |this, window, cx| {
12292            this.buffer.update(cx, |buffer, cx| {
12293                buffer.edit(edits, None, cx);
12294            });
12295            this.change_selections(Default::default(), window, cx, |s| {
12296                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12297            });
12298        });
12299    }
12300
12301    pub fn clear_selection_drag_state(&mut self) {
12302        self.selection_drag_state = SelectionDragState::None;
12303    }
12304
12305    pub fn duplicate(
12306        &mut self,
12307        upwards: bool,
12308        whole_lines: bool,
12309        window: &mut Window,
12310        cx: &mut Context<Self>,
12311    ) {
12312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12313
12314        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12315        let buffer = display_map.buffer_snapshot();
12316        let selections = self.selections.all::<Point>(&display_map);
12317
12318        let mut edits = Vec::new();
12319        let mut selections_iter = selections.iter().peekable();
12320        while let Some(selection) = selections_iter.next() {
12321            let mut rows = selection.spanned_rows(false, &display_map);
12322            // duplicate line-wise
12323            if whole_lines || selection.start == selection.end {
12324                // Avoid duplicating the same lines twice.
12325                while let Some(next_selection) = selections_iter.peek() {
12326                    let next_rows = next_selection.spanned_rows(false, &display_map);
12327                    if next_rows.start < rows.end {
12328                        rows.end = next_rows.end;
12329                        selections_iter.next().unwrap();
12330                    } else {
12331                        break;
12332                    }
12333                }
12334
12335                // Copy the text from the selected row region and splice it either at the start
12336                // or end of the region.
12337                let start = Point::new(rows.start.0, 0);
12338                let end = Point::new(
12339                    rows.end.previous_row().0,
12340                    buffer.line_len(rows.end.previous_row()),
12341                );
12342
12343                let mut text = buffer.text_for_range(start..end).collect::<String>();
12344
12345                let insert_location = if upwards {
12346                    // When duplicating upward, we need to insert before the current line.
12347                    // If we're on the last line and it doesn't end with a newline,
12348                    // we need to add a newline before the duplicated content.
12349                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12350                        && buffer.max_point().column > 0
12351                        && !text.ends_with('\n');
12352
12353                    if needs_leading_newline {
12354                        text.insert(0, '\n');
12355                        end
12356                    } else {
12357                        text.push('\n');
12358                        Point::new(rows.start.0, 0)
12359                    }
12360                } else {
12361                    text.push('\n');
12362                    start
12363                };
12364                edits.push((insert_location..insert_location, text));
12365            } else {
12366                // duplicate character-wise
12367                let start = selection.start;
12368                let end = selection.end;
12369                let text = buffer.text_for_range(start..end).collect::<String>();
12370                edits.push((selection.end..selection.end, text));
12371            }
12372        }
12373
12374        self.transact(window, cx, |this, window, cx| {
12375            this.buffer.update(cx, |buffer, cx| {
12376                buffer.edit(edits, None, cx);
12377            });
12378
12379            // When duplicating upward with whole lines, move the cursor to the duplicated line
12380            if upwards && whole_lines {
12381                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12382
12383                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12384                    let mut new_ranges = Vec::new();
12385                    let selections = s.all::<Point>(&display_map);
12386                    let mut selections_iter = selections.iter().peekable();
12387
12388                    while let Some(first_selection) = selections_iter.next() {
12389                        // Group contiguous selections together to find the total row span
12390                        let mut group_selections = vec![first_selection];
12391                        let mut rows = first_selection.spanned_rows(false, &display_map);
12392
12393                        while let Some(next_selection) = selections_iter.peek() {
12394                            let next_rows = next_selection.spanned_rows(false, &display_map);
12395                            if next_rows.start < rows.end {
12396                                rows.end = next_rows.end;
12397                                group_selections.push(selections_iter.next().unwrap());
12398                            } else {
12399                                break;
12400                            }
12401                        }
12402
12403                        let row_count = rows.end.0 - rows.start.0;
12404
12405                        // Move all selections in this group up by the total number of duplicated rows
12406                        for selection in group_selections {
12407                            let new_start = Point::new(
12408                                selection.start.row.saturating_sub(row_count),
12409                                selection.start.column,
12410                            );
12411
12412                            let new_end = Point::new(
12413                                selection.end.row.saturating_sub(row_count),
12414                                selection.end.column,
12415                            );
12416
12417                            new_ranges.push(new_start..new_end);
12418                        }
12419                    }
12420
12421                    s.select_ranges(new_ranges);
12422                });
12423            }
12424
12425            this.request_autoscroll(Autoscroll::fit(), cx);
12426        });
12427    }
12428
12429    pub fn duplicate_line_up(
12430        &mut self,
12431        _: &DuplicateLineUp,
12432        window: &mut Window,
12433        cx: &mut Context<Self>,
12434    ) {
12435        self.duplicate(true, true, window, cx);
12436    }
12437
12438    pub fn duplicate_line_down(
12439        &mut self,
12440        _: &DuplicateLineDown,
12441        window: &mut Window,
12442        cx: &mut Context<Self>,
12443    ) {
12444        self.duplicate(false, true, window, cx);
12445    }
12446
12447    pub fn duplicate_selection(
12448        &mut self,
12449        _: &DuplicateSelection,
12450        window: &mut Window,
12451        cx: &mut Context<Self>,
12452    ) {
12453        self.duplicate(false, false, window, cx);
12454    }
12455
12456    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12458        if self.mode.is_single_line() {
12459            cx.propagate();
12460            return;
12461        }
12462
12463        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12464        let buffer = self.buffer.read(cx).snapshot(cx);
12465
12466        let mut edits = Vec::new();
12467        let mut unfold_ranges = Vec::new();
12468        let mut refold_creases = Vec::new();
12469
12470        let selections = self.selections.all::<Point>(&display_map);
12471        let mut selections = selections.iter().peekable();
12472        let mut contiguous_row_selections = Vec::new();
12473        let mut new_selections = Vec::new();
12474
12475        while let Some(selection) = selections.next() {
12476            // Find all the selections that span a contiguous row range
12477            let (start_row, end_row) = consume_contiguous_rows(
12478                &mut contiguous_row_selections,
12479                selection,
12480                &display_map,
12481                &mut selections,
12482            );
12483
12484            // Move the text spanned by the row range to be before the line preceding the row range
12485            if start_row.0 > 0 {
12486                let range_to_move = Point::new(
12487                    start_row.previous_row().0,
12488                    buffer.line_len(start_row.previous_row()),
12489                )
12490                    ..Point::new(
12491                        end_row.previous_row().0,
12492                        buffer.line_len(end_row.previous_row()),
12493                    );
12494                let insertion_point = display_map
12495                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12496                    .0;
12497
12498                // Don't move lines across excerpts
12499                if buffer
12500                    .excerpt_containing(insertion_point..range_to_move.end)
12501                    .is_some()
12502                {
12503                    let text = buffer
12504                        .text_for_range(range_to_move.clone())
12505                        .flat_map(|s| s.chars())
12506                        .skip(1)
12507                        .chain(['\n'])
12508                        .collect::<String>();
12509
12510                    edits.push((
12511                        buffer.anchor_after(range_to_move.start)
12512                            ..buffer.anchor_before(range_to_move.end),
12513                        String::new(),
12514                    ));
12515                    let insertion_anchor = buffer.anchor_after(insertion_point);
12516                    edits.push((insertion_anchor..insertion_anchor, text));
12517
12518                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12519
12520                    // Move selections up
12521                    new_selections.extend(contiguous_row_selections.drain(..).map(
12522                        |mut selection| {
12523                            selection.start.row -= row_delta;
12524                            selection.end.row -= row_delta;
12525                            selection
12526                        },
12527                    ));
12528
12529                    // Move folds up
12530                    unfold_ranges.push(range_to_move.clone());
12531                    for fold in display_map.folds_in_range(
12532                        buffer.anchor_before(range_to_move.start)
12533                            ..buffer.anchor_after(range_to_move.end),
12534                    ) {
12535                        let mut start = fold.range.start.to_point(&buffer);
12536                        let mut end = fold.range.end.to_point(&buffer);
12537                        start.row -= row_delta;
12538                        end.row -= row_delta;
12539                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12540                    }
12541                }
12542            }
12543
12544            // If we didn't move line(s), preserve the existing selections
12545            new_selections.append(&mut contiguous_row_selections);
12546        }
12547
12548        self.transact(window, cx, |this, window, cx| {
12549            this.unfold_ranges(&unfold_ranges, true, true, cx);
12550            this.buffer.update(cx, |buffer, cx| {
12551                for (range, text) in edits {
12552                    buffer.edit([(range, text)], None, cx);
12553                }
12554            });
12555            this.fold_creases(refold_creases, true, window, cx);
12556            this.change_selections(Default::default(), window, cx, |s| {
12557                s.select(new_selections);
12558            })
12559        });
12560    }
12561
12562    pub fn move_line_down(
12563        &mut self,
12564        _: &MoveLineDown,
12565        window: &mut Window,
12566        cx: &mut Context<Self>,
12567    ) {
12568        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12569        if self.mode.is_single_line() {
12570            cx.propagate();
12571            return;
12572        }
12573
12574        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12575        let buffer = self.buffer.read(cx).snapshot(cx);
12576
12577        let mut edits = Vec::new();
12578        let mut unfold_ranges = Vec::new();
12579        let mut refold_creases = Vec::new();
12580
12581        let selections = self.selections.all::<Point>(&display_map);
12582        let mut selections = selections.iter().peekable();
12583        let mut contiguous_row_selections = Vec::new();
12584        let mut new_selections = Vec::new();
12585
12586        while let Some(selection) = selections.next() {
12587            // Find all the selections that span a contiguous row range
12588            let (start_row, end_row) = consume_contiguous_rows(
12589                &mut contiguous_row_selections,
12590                selection,
12591                &display_map,
12592                &mut selections,
12593            );
12594
12595            // Move the text spanned by the row range to be after the last line of the row range
12596            if end_row.0 <= buffer.max_point().row {
12597                let range_to_move =
12598                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12599                let insertion_point = display_map
12600                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12601                    .0;
12602
12603                // Don't move lines across excerpt boundaries
12604                if buffer
12605                    .excerpt_containing(range_to_move.start..insertion_point)
12606                    .is_some()
12607                {
12608                    let mut text = String::from("\n");
12609                    text.extend(buffer.text_for_range(range_to_move.clone()));
12610                    text.pop(); // Drop trailing newline
12611                    edits.push((
12612                        buffer.anchor_after(range_to_move.start)
12613                            ..buffer.anchor_before(range_to_move.end),
12614                        String::new(),
12615                    ));
12616                    let insertion_anchor = buffer.anchor_after(insertion_point);
12617                    edits.push((insertion_anchor..insertion_anchor, text));
12618
12619                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12620
12621                    // Move selections down
12622                    new_selections.extend(contiguous_row_selections.drain(..).map(
12623                        |mut selection| {
12624                            selection.start.row += row_delta;
12625                            selection.end.row += row_delta;
12626                            selection
12627                        },
12628                    ));
12629
12630                    // Move folds down
12631                    unfold_ranges.push(range_to_move.clone());
12632                    for fold in display_map.folds_in_range(
12633                        buffer.anchor_before(range_to_move.start)
12634                            ..buffer.anchor_after(range_to_move.end),
12635                    ) {
12636                        let mut start = fold.range.start.to_point(&buffer);
12637                        let mut end = fold.range.end.to_point(&buffer);
12638                        start.row += row_delta;
12639                        end.row += row_delta;
12640                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12641                    }
12642                }
12643            }
12644
12645            // If we didn't move line(s), preserve the existing selections
12646            new_selections.append(&mut contiguous_row_selections);
12647        }
12648
12649        self.transact(window, cx, |this, window, cx| {
12650            this.unfold_ranges(&unfold_ranges, true, true, cx);
12651            this.buffer.update(cx, |buffer, cx| {
12652                for (range, text) in edits {
12653                    buffer.edit([(range, text)], None, cx);
12654                }
12655            });
12656            this.fold_creases(refold_creases, true, window, cx);
12657            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12658        });
12659    }
12660
12661    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12663        let text_layout_details = &self.text_layout_details(window);
12664        self.transact(window, cx, |this, window, cx| {
12665            let edits = this.change_selections(Default::default(), window, cx, |s| {
12666                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12667                s.move_with(|display_map, selection| {
12668                    if !selection.is_empty() {
12669                        return;
12670                    }
12671
12672                    let mut head = selection.head();
12673                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12674                    if head.column() == display_map.line_len(head.row()) {
12675                        transpose_offset = display_map
12676                            .buffer_snapshot()
12677                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12678                    }
12679
12680                    if transpose_offset == MultiBufferOffset(0) {
12681                        return;
12682                    }
12683
12684                    *head.column_mut() += 1;
12685                    head = display_map.clip_point(head, Bias::Right);
12686                    let goal = SelectionGoal::HorizontalPosition(
12687                        display_map
12688                            .x_for_display_point(head, text_layout_details)
12689                            .into(),
12690                    );
12691                    selection.collapse_to(head, goal);
12692
12693                    let transpose_start = display_map
12694                        .buffer_snapshot()
12695                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12696                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12697                        let transpose_end = display_map
12698                            .buffer_snapshot()
12699                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12700                        if let Some(ch) = display_map
12701                            .buffer_snapshot()
12702                            .chars_at(transpose_start)
12703                            .next()
12704                        {
12705                            edits.push((transpose_start..transpose_offset, String::new()));
12706                            edits.push((transpose_end..transpose_end, ch.to_string()));
12707                        }
12708                    }
12709                });
12710                edits
12711            });
12712            this.buffer
12713                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12714            let selections = this
12715                .selections
12716                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12717            this.change_selections(Default::default(), window, cx, |s| {
12718                s.select(selections);
12719            });
12720        });
12721    }
12722
12723    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12724        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12725        if self.mode.is_single_line() {
12726            cx.propagate();
12727            return;
12728        }
12729
12730        self.rewrap_impl(RewrapOptions::default(), cx)
12731    }
12732
12733    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12734        let buffer = self.buffer.read(cx).snapshot(cx);
12735        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12736
12737        #[derive(Clone, Debug, PartialEq)]
12738        enum CommentFormat {
12739            /// single line comment, with prefix for line
12740            Line(String),
12741            /// single line within a block comment, with prefix for line
12742            BlockLine(String),
12743            /// a single line of a block comment that includes the initial delimiter
12744            BlockCommentWithStart(BlockCommentConfig),
12745            /// a single line of a block comment that includes the ending delimiter
12746            BlockCommentWithEnd(BlockCommentConfig),
12747        }
12748
12749        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12750        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12751            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12752                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12753                .peekable();
12754
12755            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12756                row
12757            } else {
12758                return Vec::new();
12759            };
12760
12761            let language_settings = buffer.language_settings_at(selection.head(), cx);
12762            let language_scope = buffer.language_scope_at(selection.head());
12763
12764            let indent_and_prefix_for_row =
12765                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12766                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12767                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12768                        &language_scope
12769                    {
12770                        let indent_end = Point::new(row, indent.len);
12771                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12772                        let line_text_after_indent = buffer
12773                            .text_for_range(indent_end..line_end)
12774                            .collect::<String>();
12775
12776                        let is_within_comment_override = buffer
12777                            .language_scope_at(indent_end)
12778                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12779                        let comment_delimiters = if is_within_comment_override {
12780                            // we are within a comment syntax node, but we don't
12781                            // yet know what kind of comment: block, doc or line
12782                            match (
12783                                language_scope.documentation_comment(),
12784                                language_scope.block_comment(),
12785                            ) {
12786                                (Some(config), _) | (_, Some(config))
12787                                    if buffer.contains_str_at(indent_end, &config.start) =>
12788                                {
12789                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12790                                }
12791                                (Some(config), _) | (_, Some(config))
12792                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12793                                {
12794                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12795                                }
12796                                (Some(config), _) | (_, Some(config))
12797                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12798                                {
12799                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12800                                }
12801                                (_, _) => language_scope
12802                                    .line_comment_prefixes()
12803                                    .iter()
12804                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12805                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12806                            }
12807                        } else {
12808                            // we not in an overridden comment node, but we may
12809                            // be within a non-overridden line comment node
12810                            language_scope
12811                                .line_comment_prefixes()
12812                                .iter()
12813                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12814                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12815                        };
12816
12817                        let rewrap_prefix = language_scope
12818                            .rewrap_prefixes()
12819                            .iter()
12820                            .find_map(|prefix_regex| {
12821                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12822                                    if mat.start() == 0 {
12823                                        Some(mat.as_str().to_string())
12824                                    } else {
12825                                        None
12826                                    }
12827                                })
12828                            })
12829                            .flatten();
12830                        (comment_delimiters, rewrap_prefix)
12831                    } else {
12832                        (None, None)
12833                    };
12834                    (indent, comment_prefix, rewrap_prefix)
12835                };
12836
12837            let mut ranges = Vec::new();
12838            let from_empty_selection = selection.is_empty();
12839
12840            let mut current_range_start = first_row;
12841            let mut prev_row = first_row;
12842            let (
12843                mut current_range_indent,
12844                mut current_range_comment_delimiters,
12845                mut current_range_rewrap_prefix,
12846            ) = indent_and_prefix_for_row(first_row);
12847
12848            for row in non_blank_rows_iter.skip(1) {
12849                let has_paragraph_break = row > prev_row + 1;
12850
12851                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12852                    indent_and_prefix_for_row(row);
12853
12854                let has_indent_change = row_indent != current_range_indent;
12855                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12856
12857                let has_boundary_change = has_comment_change
12858                    || row_rewrap_prefix.is_some()
12859                    || (has_indent_change && current_range_comment_delimiters.is_some());
12860
12861                if has_paragraph_break || has_boundary_change {
12862                    ranges.push((
12863                        language_settings.clone(),
12864                        Point::new(current_range_start, 0)
12865                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12866                        current_range_indent,
12867                        current_range_comment_delimiters.clone(),
12868                        current_range_rewrap_prefix.clone(),
12869                        from_empty_selection,
12870                    ));
12871                    current_range_start = row;
12872                    current_range_indent = row_indent;
12873                    current_range_comment_delimiters = row_comment_delimiters;
12874                    current_range_rewrap_prefix = row_rewrap_prefix;
12875                }
12876                prev_row = row;
12877            }
12878
12879            ranges.push((
12880                language_settings.clone(),
12881                Point::new(current_range_start, 0)
12882                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12883                current_range_indent,
12884                current_range_comment_delimiters,
12885                current_range_rewrap_prefix,
12886                from_empty_selection,
12887            ));
12888
12889            ranges
12890        });
12891
12892        let mut edits = Vec::new();
12893        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12894
12895        for (
12896            language_settings,
12897            wrap_range,
12898            mut indent_size,
12899            comment_prefix,
12900            rewrap_prefix,
12901            from_empty_selection,
12902        ) in wrap_ranges
12903        {
12904            let mut start_row = wrap_range.start.row;
12905            let mut end_row = wrap_range.end.row;
12906
12907            // Skip selections that overlap with a range that has already been rewrapped.
12908            let selection_range = start_row..end_row;
12909            if rewrapped_row_ranges
12910                .iter()
12911                .any(|range| range.overlaps(&selection_range))
12912            {
12913                continue;
12914            }
12915
12916            let tab_size = language_settings.tab_size;
12917
12918            let (line_prefix, inside_comment) = match &comment_prefix {
12919                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12920                    (Some(prefix.as_str()), true)
12921                }
12922                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12923                    (Some(prefix.as_ref()), true)
12924                }
12925                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12926                    start: _,
12927                    end: _,
12928                    prefix,
12929                    tab_size,
12930                })) => {
12931                    indent_size.len += tab_size;
12932                    (Some(prefix.as_ref()), true)
12933                }
12934                None => (None, false),
12935            };
12936            let indent_prefix = indent_size.chars().collect::<String>();
12937            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12938
12939            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12940                RewrapBehavior::InComments => inside_comment,
12941                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12942                RewrapBehavior::Anywhere => true,
12943            };
12944
12945            let should_rewrap = options.override_language_settings
12946                || allow_rewrap_based_on_language
12947                || self.hard_wrap.is_some();
12948            if !should_rewrap {
12949                continue;
12950            }
12951
12952            if from_empty_selection {
12953                'expand_upwards: while start_row > 0 {
12954                    let prev_row = start_row - 1;
12955                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12956                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12957                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12958                    {
12959                        start_row = prev_row;
12960                    } else {
12961                        break 'expand_upwards;
12962                    }
12963                }
12964
12965                'expand_downwards: while end_row < buffer.max_point().row {
12966                    let next_row = end_row + 1;
12967                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12968                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12969                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12970                    {
12971                        end_row = next_row;
12972                    } else {
12973                        break 'expand_downwards;
12974                    }
12975                }
12976            }
12977
12978            let start = Point::new(start_row, 0);
12979            let start_offset = ToOffset::to_offset(&start, &buffer);
12980            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12981            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12982            let mut first_line_delimiter = None;
12983            let mut last_line_delimiter = None;
12984            let Some(lines_without_prefixes) = selection_text
12985                .lines()
12986                .enumerate()
12987                .map(|(ix, line)| {
12988                    let line_trimmed = line.trim_start();
12989                    if rewrap_prefix.is_some() && ix > 0 {
12990                        Ok(line_trimmed)
12991                    } else if let Some(
12992                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12993                            start,
12994                            prefix,
12995                            end,
12996                            tab_size,
12997                        })
12998                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12999                            start,
13000                            prefix,
13001                            end,
13002                            tab_size,
13003                        }),
13004                    ) = &comment_prefix
13005                    {
13006                        let line_trimmed = line_trimmed
13007                            .strip_prefix(start.as_ref())
13008                            .map(|s| {
13009                                let mut indent_size = indent_size;
13010                                indent_size.len -= tab_size;
13011                                let indent_prefix: String = indent_size.chars().collect();
13012                                first_line_delimiter = Some((indent_prefix, start));
13013                                s.trim_start()
13014                            })
13015                            .unwrap_or(line_trimmed);
13016                        let line_trimmed = line_trimmed
13017                            .strip_suffix(end.as_ref())
13018                            .map(|s| {
13019                                last_line_delimiter = Some(end);
13020                                s.trim_end()
13021                            })
13022                            .unwrap_or(line_trimmed);
13023                        let line_trimmed = line_trimmed
13024                            .strip_prefix(prefix.as_ref())
13025                            .unwrap_or(line_trimmed);
13026                        Ok(line_trimmed)
13027                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13028                        line_trimmed.strip_prefix(prefix).with_context(|| {
13029                            format!("line did not start with prefix {prefix:?}: {line:?}")
13030                        })
13031                    } else {
13032                        line_trimmed
13033                            .strip_prefix(&line_prefix.trim_start())
13034                            .with_context(|| {
13035                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13036                            })
13037                    }
13038                })
13039                .collect::<Result<Vec<_>, _>>()
13040                .log_err()
13041            else {
13042                continue;
13043            };
13044
13045            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13046                buffer
13047                    .language_settings_at(Point::new(start_row, 0), cx)
13048                    .preferred_line_length as usize
13049            });
13050
13051            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13052                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13053            } else {
13054                line_prefix.clone()
13055            };
13056
13057            let wrapped_text = {
13058                let mut wrapped_text = wrap_with_prefix(
13059                    line_prefix,
13060                    subsequent_lines_prefix,
13061                    lines_without_prefixes.join("\n"),
13062                    wrap_column,
13063                    tab_size,
13064                    options.preserve_existing_whitespace,
13065                );
13066
13067                if let Some((indent, delimiter)) = first_line_delimiter {
13068                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13069                }
13070                if let Some(last_line) = last_line_delimiter {
13071                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13072                }
13073
13074                wrapped_text
13075            };
13076
13077            // TODO: should always use char-based diff while still supporting cursor behavior that
13078            // matches vim.
13079            let mut diff_options = DiffOptions::default();
13080            if options.override_language_settings {
13081                diff_options.max_word_diff_len = 0;
13082                diff_options.max_word_diff_line_count = 0;
13083            } else {
13084                diff_options.max_word_diff_len = usize::MAX;
13085                diff_options.max_word_diff_line_count = usize::MAX;
13086            }
13087
13088            for (old_range, new_text) in
13089                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13090            {
13091                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13092                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13093                edits.push((edit_start..edit_end, new_text));
13094            }
13095
13096            rewrapped_row_ranges.push(start_row..=end_row);
13097        }
13098
13099        self.buffer
13100            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13101    }
13102
13103    pub fn cut_common(
13104        &mut self,
13105        cut_no_selection_line: bool,
13106        window: &mut Window,
13107        cx: &mut Context<Self>,
13108    ) -> ClipboardItem {
13109        let mut text = String::new();
13110        let buffer = self.buffer.read(cx).snapshot(cx);
13111        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13112        let mut clipboard_selections = Vec::with_capacity(selections.len());
13113        {
13114            let max_point = buffer.max_point();
13115            let mut is_first = true;
13116            let mut prev_selection_was_entire_line = false;
13117            for selection in &mut selections {
13118                let is_entire_line =
13119                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13120                if is_entire_line {
13121                    selection.start = Point::new(selection.start.row, 0);
13122                    if !selection.is_empty() && selection.end.column == 0 {
13123                        selection.end = cmp::min(max_point, selection.end);
13124                    } else {
13125                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13126                    }
13127                    selection.goal = SelectionGoal::None;
13128                }
13129                if is_first {
13130                    is_first = false;
13131                } else if !prev_selection_was_entire_line {
13132                    text += "\n";
13133                }
13134                prev_selection_was_entire_line = is_entire_line;
13135                let mut len = 0;
13136                for chunk in buffer.text_for_range(selection.start..selection.end) {
13137                    text.push_str(chunk);
13138                    len += chunk.len();
13139                }
13140
13141                clipboard_selections.push(ClipboardSelection::for_buffer(
13142                    len,
13143                    is_entire_line,
13144                    selection.range(),
13145                    &buffer,
13146                    self.project.as_ref(),
13147                    cx,
13148                ));
13149            }
13150        }
13151
13152        self.transact(window, cx, |this, window, cx| {
13153            this.change_selections(Default::default(), window, cx, |s| {
13154                s.select(selections);
13155            });
13156            this.insert("", window, cx);
13157        });
13158        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13159    }
13160
13161    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13163        let item = self.cut_common(true, window, cx);
13164        cx.write_to_clipboard(item);
13165    }
13166
13167    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13169        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13170            s.move_with(|snapshot, sel| {
13171                if sel.is_empty() {
13172                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13173                }
13174                if sel.is_empty() {
13175                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13176                }
13177            });
13178        });
13179        let item = self.cut_common(false, window, cx);
13180        cx.set_global(KillRing(item))
13181    }
13182
13183    pub fn kill_ring_yank(
13184        &mut self,
13185        _: &KillRingYank,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13190        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13191            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13192                (kill_ring.text().to_string(), kill_ring.metadata_json())
13193            } else {
13194                return;
13195            }
13196        } else {
13197            return;
13198        };
13199        self.do_paste(&text, metadata, false, window, cx);
13200    }
13201
13202    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13203        self.do_copy(true, cx);
13204    }
13205
13206    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13207        self.do_copy(false, cx);
13208    }
13209
13210    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13211        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13212        let buffer = self.buffer.read(cx).read(cx);
13213        let mut text = String::new();
13214
13215        let mut clipboard_selections = Vec::with_capacity(selections.len());
13216        {
13217            let max_point = buffer.max_point();
13218            let mut is_first = true;
13219            let mut prev_selection_was_entire_line = false;
13220            for selection in &selections {
13221                let mut start = selection.start;
13222                let mut end = selection.end;
13223                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13224                let mut add_trailing_newline = false;
13225                if is_entire_line {
13226                    start = Point::new(start.row, 0);
13227                    let next_line_start = Point::new(end.row + 1, 0);
13228                    if next_line_start <= max_point {
13229                        end = next_line_start;
13230                    } else {
13231                        // We're on the last line without a trailing newline.
13232                        // Copy to the end of the line and add a newline afterwards.
13233                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13234                        add_trailing_newline = true;
13235                    }
13236                }
13237
13238                let mut trimmed_selections = Vec::new();
13239                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13240                    let row = MultiBufferRow(start.row);
13241                    let first_indent = buffer.indent_size_for_line(row);
13242                    if first_indent.len == 0 || start.column > first_indent.len {
13243                        trimmed_selections.push(start..end);
13244                    } else {
13245                        trimmed_selections.push(
13246                            Point::new(row.0, first_indent.len)
13247                                ..Point::new(row.0, buffer.line_len(row)),
13248                        );
13249                        for row in start.row + 1..=end.row {
13250                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13251                            if row == end.row {
13252                                line_len = end.column;
13253                            }
13254                            if line_len == 0 {
13255                                trimmed_selections
13256                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13257                                continue;
13258                            }
13259                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13260                            if row_indent_size.len >= first_indent.len {
13261                                trimmed_selections.push(
13262                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13263                                );
13264                            } else {
13265                                trimmed_selections.clear();
13266                                trimmed_selections.push(start..end);
13267                                break;
13268                            }
13269                        }
13270                    }
13271                } else {
13272                    trimmed_selections.push(start..end);
13273                }
13274
13275                for trimmed_range in trimmed_selections {
13276                    if is_first {
13277                        is_first = false;
13278                    } else if !prev_selection_was_entire_line {
13279                        text += "\n";
13280                    }
13281                    prev_selection_was_entire_line = is_entire_line;
13282                    let mut len = 0;
13283                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13284                        text.push_str(chunk);
13285                        len += chunk.len();
13286                    }
13287                    if add_trailing_newline {
13288                        text.push('\n');
13289                        len += 1;
13290                    }
13291                    clipboard_selections.push(ClipboardSelection::for_buffer(
13292                        len,
13293                        is_entire_line,
13294                        trimmed_range,
13295                        &buffer,
13296                        self.project.as_ref(),
13297                        cx,
13298                    ));
13299                }
13300            }
13301        }
13302
13303        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13304            text,
13305            clipboard_selections,
13306        ));
13307    }
13308
13309    pub fn do_paste(
13310        &mut self,
13311        text: &String,
13312        clipboard_selections: Option<Vec<ClipboardSelection>>,
13313        handle_entire_lines: bool,
13314        window: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        if self.read_only(cx) {
13318            return;
13319        }
13320
13321        let clipboard_text = Cow::Borrowed(text.as_str());
13322
13323        self.transact(window, cx, |this, window, cx| {
13324            let had_active_edit_prediction = this.has_active_edit_prediction();
13325            let display_map = this.display_snapshot(cx);
13326            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13327            let cursor_offset = this
13328                .selections
13329                .last::<MultiBufferOffset>(&display_map)
13330                .head();
13331
13332            if let Some(mut clipboard_selections) = clipboard_selections {
13333                let all_selections_were_entire_line =
13334                    clipboard_selections.iter().all(|s| s.is_entire_line);
13335                let first_selection_indent_column =
13336                    clipboard_selections.first().map(|s| s.first_line_indent);
13337                if clipboard_selections.len() != old_selections.len() {
13338                    clipboard_selections.drain(..);
13339                }
13340                let mut auto_indent_on_paste = true;
13341
13342                this.buffer.update(cx, |buffer, cx| {
13343                    let snapshot = buffer.read(cx);
13344                    auto_indent_on_paste = snapshot
13345                        .language_settings_at(cursor_offset, cx)
13346                        .auto_indent_on_paste;
13347
13348                    let mut start_offset = 0;
13349                    let mut edits = Vec::new();
13350                    let mut original_indent_columns = Vec::new();
13351                    for (ix, selection) in old_selections.iter().enumerate() {
13352                        let to_insert;
13353                        let entire_line;
13354                        let original_indent_column;
13355                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13356                            let end_offset = start_offset + clipboard_selection.len;
13357                            to_insert = &clipboard_text[start_offset..end_offset];
13358                            entire_line = clipboard_selection.is_entire_line;
13359                            start_offset = if entire_line {
13360                                end_offset
13361                            } else {
13362                                end_offset + 1
13363                            };
13364                            original_indent_column = Some(clipboard_selection.first_line_indent);
13365                        } else {
13366                            to_insert = &*clipboard_text;
13367                            entire_line = all_selections_were_entire_line;
13368                            original_indent_column = first_selection_indent_column
13369                        }
13370
13371                        let (range, to_insert) =
13372                            if selection.is_empty() && handle_entire_lines && entire_line {
13373                                // If the corresponding selection was empty when this slice of the
13374                                // clipboard text was written, then the entire line containing the
13375                                // selection was copied. If this selection is also currently empty,
13376                                // then paste the line before the current line of the buffer.
13377                                let column = selection.start.to_point(&snapshot).column as usize;
13378                                let line_start = selection.start - column;
13379                                (line_start..line_start, Cow::Borrowed(to_insert))
13380                            } else {
13381                                let language = snapshot.language_at(selection.head());
13382                                let range = selection.range();
13383                                if let Some(language) = language
13384                                    && language.name() == "Markdown".into()
13385                                {
13386                                    edit_for_markdown_paste(
13387                                        &snapshot,
13388                                        range,
13389                                        to_insert,
13390                                        url::Url::parse(to_insert).ok(),
13391                                    )
13392                                } else {
13393                                    (range, Cow::Borrowed(to_insert))
13394                                }
13395                            };
13396
13397                        edits.push((range, to_insert));
13398                        original_indent_columns.push(original_indent_column);
13399                    }
13400                    drop(snapshot);
13401
13402                    buffer.edit(
13403                        edits,
13404                        if auto_indent_on_paste {
13405                            Some(AutoindentMode::Block {
13406                                original_indent_columns,
13407                            })
13408                        } else {
13409                            None
13410                        },
13411                        cx,
13412                    );
13413                });
13414
13415                let selections = this
13416                    .selections
13417                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13418                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13419            } else {
13420                let url = url::Url::parse(&clipboard_text).ok();
13421
13422                let auto_indent_mode = if !clipboard_text.is_empty() {
13423                    Some(AutoindentMode::Block {
13424                        original_indent_columns: Vec::new(),
13425                    })
13426                } else {
13427                    None
13428                };
13429
13430                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13431                    let snapshot = buffer.snapshot(cx);
13432
13433                    let anchors = old_selections
13434                        .iter()
13435                        .map(|s| {
13436                            let anchor = snapshot.anchor_after(s.head());
13437                            s.map(|_| anchor)
13438                        })
13439                        .collect::<Vec<_>>();
13440
13441                    let mut edits = Vec::new();
13442
13443                    for selection in old_selections.iter() {
13444                        let language = snapshot.language_at(selection.head());
13445                        let range = selection.range();
13446
13447                        let (edit_range, edit_text) = if let Some(language) = language
13448                            && language.name() == "Markdown".into()
13449                        {
13450                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13451                        } else {
13452                            (range, clipboard_text.clone())
13453                        };
13454
13455                        edits.push((edit_range, edit_text));
13456                    }
13457
13458                    drop(snapshot);
13459                    buffer.edit(edits, auto_indent_mode, cx);
13460
13461                    anchors
13462                });
13463
13464                this.change_selections(Default::default(), window, cx, |s| {
13465                    s.select_anchors(selection_anchors);
13466                });
13467            }
13468
13469            //   🤔                 |    ..     | show_in_menu |
13470            // | ..                  |   true        true
13471            // | had_edit_prediction |   false       true
13472
13473            let trigger_in_words =
13474                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13475
13476            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13477        });
13478    }
13479
13480    pub fn diff_clipboard_with_selection(
13481        &mut self,
13482        _: &DiffClipboardWithSelection,
13483        window: &mut Window,
13484        cx: &mut Context<Self>,
13485    ) {
13486        let selections = self
13487            .selections
13488            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13489
13490        if selections.is_empty() {
13491            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13492            return;
13493        };
13494
13495        let clipboard_text = match cx.read_from_clipboard() {
13496            Some(item) => match item.entries().first() {
13497                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13498                _ => None,
13499            },
13500            None => None,
13501        };
13502
13503        let Some(clipboard_text) = clipboard_text else {
13504            log::warn!("Clipboard doesn't contain text.");
13505            return;
13506        };
13507
13508        window.dispatch_action(
13509            Box::new(DiffClipboardWithSelectionData {
13510                clipboard_text,
13511                editor: cx.entity(),
13512            }),
13513            cx,
13514        );
13515    }
13516
13517    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13518        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13519        if let Some(item) = cx.read_from_clipboard() {
13520            let entries = item.entries();
13521
13522            match entries.first() {
13523                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13524                // of all the pasted entries.
13525                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13526                    .do_paste(
13527                        clipboard_string.text(),
13528                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13529                        true,
13530                        window,
13531                        cx,
13532                    ),
13533                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13534            }
13535        }
13536    }
13537
13538    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13539        if self.read_only(cx) {
13540            return;
13541        }
13542
13543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13544
13545        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13546            if let Some((selections, _)) =
13547                self.selection_history.transaction(transaction_id).cloned()
13548            {
13549                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13550                    s.select_anchors(selections.to_vec());
13551                });
13552            } else {
13553                log::error!(
13554                    "No entry in selection_history found for undo. \
13555                     This may correspond to a bug where undo does not update the selection. \
13556                     If this is occurring, please add details to \
13557                     https://github.com/zed-industries/zed/issues/22692"
13558                );
13559            }
13560            self.request_autoscroll(Autoscroll::fit(), cx);
13561            self.unmark_text(window, cx);
13562            self.refresh_edit_prediction(true, false, window, cx);
13563            cx.emit(EditorEvent::Edited { transaction_id });
13564            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13565        }
13566    }
13567
13568    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13569        if self.read_only(cx) {
13570            return;
13571        }
13572
13573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13574
13575        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13576            if let Some((_, Some(selections))) =
13577                self.selection_history.transaction(transaction_id).cloned()
13578            {
13579                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13580                    s.select_anchors(selections.to_vec());
13581                });
13582            } else {
13583                log::error!(
13584                    "No entry in selection_history found for redo. \
13585                     This may correspond to a bug where undo does not update the selection. \
13586                     If this is occurring, please add details to \
13587                     https://github.com/zed-industries/zed/issues/22692"
13588                );
13589            }
13590            self.request_autoscroll(Autoscroll::fit(), cx);
13591            self.unmark_text(window, cx);
13592            self.refresh_edit_prediction(true, false, window, cx);
13593            cx.emit(EditorEvent::Edited { transaction_id });
13594        }
13595    }
13596
13597    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13598        self.buffer
13599            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13600    }
13601
13602    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13603        self.buffer
13604            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13605    }
13606
13607    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13609        self.change_selections(Default::default(), window, cx, |s| {
13610            s.move_with(|map, selection| {
13611                let cursor = if selection.is_empty() {
13612                    movement::left(map, selection.start)
13613                } else {
13614                    selection.start
13615                };
13616                selection.collapse_to(cursor, SelectionGoal::None);
13617            });
13618        })
13619    }
13620
13621    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13623        self.change_selections(Default::default(), window, cx, |s| {
13624            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13625        })
13626    }
13627
13628    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13630        self.change_selections(Default::default(), window, cx, |s| {
13631            s.move_with(|map, selection| {
13632                let cursor = if selection.is_empty() {
13633                    movement::right(map, selection.end)
13634                } else {
13635                    selection.end
13636                };
13637                selection.collapse_to(cursor, SelectionGoal::None)
13638            });
13639        })
13640    }
13641
13642    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644        self.change_selections(Default::default(), window, cx, |s| {
13645            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13646        });
13647    }
13648
13649    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13650        if self.take_rename(true, window, cx).is_some() {
13651            return;
13652        }
13653
13654        if self.mode.is_single_line() {
13655            cx.propagate();
13656            return;
13657        }
13658
13659        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13660
13661        let text_layout_details = &self.text_layout_details(window);
13662        let selection_count = self.selections.count();
13663        let first_selection = self.selections.first_anchor();
13664
13665        self.change_selections(Default::default(), window, cx, |s| {
13666            s.move_with(|map, selection| {
13667                if !selection.is_empty() {
13668                    selection.goal = SelectionGoal::None;
13669                }
13670                let (cursor, goal) = movement::up(
13671                    map,
13672                    selection.start,
13673                    selection.goal,
13674                    false,
13675                    text_layout_details,
13676                );
13677                selection.collapse_to(cursor, goal);
13678            });
13679        });
13680
13681        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13682        {
13683            cx.propagate();
13684        }
13685    }
13686
13687    pub fn move_up_by_lines(
13688        &mut self,
13689        action: &MoveUpByLines,
13690        window: &mut Window,
13691        cx: &mut Context<Self>,
13692    ) {
13693        if self.take_rename(true, window, cx).is_some() {
13694            return;
13695        }
13696
13697        if self.mode.is_single_line() {
13698            cx.propagate();
13699            return;
13700        }
13701
13702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13703
13704        let text_layout_details = &self.text_layout_details(window);
13705
13706        self.change_selections(Default::default(), window, cx, |s| {
13707            s.move_with(|map, selection| {
13708                if !selection.is_empty() {
13709                    selection.goal = SelectionGoal::None;
13710                }
13711                let (cursor, goal) = movement::up_by_rows(
13712                    map,
13713                    selection.start,
13714                    action.lines,
13715                    selection.goal,
13716                    false,
13717                    text_layout_details,
13718                );
13719                selection.collapse_to(cursor, goal);
13720            });
13721        })
13722    }
13723
13724    pub fn move_down_by_lines(
13725        &mut self,
13726        action: &MoveDownByLines,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        if self.take_rename(true, window, cx).is_some() {
13731            return;
13732        }
13733
13734        if self.mode.is_single_line() {
13735            cx.propagate();
13736            return;
13737        }
13738
13739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13740
13741        let text_layout_details = &self.text_layout_details(window);
13742
13743        self.change_selections(Default::default(), window, cx, |s| {
13744            s.move_with(|map, selection| {
13745                if !selection.is_empty() {
13746                    selection.goal = SelectionGoal::None;
13747                }
13748                let (cursor, goal) = movement::down_by_rows(
13749                    map,
13750                    selection.start,
13751                    action.lines,
13752                    selection.goal,
13753                    false,
13754                    text_layout_details,
13755                );
13756                selection.collapse_to(cursor, goal);
13757            });
13758        })
13759    }
13760
13761    pub fn select_down_by_lines(
13762        &mut self,
13763        action: &SelectDownByLines,
13764        window: &mut Window,
13765        cx: &mut Context<Self>,
13766    ) {
13767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13768        let text_layout_details = &self.text_layout_details(window);
13769        self.change_selections(Default::default(), window, cx, |s| {
13770            s.move_heads_with(|map, head, goal| {
13771                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13772            })
13773        })
13774    }
13775
13776    pub fn select_up_by_lines(
13777        &mut self,
13778        action: &SelectUpByLines,
13779        window: &mut Window,
13780        cx: &mut Context<Self>,
13781    ) {
13782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13783        let text_layout_details = &self.text_layout_details(window);
13784        self.change_selections(Default::default(), window, cx, |s| {
13785            s.move_heads_with(|map, head, goal| {
13786                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13787            })
13788        })
13789    }
13790
13791    pub fn select_page_up(
13792        &mut self,
13793        _: &SelectPageUp,
13794        window: &mut Window,
13795        cx: &mut Context<Self>,
13796    ) {
13797        let Some(row_count) = self.visible_row_count() else {
13798            return;
13799        };
13800
13801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13802
13803        let text_layout_details = &self.text_layout_details(window);
13804
13805        self.change_selections(Default::default(), window, cx, |s| {
13806            s.move_heads_with(|map, head, goal| {
13807                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13808            })
13809        })
13810    }
13811
13812    pub fn move_page_up(
13813        &mut self,
13814        action: &MovePageUp,
13815        window: &mut Window,
13816        cx: &mut Context<Self>,
13817    ) {
13818        if self.take_rename(true, window, cx).is_some() {
13819            return;
13820        }
13821
13822        if self
13823            .context_menu
13824            .borrow_mut()
13825            .as_mut()
13826            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13827            .unwrap_or(false)
13828        {
13829            return;
13830        }
13831
13832        if matches!(self.mode, EditorMode::SingleLine) {
13833            cx.propagate();
13834            return;
13835        }
13836
13837        let Some(row_count) = self.visible_row_count() else {
13838            return;
13839        };
13840
13841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13842
13843        let effects = if action.center_cursor {
13844            SelectionEffects::scroll(Autoscroll::center())
13845        } else {
13846            SelectionEffects::default()
13847        };
13848
13849        let text_layout_details = &self.text_layout_details(window);
13850
13851        self.change_selections(effects, window, cx, |s| {
13852            s.move_with(|map, selection| {
13853                if !selection.is_empty() {
13854                    selection.goal = SelectionGoal::None;
13855                }
13856                let (cursor, goal) = movement::up_by_rows(
13857                    map,
13858                    selection.end,
13859                    row_count,
13860                    selection.goal,
13861                    false,
13862                    text_layout_details,
13863                );
13864                selection.collapse_to(cursor, goal);
13865            });
13866        });
13867    }
13868
13869    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13870        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13871        let text_layout_details = &self.text_layout_details(window);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.move_heads_with(|map, head, goal| {
13874                movement::up(map, head, goal, false, text_layout_details)
13875            })
13876        })
13877    }
13878
13879    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13880        self.take_rename(true, window, cx);
13881
13882        if self.mode.is_single_line() {
13883            cx.propagate();
13884            return;
13885        }
13886
13887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13888
13889        let text_layout_details = &self.text_layout_details(window);
13890        let selection_count = self.selections.count();
13891        let first_selection = self.selections.first_anchor();
13892
13893        self.change_selections(Default::default(), window, cx, |s| {
13894            s.move_with(|map, selection| {
13895                if !selection.is_empty() {
13896                    selection.goal = SelectionGoal::None;
13897                }
13898                let (cursor, goal) = movement::down(
13899                    map,
13900                    selection.end,
13901                    selection.goal,
13902                    false,
13903                    text_layout_details,
13904                );
13905                selection.collapse_to(cursor, goal);
13906            });
13907        });
13908
13909        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13910        {
13911            cx.propagate();
13912        }
13913    }
13914
13915    pub fn select_page_down(
13916        &mut self,
13917        _: &SelectPageDown,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        let Some(row_count) = self.visible_row_count() else {
13922            return;
13923        };
13924
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13926
13927        let text_layout_details = &self.text_layout_details(window);
13928
13929        self.change_selections(Default::default(), window, cx, |s| {
13930            s.move_heads_with(|map, head, goal| {
13931                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13932            })
13933        })
13934    }
13935
13936    pub fn move_page_down(
13937        &mut self,
13938        action: &MovePageDown,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) {
13942        if self.take_rename(true, window, cx).is_some() {
13943            return;
13944        }
13945
13946        if self
13947            .context_menu
13948            .borrow_mut()
13949            .as_mut()
13950            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13951            .unwrap_or(false)
13952        {
13953            return;
13954        }
13955
13956        if matches!(self.mode, EditorMode::SingleLine) {
13957            cx.propagate();
13958            return;
13959        }
13960
13961        let Some(row_count) = self.visible_row_count() else {
13962            return;
13963        };
13964
13965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13966
13967        let effects = if action.center_cursor {
13968            SelectionEffects::scroll(Autoscroll::center())
13969        } else {
13970            SelectionEffects::default()
13971        };
13972
13973        let text_layout_details = &self.text_layout_details(window);
13974        self.change_selections(effects, window, cx, |s| {
13975            s.move_with(|map, selection| {
13976                if !selection.is_empty() {
13977                    selection.goal = SelectionGoal::None;
13978                }
13979                let (cursor, goal) = movement::down_by_rows(
13980                    map,
13981                    selection.end,
13982                    row_count,
13983                    selection.goal,
13984                    false,
13985                    text_layout_details,
13986                );
13987                selection.collapse_to(cursor, goal);
13988            });
13989        });
13990    }
13991
13992    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13994        let text_layout_details = &self.text_layout_details(window);
13995        self.change_selections(Default::default(), window, cx, |s| {
13996            s.move_heads_with(|map, head, goal| {
13997                movement::down(map, head, goal, false, text_layout_details)
13998            })
13999        });
14000    }
14001
14002    pub fn context_menu_first(
14003        &mut self,
14004        _: &ContextMenuFirst,
14005        window: &mut Window,
14006        cx: &mut Context<Self>,
14007    ) {
14008        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14009            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14010        }
14011    }
14012
14013    pub fn context_menu_prev(
14014        &mut self,
14015        _: &ContextMenuPrevious,
14016        window: &mut Window,
14017        cx: &mut Context<Self>,
14018    ) {
14019        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14020            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14021        }
14022    }
14023
14024    pub fn context_menu_next(
14025        &mut self,
14026        _: &ContextMenuNext,
14027        window: &mut Window,
14028        cx: &mut Context<Self>,
14029    ) {
14030        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14031            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14032        }
14033    }
14034
14035    pub fn context_menu_last(
14036        &mut self,
14037        _: &ContextMenuLast,
14038        window: &mut Window,
14039        cx: &mut Context<Self>,
14040    ) {
14041        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14042            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14043        }
14044    }
14045
14046    pub fn signature_help_prev(
14047        &mut self,
14048        _: &SignatureHelpPrevious,
14049        _: &mut Window,
14050        cx: &mut Context<Self>,
14051    ) {
14052        if let Some(popover) = self.signature_help_state.popover_mut() {
14053            if popover.current_signature == 0 {
14054                popover.current_signature = popover.signatures.len() - 1;
14055            } else {
14056                popover.current_signature -= 1;
14057            }
14058            cx.notify();
14059        }
14060    }
14061
14062    pub fn signature_help_next(
14063        &mut self,
14064        _: &SignatureHelpNext,
14065        _: &mut Window,
14066        cx: &mut Context<Self>,
14067    ) {
14068        if let Some(popover) = self.signature_help_state.popover_mut() {
14069            if popover.current_signature + 1 == popover.signatures.len() {
14070                popover.current_signature = 0;
14071            } else {
14072                popover.current_signature += 1;
14073            }
14074            cx.notify();
14075        }
14076    }
14077
14078    pub fn move_to_previous_word_start(
14079        &mut self,
14080        _: &MoveToPreviousWordStart,
14081        window: &mut Window,
14082        cx: &mut Context<Self>,
14083    ) {
14084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14085        self.change_selections(Default::default(), window, cx, |s| {
14086            s.move_cursors_with(|map, head, _| {
14087                (
14088                    movement::previous_word_start(map, head),
14089                    SelectionGoal::None,
14090                )
14091            });
14092        })
14093    }
14094
14095    pub fn move_to_previous_subword_start(
14096        &mut self,
14097        _: &MoveToPreviousSubwordStart,
14098        window: &mut Window,
14099        cx: &mut Context<Self>,
14100    ) {
14101        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14102        self.change_selections(Default::default(), window, cx, |s| {
14103            s.move_cursors_with(|map, head, _| {
14104                (
14105                    movement::previous_subword_start(map, head),
14106                    SelectionGoal::None,
14107                )
14108            });
14109        })
14110    }
14111
14112    pub fn select_to_previous_word_start(
14113        &mut self,
14114        _: &SelectToPreviousWordStart,
14115        window: &mut Window,
14116        cx: &mut Context<Self>,
14117    ) {
14118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14119        self.change_selections(Default::default(), window, cx, |s| {
14120            s.move_heads_with(|map, head, _| {
14121                (
14122                    movement::previous_word_start(map, head),
14123                    SelectionGoal::None,
14124                )
14125            });
14126        })
14127    }
14128
14129    pub fn select_to_previous_subword_start(
14130        &mut self,
14131        _: &SelectToPreviousSubwordStart,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) {
14135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14136        self.change_selections(Default::default(), window, cx, |s| {
14137            s.move_heads_with(|map, head, _| {
14138                (
14139                    movement::previous_subword_start(map, head),
14140                    SelectionGoal::None,
14141                )
14142            });
14143        })
14144    }
14145
14146    pub fn delete_to_previous_word_start(
14147        &mut self,
14148        action: &DeleteToPreviousWordStart,
14149        window: &mut Window,
14150        cx: &mut Context<Self>,
14151    ) {
14152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14153        self.transact(window, cx, |this, window, cx| {
14154            this.select_autoclose_pair(window, cx);
14155            this.change_selections(Default::default(), window, cx, |s| {
14156                s.move_with(|map, selection| {
14157                    if selection.is_empty() {
14158                        let mut cursor = if action.ignore_newlines {
14159                            movement::previous_word_start(map, selection.head())
14160                        } else {
14161                            movement::previous_word_start_or_newline(map, selection.head())
14162                        };
14163                        cursor = movement::adjust_greedy_deletion(
14164                            map,
14165                            selection.head(),
14166                            cursor,
14167                            action.ignore_brackets,
14168                        );
14169                        selection.set_head(cursor, SelectionGoal::None);
14170                    }
14171                });
14172            });
14173            this.insert("", window, cx);
14174        });
14175    }
14176
14177    pub fn delete_to_previous_subword_start(
14178        &mut self,
14179        action: &DeleteToPreviousSubwordStart,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) {
14183        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14184        self.transact(window, cx, |this, window, cx| {
14185            this.select_autoclose_pair(window, cx);
14186            this.change_selections(Default::default(), window, cx, |s| {
14187                s.move_with(|map, selection| {
14188                    if selection.is_empty() {
14189                        let mut cursor = if action.ignore_newlines {
14190                            movement::previous_subword_start(map, selection.head())
14191                        } else {
14192                            movement::previous_subword_start_or_newline(map, selection.head())
14193                        };
14194                        cursor = movement::adjust_greedy_deletion(
14195                            map,
14196                            selection.head(),
14197                            cursor,
14198                            action.ignore_brackets,
14199                        );
14200                        selection.set_head(cursor, SelectionGoal::None);
14201                    }
14202                });
14203            });
14204            this.insert("", window, cx);
14205        });
14206    }
14207
14208    pub fn move_to_next_word_end(
14209        &mut self,
14210        _: &MoveToNextWordEnd,
14211        window: &mut Window,
14212        cx: &mut Context<Self>,
14213    ) {
14214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14215        self.change_selections(Default::default(), window, cx, |s| {
14216            s.move_cursors_with(|map, head, _| {
14217                (movement::next_word_end(map, head), SelectionGoal::None)
14218            });
14219        })
14220    }
14221
14222    pub fn move_to_next_subword_end(
14223        &mut self,
14224        _: &MoveToNextSubwordEnd,
14225        window: &mut Window,
14226        cx: &mut Context<Self>,
14227    ) {
14228        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14229        self.change_selections(Default::default(), window, cx, |s| {
14230            s.move_cursors_with(|map, head, _| {
14231                (movement::next_subword_end(map, head), SelectionGoal::None)
14232            });
14233        })
14234    }
14235
14236    pub fn select_to_next_word_end(
14237        &mut self,
14238        _: &SelectToNextWordEnd,
14239        window: &mut Window,
14240        cx: &mut Context<Self>,
14241    ) {
14242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14243        self.change_selections(Default::default(), window, cx, |s| {
14244            s.move_heads_with(|map, head, _| {
14245                (movement::next_word_end(map, head), SelectionGoal::None)
14246            });
14247        })
14248    }
14249
14250    pub fn select_to_next_subword_end(
14251        &mut self,
14252        _: &SelectToNextSubwordEnd,
14253        window: &mut Window,
14254        cx: &mut Context<Self>,
14255    ) {
14256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14257        self.change_selections(Default::default(), window, cx, |s| {
14258            s.move_heads_with(|map, head, _| {
14259                (movement::next_subword_end(map, head), SelectionGoal::None)
14260            });
14261        })
14262    }
14263
14264    pub fn delete_to_next_word_end(
14265        &mut self,
14266        action: &DeleteToNextWordEnd,
14267        window: &mut Window,
14268        cx: &mut Context<Self>,
14269    ) {
14270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14271        self.transact(window, cx, |this, window, cx| {
14272            this.change_selections(Default::default(), window, cx, |s| {
14273                s.move_with(|map, selection| {
14274                    if selection.is_empty() {
14275                        let mut cursor = if action.ignore_newlines {
14276                            movement::next_word_end(map, selection.head())
14277                        } else {
14278                            movement::next_word_end_or_newline(map, selection.head())
14279                        };
14280                        cursor = movement::adjust_greedy_deletion(
14281                            map,
14282                            selection.head(),
14283                            cursor,
14284                            action.ignore_brackets,
14285                        );
14286                        selection.set_head(cursor, SelectionGoal::None);
14287                    }
14288                });
14289            });
14290            this.insert("", window, cx);
14291        });
14292    }
14293
14294    pub fn delete_to_next_subword_end(
14295        &mut self,
14296        action: &DeleteToNextSubwordEnd,
14297        window: &mut Window,
14298        cx: &mut Context<Self>,
14299    ) {
14300        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14301        self.transact(window, cx, |this, window, cx| {
14302            this.change_selections(Default::default(), window, cx, |s| {
14303                s.move_with(|map, selection| {
14304                    if selection.is_empty() {
14305                        let mut cursor = if action.ignore_newlines {
14306                            movement::next_subword_end(map, selection.head())
14307                        } else {
14308                            movement::next_subword_end_or_newline(map, selection.head())
14309                        };
14310                        cursor = movement::adjust_greedy_deletion(
14311                            map,
14312                            selection.head(),
14313                            cursor,
14314                            action.ignore_brackets,
14315                        );
14316                        selection.set_head(cursor, SelectionGoal::None);
14317                    }
14318                });
14319            });
14320            this.insert("", window, cx);
14321        });
14322    }
14323
14324    pub fn move_to_beginning_of_line(
14325        &mut self,
14326        action: &MoveToBeginningOfLine,
14327        window: &mut Window,
14328        cx: &mut Context<Self>,
14329    ) {
14330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14331        self.change_selections(Default::default(), window, cx, |s| {
14332            s.move_cursors_with(|map, head, _| {
14333                (
14334                    movement::indented_line_beginning(
14335                        map,
14336                        head,
14337                        action.stop_at_soft_wraps,
14338                        action.stop_at_indent,
14339                    ),
14340                    SelectionGoal::None,
14341                )
14342            });
14343        })
14344    }
14345
14346    pub fn select_to_beginning_of_line(
14347        &mut self,
14348        action: &SelectToBeginningOfLine,
14349        window: &mut Window,
14350        cx: &mut Context<Self>,
14351    ) {
14352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14353        self.change_selections(Default::default(), window, cx, |s| {
14354            s.move_heads_with(|map, head, _| {
14355                (
14356                    movement::indented_line_beginning(
14357                        map,
14358                        head,
14359                        action.stop_at_soft_wraps,
14360                        action.stop_at_indent,
14361                    ),
14362                    SelectionGoal::None,
14363                )
14364            });
14365        });
14366    }
14367
14368    pub fn delete_to_beginning_of_line(
14369        &mut self,
14370        action: &DeleteToBeginningOfLine,
14371        window: &mut Window,
14372        cx: &mut Context<Self>,
14373    ) {
14374        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14375        self.transact(window, cx, |this, window, cx| {
14376            this.change_selections(Default::default(), window, cx, |s| {
14377                s.move_with(|_, selection| {
14378                    selection.reversed = true;
14379                });
14380            });
14381
14382            this.select_to_beginning_of_line(
14383                &SelectToBeginningOfLine {
14384                    stop_at_soft_wraps: false,
14385                    stop_at_indent: action.stop_at_indent,
14386                },
14387                window,
14388                cx,
14389            );
14390            this.backspace(&Backspace, window, cx);
14391        });
14392    }
14393
14394    pub fn move_to_end_of_line(
14395        &mut self,
14396        action: &MoveToEndOfLine,
14397        window: &mut Window,
14398        cx: &mut Context<Self>,
14399    ) {
14400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14401        self.change_selections(Default::default(), window, cx, |s| {
14402            s.move_cursors_with(|map, head, _| {
14403                (
14404                    movement::line_end(map, head, action.stop_at_soft_wraps),
14405                    SelectionGoal::None,
14406                )
14407            });
14408        })
14409    }
14410
14411    pub fn select_to_end_of_line(
14412        &mut self,
14413        action: &SelectToEndOfLine,
14414        window: &mut Window,
14415        cx: &mut Context<Self>,
14416    ) {
14417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14418        self.change_selections(Default::default(), window, cx, |s| {
14419            s.move_heads_with(|map, head, _| {
14420                (
14421                    movement::line_end(map, head, action.stop_at_soft_wraps),
14422                    SelectionGoal::None,
14423                )
14424            });
14425        })
14426    }
14427
14428    pub fn delete_to_end_of_line(
14429        &mut self,
14430        _: &DeleteToEndOfLine,
14431        window: &mut Window,
14432        cx: &mut Context<Self>,
14433    ) {
14434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14435        self.transact(window, cx, |this, window, cx| {
14436            this.select_to_end_of_line(
14437                &SelectToEndOfLine {
14438                    stop_at_soft_wraps: false,
14439                },
14440                window,
14441                cx,
14442            );
14443            this.delete(&Delete, window, cx);
14444        });
14445    }
14446
14447    pub fn cut_to_end_of_line(
14448        &mut self,
14449        action: &CutToEndOfLine,
14450        window: &mut Window,
14451        cx: &mut Context<Self>,
14452    ) {
14453        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14454        self.transact(window, cx, |this, window, cx| {
14455            this.select_to_end_of_line(
14456                &SelectToEndOfLine {
14457                    stop_at_soft_wraps: false,
14458                },
14459                window,
14460                cx,
14461            );
14462            if !action.stop_at_newlines {
14463                this.change_selections(Default::default(), window, cx, |s| {
14464                    s.move_with(|_, sel| {
14465                        if sel.is_empty() {
14466                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14467                        }
14468                    });
14469                });
14470            }
14471            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14472            let item = this.cut_common(false, window, cx);
14473            cx.write_to_clipboard(item);
14474        });
14475    }
14476
14477    pub fn move_to_start_of_paragraph(
14478        &mut self,
14479        _: &MoveToStartOfParagraph,
14480        window: &mut Window,
14481        cx: &mut Context<Self>,
14482    ) {
14483        if matches!(self.mode, EditorMode::SingleLine) {
14484            cx.propagate();
14485            return;
14486        }
14487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14488        self.change_selections(Default::default(), window, cx, |s| {
14489            s.move_with(|map, selection| {
14490                selection.collapse_to(
14491                    movement::start_of_paragraph(map, selection.head(), 1),
14492                    SelectionGoal::None,
14493                )
14494            });
14495        })
14496    }
14497
14498    pub fn move_to_end_of_paragraph(
14499        &mut self,
14500        _: &MoveToEndOfParagraph,
14501        window: &mut Window,
14502        cx: &mut Context<Self>,
14503    ) {
14504        if matches!(self.mode, EditorMode::SingleLine) {
14505            cx.propagate();
14506            return;
14507        }
14508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14509        self.change_selections(Default::default(), window, cx, |s| {
14510            s.move_with(|map, selection| {
14511                selection.collapse_to(
14512                    movement::end_of_paragraph(map, selection.head(), 1),
14513                    SelectionGoal::None,
14514                )
14515            });
14516        })
14517    }
14518
14519    pub fn select_to_start_of_paragraph(
14520        &mut self,
14521        _: &SelectToStartOfParagraph,
14522        window: &mut Window,
14523        cx: &mut Context<Self>,
14524    ) {
14525        if matches!(self.mode, EditorMode::SingleLine) {
14526            cx.propagate();
14527            return;
14528        }
14529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14530        self.change_selections(Default::default(), window, cx, |s| {
14531            s.move_heads_with(|map, head, _| {
14532                (
14533                    movement::start_of_paragraph(map, head, 1),
14534                    SelectionGoal::None,
14535                )
14536            });
14537        })
14538    }
14539
14540    pub fn select_to_end_of_paragraph(
14541        &mut self,
14542        _: &SelectToEndOfParagraph,
14543        window: &mut Window,
14544        cx: &mut Context<Self>,
14545    ) {
14546        if matches!(self.mode, EditorMode::SingleLine) {
14547            cx.propagate();
14548            return;
14549        }
14550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14551        self.change_selections(Default::default(), window, cx, |s| {
14552            s.move_heads_with(|map, head, _| {
14553                (
14554                    movement::end_of_paragraph(map, head, 1),
14555                    SelectionGoal::None,
14556                )
14557            });
14558        })
14559    }
14560
14561    pub fn move_to_start_of_excerpt(
14562        &mut self,
14563        _: &MoveToStartOfExcerpt,
14564        window: &mut Window,
14565        cx: &mut Context<Self>,
14566    ) {
14567        if matches!(self.mode, EditorMode::SingleLine) {
14568            cx.propagate();
14569            return;
14570        }
14571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14572        self.change_selections(Default::default(), window, cx, |s| {
14573            s.move_with(|map, selection| {
14574                selection.collapse_to(
14575                    movement::start_of_excerpt(
14576                        map,
14577                        selection.head(),
14578                        workspace::searchable::Direction::Prev,
14579                    ),
14580                    SelectionGoal::None,
14581                )
14582            });
14583        })
14584    }
14585
14586    pub fn move_to_start_of_next_excerpt(
14587        &mut self,
14588        _: &MoveToStartOfNextExcerpt,
14589        window: &mut Window,
14590        cx: &mut Context<Self>,
14591    ) {
14592        if matches!(self.mode, EditorMode::SingleLine) {
14593            cx.propagate();
14594            return;
14595        }
14596
14597        self.change_selections(Default::default(), window, cx, |s| {
14598            s.move_with(|map, selection| {
14599                selection.collapse_to(
14600                    movement::start_of_excerpt(
14601                        map,
14602                        selection.head(),
14603                        workspace::searchable::Direction::Next,
14604                    ),
14605                    SelectionGoal::None,
14606                )
14607            });
14608        })
14609    }
14610
14611    pub fn move_to_end_of_excerpt(
14612        &mut self,
14613        _: &MoveToEndOfExcerpt,
14614        window: &mut Window,
14615        cx: &mut Context<Self>,
14616    ) {
14617        if matches!(self.mode, EditorMode::SingleLine) {
14618            cx.propagate();
14619            return;
14620        }
14621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14622        self.change_selections(Default::default(), window, cx, |s| {
14623            s.move_with(|map, selection| {
14624                selection.collapse_to(
14625                    movement::end_of_excerpt(
14626                        map,
14627                        selection.head(),
14628                        workspace::searchable::Direction::Next,
14629                    ),
14630                    SelectionGoal::None,
14631                )
14632            });
14633        })
14634    }
14635
14636    pub fn move_to_end_of_previous_excerpt(
14637        &mut self,
14638        _: &MoveToEndOfPreviousExcerpt,
14639        window: &mut Window,
14640        cx: &mut Context<Self>,
14641    ) {
14642        if matches!(self.mode, EditorMode::SingleLine) {
14643            cx.propagate();
14644            return;
14645        }
14646        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14647        self.change_selections(Default::default(), window, cx, |s| {
14648            s.move_with(|map, selection| {
14649                selection.collapse_to(
14650                    movement::end_of_excerpt(
14651                        map,
14652                        selection.head(),
14653                        workspace::searchable::Direction::Prev,
14654                    ),
14655                    SelectionGoal::None,
14656                )
14657            });
14658        })
14659    }
14660
14661    pub fn select_to_start_of_excerpt(
14662        &mut self,
14663        _: &SelectToStartOfExcerpt,
14664        window: &mut Window,
14665        cx: &mut Context<Self>,
14666    ) {
14667        if matches!(self.mode, EditorMode::SingleLine) {
14668            cx.propagate();
14669            return;
14670        }
14671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14672        self.change_selections(Default::default(), window, cx, |s| {
14673            s.move_heads_with(|map, head, _| {
14674                (
14675                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14676                    SelectionGoal::None,
14677                )
14678            });
14679        })
14680    }
14681
14682    pub fn select_to_start_of_next_excerpt(
14683        &mut self,
14684        _: &SelectToStartOfNextExcerpt,
14685        window: &mut Window,
14686        cx: &mut Context<Self>,
14687    ) {
14688        if matches!(self.mode, EditorMode::SingleLine) {
14689            cx.propagate();
14690            return;
14691        }
14692        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14693        self.change_selections(Default::default(), window, cx, |s| {
14694            s.move_heads_with(|map, head, _| {
14695                (
14696                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14697                    SelectionGoal::None,
14698                )
14699            });
14700        })
14701    }
14702
14703    pub fn select_to_end_of_excerpt(
14704        &mut self,
14705        _: &SelectToEndOfExcerpt,
14706        window: &mut Window,
14707        cx: &mut Context<Self>,
14708    ) {
14709        if matches!(self.mode, EditorMode::SingleLine) {
14710            cx.propagate();
14711            return;
14712        }
14713        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14714        self.change_selections(Default::default(), window, cx, |s| {
14715            s.move_heads_with(|map, head, _| {
14716                (
14717                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14718                    SelectionGoal::None,
14719                )
14720            });
14721        })
14722    }
14723
14724    pub fn select_to_end_of_previous_excerpt(
14725        &mut self,
14726        _: &SelectToEndOfPreviousExcerpt,
14727        window: &mut Window,
14728        cx: &mut Context<Self>,
14729    ) {
14730        if matches!(self.mode, EditorMode::SingleLine) {
14731            cx.propagate();
14732            return;
14733        }
14734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14735        self.change_selections(Default::default(), window, cx, |s| {
14736            s.move_heads_with(|map, head, _| {
14737                (
14738                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14739                    SelectionGoal::None,
14740                )
14741            });
14742        })
14743    }
14744
14745    pub fn move_to_beginning(
14746        &mut self,
14747        _: &MoveToBeginning,
14748        window: &mut Window,
14749        cx: &mut Context<Self>,
14750    ) {
14751        if matches!(self.mode, EditorMode::SingleLine) {
14752            cx.propagate();
14753            return;
14754        }
14755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14756        self.change_selections(Default::default(), window, cx, |s| {
14757            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14758        });
14759    }
14760
14761    pub fn select_to_beginning(
14762        &mut self,
14763        _: &SelectToBeginning,
14764        window: &mut Window,
14765        cx: &mut Context<Self>,
14766    ) {
14767        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14768        selection.set_head(Point::zero(), SelectionGoal::None);
14769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14770        self.change_selections(Default::default(), window, cx, |s| {
14771            s.select(vec![selection]);
14772        });
14773    }
14774
14775    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14776        if matches!(self.mode, EditorMode::SingleLine) {
14777            cx.propagate();
14778            return;
14779        }
14780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14781        let cursor = self.buffer.read(cx).read(cx).len();
14782        self.change_selections(Default::default(), window, cx, |s| {
14783            s.select_ranges(vec![cursor..cursor])
14784        });
14785    }
14786
14787    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14788        self.nav_history = nav_history;
14789    }
14790
14791    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14792        self.nav_history.as_ref()
14793    }
14794
14795    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14796        self.push_to_nav_history(
14797            self.selections.newest_anchor().head(),
14798            None,
14799            false,
14800            true,
14801            cx,
14802        );
14803    }
14804
14805    fn push_to_nav_history(
14806        &mut self,
14807        cursor_anchor: Anchor,
14808        new_position: Option<Point>,
14809        is_deactivate: bool,
14810        always: bool,
14811        cx: &mut Context<Self>,
14812    ) {
14813        if let Some(nav_history) = self.nav_history.as_mut() {
14814            let buffer = self.buffer.read(cx).read(cx);
14815            let cursor_position = cursor_anchor.to_point(&buffer);
14816            let scroll_state = self.scroll_manager.anchor();
14817            let scroll_top_row = scroll_state.top_row(&buffer);
14818            drop(buffer);
14819
14820            if let Some(new_position) = new_position {
14821                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14822                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14823                    return;
14824                }
14825            }
14826
14827            nav_history.push(
14828                Some(NavigationData {
14829                    cursor_anchor,
14830                    cursor_position,
14831                    scroll_anchor: scroll_state,
14832                    scroll_top_row,
14833                }),
14834                cx,
14835            );
14836            cx.emit(EditorEvent::PushedToNavHistory {
14837                anchor: cursor_anchor,
14838                is_deactivate,
14839            })
14840        }
14841    }
14842
14843    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14845        let buffer = self.buffer.read(cx).snapshot(cx);
14846        let mut selection = self
14847            .selections
14848            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14849        selection.set_head(buffer.len(), SelectionGoal::None);
14850        self.change_selections(Default::default(), window, cx, |s| {
14851            s.select(vec![selection]);
14852        });
14853    }
14854
14855    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14857        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14858            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14859        });
14860    }
14861
14862    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14863        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14864        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14865        let mut selections = self.selections.all::<Point>(&display_map);
14866        let max_point = display_map.buffer_snapshot().max_point();
14867        for selection in &mut selections {
14868            let rows = selection.spanned_rows(true, &display_map);
14869            selection.start = Point::new(rows.start.0, 0);
14870            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14871            selection.reversed = false;
14872        }
14873        self.change_selections(Default::default(), window, cx, |s| {
14874            s.select(selections);
14875        });
14876    }
14877
14878    pub fn split_selection_into_lines(
14879        &mut self,
14880        action: &SplitSelectionIntoLines,
14881        window: &mut Window,
14882        cx: &mut Context<Self>,
14883    ) {
14884        let selections = self
14885            .selections
14886            .all::<Point>(&self.display_snapshot(cx))
14887            .into_iter()
14888            .map(|selection| selection.start..selection.end)
14889            .collect::<Vec<_>>();
14890        self.unfold_ranges(&selections, true, true, cx);
14891
14892        let mut new_selection_ranges = Vec::new();
14893        {
14894            let buffer = self.buffer.read(cx).read(cx);
14895            for selection in selections {
14896                for row in selection.start.row..selection.end.row {
14897                    let line_start = Point::new(row, 0);
14898                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14899
14900                    if action.keep_selections {
14901                        // Keep the selection range for each line
14902                        let selection_start = if row == selection.start.row {
14903                            selection.start
14904                        } else {
14905                            line_start
14906                        };
14907                        new_selection_ranges.push(selection_start..line_end);
14908                    } else {
14909                        // Collapse to cursor at end of line
14910                        new_selection_ranges.push(line_end..line_end);
14911                    }
14912                }
14913
14914                let is_multiline_selection = selection.start.row != selection.end.row;
14915                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14916                // so this action feels more ergonomic when paired with other selection operations
14917                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14918                if !should_skip_last {
14919                    if action.keep_selections {
14920                        if is_multiline_selection {
14921                            let line_start = Point::new(selection.end.row, 0);
14922                            new_selection_ranges.push(line_start..selection.end);
14923                        } else {
14924                            new_selection_ranges.push(selection.start..selection.end);
14925                        }
14926                    } else {
14927                        new_selection_ranges.push(selection.end..selection.end);
14928                    }
14929                }
14930            }
14931        }
14932        self.change_selections(Default::default(), window, cx, |s| {
14933            s.select_ranges(new_selection_ranges);
14934        });
14935    }
14936
14937    pub fn add_selection_above(
14938        &mut self,
14939        action: &AddSelectionAbove,
14940        window: &mut Window,
14941        cx: &mut Context<Self>,
14942    ) {
14943        self.add_selection(true, action.skip_soft_wrap, window, cx);
14944    }
14945
14946    pub fn add_selection_below(
14947        &mut self,
14948        action: &AddSelectionBelow,
14949        window: &mut Window,
14950        cx: &mut Context<Self>,
14951    ) {
14952        self.add_selection(false, action.skip_soft_wrap, window, cx);
14953    }
14954
14955    fn add_selection(
14956        &mut self,
14957        above: bool,
14958        skip_soft_wrap: bool,
14959        window: &mut Window,
14960        cx: &mut Context<Self>,
14961    ) {
14962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14963
14964        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14965        let all_selections = self.selections.all::<Point>(&display_map);
14966        let text_layout_details = self.text_layout_details(window);
14967
14968        let (mut columnar_selections, new_selections_to_columnarize) = {
14969            if let Some(state) = self.add_selections_state.as_ref() {
14970                let columnar_selection_ids: HashSet<_> = state
14971                    .groups
14972                    .iter()
14973                    .flat_map(|group| group.stack.iter())
14974                    .copied()
14975                    .collect();
14976
14977                all_selections
14978                    .into_iter()
14979                    .partition(|s| columnar_selection_ids.contains(&s.id))
14980            } else {
14981                (Vec::new(), all_selections)
14982            }
14983        };
14984
14985        let mut state = self
14986            .add_selections_state
14987            .take()
14988            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14989
14990        for selection in new_selections_to_columnarize {
14991            let range = selection.display_range(&display_map).sorted();
14992            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14993            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14994            let positions = start_x.min(end_x)..start_x.max(end_x);
14995            let mut stack = Vec::new();
14996            for row in range.start.row().0..=range.end.row().0 {
14997                if let Some(selection) = self.selections.build_columnar_selection(
14998                    &display_map,
14999                    DisplayRow(row),
15000                    &positions,
15001                    selection.reversed,
15002                    &text_layout_details,
15003                ) {
15004                    stack.push(selection.id);
15005                    columnar_selections.push(selection);
15006                }
15007            }
15008            if !stack.is_empty() {
15009                if above {
15010                    stack.reverse();
15011                }
15012                state.groups.push(AddSelectionsGroup { above, stack });
15013            }
15014        }
15015
15016        let mut final_selections = Vec::new();
15017        let end_row = if above {
15018            DisplayRow(0)
15019        } else {
15020            display_map.max_point().row()
15021        };
15022
15023        let mut last_added_item_per_group = HashMap::default();
15024        for group in state.groups.iter_mut() {
15025            if let Some(last_id) = group.stack.last() {
15026                last_added_item_per_group.insert(*last_id, group);
15027            }
15028        }
15029
15030        for selection in columnar_selections {
15031            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15032                if above == group.above {
15033                    let range = selection.display_range(&display_map).sorted();
15034                    debug_assert_eq!(range.start.row(), range.end.row());
15035                    let mut row = range.start.row();
15036                    let positions =
15037                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15038                            Pixels::from(start)..Pixels::from(end)
15039                        } else {
15040                            let start_x =
15041                                display_map.x_for_display_point(range.start, &text_layout_details);
15042                            let end_x =
15043                                display_map.x_for_display_point(range.end, &text_layout_details);
15044                            start_x.min(end_x)..start_x.max(end_x)
15045                        };
15046
15047                    let mut maybe_new_selection = None;
15048                    let direction = if above { -1 } else { 1 };
15049
15050                    while row != end_row {
15051                        let new_buffer_row = if skip_soft_wrap {
15052                            let new_row = display_map
15053                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction);
15054                            row = new_row.row();
15055                            Some(new_row.to_point(&display_map).row)
15056                        } else {
15057                            if above {
15058                                row.0 -= 1;
15059                            } else {
15060                                row.0 += 1;
15061                            }
15062                            None
15063                        };
15064
15065                        let new_selection = if let Some(buffer_row) = new_buffer_row {
15066                            let start_col = selection.start.column;
15067                            let end_col = selection.end.column;
15068                            let buffer_columns = start_col.min(end_col)..start_col.max(end_col);
15069
15070                            self.selections
15071                                .build_columnar_selection_from_buffer_columns(
15072                                    &display_map,
15073                                    buffer_row,
15074                                    &buffer_columns,
15075                                    selection.reversed,
15076                                    &text_layout_details,
15077                                )
15078                        } else {
15079                            self.selections.build_columnar_selection(
15080                                &display_map,
15081                                row,
15082                                &positions,
15083                                selection.reversed,
15084                                &text_layout_details,
15085                            )
15086                        };
15087
15088                        if let Some(new_selection) = new_selection {
15089                            maybe_new_selection = Some(new_selection);
15090                            break;
15091                        }
15092                    }
15093
15094                    if let Some(new_selection) = maybe_new_selection {
15095                        group.stack.push(new_selection.id);
15096                        if above {
15097                            final_selections.push(new_selection);
15098                            final_selections.push(selection);
15099                        } else {
15100                            final_selections.push(selection);
15101                            final_selections.push(new_selection);
15102                        }
15103                    } else {
15104                        final_selections.push(selection);
15105                    }
15106                } else {
15107                    group.stack.pop();
15108                }
15109            } else {
15110                final_selections.push(selection);
15111            }
15112        }
15113
15114        self.change_selections(Default::default(), window, cx, |s| {
15115            s.select(final_selections);
15116        });
15117
15118        let final_selection_ids: HashSet<_> = self
15119            .selections
15120            .all::<Point>(&display_map)
15121            .iter()
15122            .map(|s| s.id)
15123            .collect();
15124        state.groups.retain_mut(|group| {
15125            // selections might get merged above so we remove invalid items from stacks
15126            group.stack.retain(|id| final_selection_ids.contains(id));
15127
15128            // single selection in stack can be treated as initial state
15129            group.stack.len() > 1
15130        });
15131
15132        if !state.groups.is_empty() {
15133            self.add_selections_state = Some(state);
15134        }
15135    }
15136
15137    pub fn insert_snippet_at_selections(
15138        &mut self,
15139        action: &InsertSnippet,
15140        window: &mut Window,
15141        cx: &mut Context<Self>,
15142    ) {
15143        self.try_insert_snippet_at_selections(action, window, cx)
15144            .log_err();
15145    }
15146
15147    fn try_insert_snippet_at_selections(
15148        &mut self,
15149        action: &InsertSnippet,
15150        window: &mut Window,
15151        cx: &mut Context<Self>,
15152    ) -> Result<()> {
15153        let insertion_ranges = self
15154            .selections
15155            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15156            .into_iter()
15157            .map(|selection| selection.range())
15158            .collect_vec();
15159
15160        let snippet = if let Some(snippet_body) = &action.snippet {
15161            if action.language.is_none() && action.name.is_none() {
15162                Snippet::parse(snippet_body)?
15163            } else {
15164                bail!("`snippet` is mutually exclusive with `language` and `name`")
15165            }
15166        } else if let Some(name) = &action.name {
15167            let project = self.project().context("no project")?;
15168            let snippet_store = project.read(cx).snippets().read(cx);
15169            let snippet = snippet_store
15170                .snippets_for(action.language.clone(), cx)
15171                .into_iter()
15172                .find(|snippet| snippet.name == *name)
15173                .context("snippet not found")?;
15174            Snippet::parse(&snippet.body)?
15175        } else {
15176            // todo(andrew): open modal to select snippet
15177            bail!("`name` or `snippet` is required")
15178        };
15179
15180        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15181    }
15182
15183    fn select_match_ranges(
15184        &mut self,
15185        range: Range<MultiBufferOffset>,
15186        reversed: bool,
15187        replace_newest: bool,
15188        auto_scroll: Option<Autoscroll>,
15189        window: &mut Window,
15190        cx: &mut Context<Editor>,
15191    ) {
15192        self.unfold_ranges(
15193            std::slice::from_ref(&range),
15194            false,
15195            auto_scroll.is_some(),
15196            cx,
15197        );
15198        let effects = if let Some(scroll) = auto_scroll {
15199            SelectionEffects::scroll(scroll)
15200        } else {
15201            SelectionEffects::no_scroll()
15202        };
15203        self.change_selections(effects, window, cx, |s| {
15204            if replace_newest {
15205                s.delete(s.newest_anchor().id);
15206            }
15207            if reversed {
15208                s.insert_range(range.end..range.start);
15209            } else {
15210                s.insert_range(range);
15211            }
15212        });
15213    }
15214
15215    pub fn select_next_match_internal(
15216        &mut self,
15217        display_map: &DisplaySnapshot,
15218        replace_newest: bool,
15219        autoscroll: Option<Autoscroll>,
15220        window: &mut Window,
15221        cx: &mut Context<Self>,
15222    ) -> Result<()> {
15223        let buffer = display_map.buffer_snapshot();
15224        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15225        if let Some(mut select_next_state) = self.select_next_state.take() {
15226            let query = &select_next_state.query;
15227            if !select_next_state.done {
15228                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15229                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15230                let mut next_selected_range = None;
15231
15232                let bytes_after_last_selection =
15233                    buffer.bytes_in_range(last_selection.end..buffer.len());
15234                let bytes_before_first_selection =
15235                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15236                let query_matches = query
15237                    .stream_find_iter(bytes_after_last_selection)
15238                    .map(|result| (last_selection.end, result))
15239                    .chain(
15240                        query
15241                            .stream_find_iter(bytes_before_first_selection)
15242                            .map(|result| (MultiBufferOffset(0), result)),
15243                    );
15244
15245                for (start_offset, query_match) in query_matches {
15246                    let query_match = query_match.unwrap(); // can only fail due to I/O
15247                    let offset_range =
15248                        start_offset + query_match.start()..start_offset + query_match.end();
15249
15250                    if !select_next_state.wordwise
15251                        || (!buffer.is_inside_word(offset_range.start, None)
15252                            && !buffer.is_inside_word(offset_range.end, None))
15253                    {
15254                        let idx = selections
15255                            .partition_point(|selection| selection.end <= offset_range.start);
15256                        let overlaps = selections
15257                            .get(idx)
15258                            .map_or(false, |selection| selection.start < offset_range.end);
15259
15260                        if !overlaps {
15261                            next_selected_range = Some(offset_range);
15262                            break;
15263                        }
15264                    }
15265                }
15266
15267                if let Some(next_selected_range) = next_selected_range {
15268                    self.select_match_ranges(
15269                        next_selected_range,
15270                        last_selection.reversed,
15271                        replace_newest,
15272                        autoscroll,
15273                        window,
15274                        cx,
15275                    );
15276                } else {
15277                    select_next_state.done = true;
15278                }
15279            }
15280
15281            self.select_next_state = Some(select_next_state);
15282        } else {
15283            let mut only_carets = true;
15284            let mut same_text_selected = true;
15285            let mut selected_text = None;
15286
15287            let mut selections_iter = selections.iter().peekable();
15288            while let Some(selection) = selections_iter.next() {
15289                if selection.start != selection.end {
15290                    only_carets = false;
15291                }
15292
15293                if same_text_selected {
15294                    if selected_text.is_none() {
15295                        selected_text =
15296                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15297                    }
15298
15299                    if let Some(next_selection) = selections_iter.peek() {
15300                        if next_selection.len() == selection.len() {
15301                            let next_selected_text = buffer
15302                                .text_for_range(next_selection.range())
15303                                .collect::<String>();
15304                            if Some(next_selected_text) != selected_text {
15305                                same_text_selected = false;
15306                                selected_text = None;
15307                            }
15308                        } else {
15309                            same_text_selected = false;
15310                            selected_text = None;
15311                        }
15312                    }
15313                }
15314            }
15315
15316            if only_carets {
15317                for selection in &mut selections {
15318                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15319                    selection.start = word_range.start;
15320                    selection.end = word_range.end;
15321                    selection.goal = SelectionGoal::None;
15322                    selection.reversed = false;
15323                    self.select_match_ranges(
15324                        selection.start..selection.end,
15325                        selection.reversed,
15326                        replace_newest,
15327                        autoscroll,
15328                        window,
15329                        cx,
15330                    );
15331                }
15332
15333                if selections.len() == 1 {
15334                    let selection = selections
15335                        .last()
15336                        .expect("ensured that there's only one selection");
15337                    let query = buffer
15338                        .text_for_range(selection.start..selection.end)
15339                        .collect::<String>();
15340                    let is_empty = query.is_empty();
15341                    let select_state = SelectNextState {
15342                        query: self.build_query(&[query], cx)?,
15343                        wordwise: true,
15344                        done: is_empty,
15345                    };
15346                    self.select_next_state = Some(select_state);
15347                } else {
15348                    self.select_next_state = None;
15349                }
15350            } else if let Some(selected_text) = selected_text {
15351                self.select_next_state = Some(SelectNextState {
15352                    query: self.build_query(&[selected_text], cx)?,
15353                    wordwise: false,
15354                    done: false,
15355                });
15356                self.select_next_match_internal(
15357                    display_map,
15358                    replace_newest,
15359                    autoscroll,
15360                    window,
15361                    cx,
15362                )?;
15363            }
15364        }
15365        Ok(())
15366    }
15367
15368    pub fn select_all_matches(
15369        &mut self,
15370        _action: &SelectAllMatches,
15371        window: &mut Window,
15372        cx: &mut Context<Self>,
15373    ) -> Result<()> {
15374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15375
15376        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15377
15378        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15379        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15380        else {
15381            return Ok(());
15382        };
15383
15384        let mut new_selections = Vec::new();
15385
15386        let reversed = self
15387            .selections
15388            .oldest::<MultiBufferOffset>(&display_map)
15389            .reversed;
15390        let buffer = display_map.buffer_snapshot();
15391        let query_matches = select_next_state
15392            .query
15393            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15394
15395        for query_match in query_matches.into_iter() {
15396            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15397            let offset_range = if reversed {
15398                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15399            } else {
15400                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15401            };
15402
15403            if !select_next_state.wordwise
15404                || (!buffer.is_inside_word(offset_range.start, None)
15405                    && !buffer.is_inside_word(offset_range.end, None))
15406            {
15407                new_selections.push(offset_range.start..offset_range.end);
15408            }
15409        }
15410
15411        select_next_state.done = true;
15412
15413        if new_selections.is_empty() {
15414            log::error!("bug: new_selections is empty in select_all_matches");
15415            return Ok(());
15416        }
15417
15418        self.unfold_ranges(&new_selections, false, false, cx);
15419        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15420            selections.select_ranges(new_selections)
15421        });
15422
15423        Ok(())
15424    }
15425
15426    pub fn select_next(
15427        &mut self,
15428        action: &SelectNext,
15429        window: &mut Window,
15430        cx: &mut Context<Self>,
15431    ) -> Result<()> {
15432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15433        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15434        self.select_next_match_internal(
15435            &display_map,
15436            action.replace_newest,
15437            Some(Autoscroll::newest()),
15438            window,
15439            cx,
15440        )
15441    }
15442
15443    pub fn select_previous(
15444        &mut self,
15445        action: &SelectPrevious,
15446        window: &mut Window,
15447        cx: &mut Context<Self>,
15448    ) -> Result<()> {
15449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15451        let buffer = display_map.buffer_snapshot();
15452        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15453        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15454            let query = &select_prev_state.query;
15455            if !select_prev_state.done {
15456                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15457                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15458                let mut next_selected_range = None;
15459                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15460                let bytes_before_last_selection =
15461                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15462                let bytes_after_first_selection =
15463                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15464                let query_matches = query
15465                    .stream_find_iter(bytes_before_last_selection)
15466                    .map(|result| (last_selection.start, result))
15467                    .chain(
15468                        query
15469                            .stream_find_iter(bytes_after_first_selection)
15470                            .map(|result| (buffer.len(), result)),
15471                    );
15472                for (end_offset, query_match) in query_matches {
15473                    let query_match = query_match.unwrap(); // can only fail due to I/O
15474                    let offset_range =
15475                        end_offset - query_match.end()..end_offset - query_match.start();
15476
15477                    if !select_prev_state.wordwise
15478                        || (!buffer.is_inside_word(offset_range.start, None)
15479                            && !buffer.is_inside_word(offset_range.end, None))
15480                    {
15481                        next_selected_range = Some(offset_range);
15482                        break;
15483                    }
15484                }
15485
15486                if let Some(next_selected_range) = next_selected_range {
15487                    self.select_match_ranges(
15488                        next_selected_range,
15489                        last_selection.reversed,
15490                        action.replace_newest,
15491                        Some(Autoscroll::newest()),
15492                        window,
15493                        cx,
15494                    );
15495                } else {
15496                    select_prev_state.done = true;
15497                }
15498            }
15499
15500            self.select_prev_state = Some(select_prev_state);
15501        } else {
15502            let mut only_carets = true;
15503            let mut same_text_selected = true;
15504            let mut selected_text = None;
15505
15506            let mut selections_iter = selections.iter().peekable();
15507            while let Some(selection) = selections_iter.next() {
15508                if selection.start != selection.end {
15509                    only_carets = false;
15510                }
15511
15512                if same_text_selected {
15513                    if selected_text.is_none() {
15514                        selected_text =
15515                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15516                    }
15517
15518                    if let Some(next_selection) = selections_iter.peek() {
15519                        if next_selection.len() == selection.len() {
15520                            let next_selected_text = buffer
15521                                .text_for_range(next_selection.range())
15522                                .collect::<String>();
15523                            if Some(next_selected_text) != selected_text {
15524                                same_text_selected = false;
15525                                selected_text = None;
15526                            }
15527                        } else {
15528                            same_text_selected = false;
15529                            selected_text = None;
15530                        }
15531                    }
15532                }
15533            }
15534
15535            if only_carets {
15536                for selection in &mut selections {
15537                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15538                    selection.start = word_range.start;
15539                    selection.end = word_range.end;
15540                    selection.goal = SelectionGoal::None;
15541                    selection.reversed = false;
15542                    self.select_match_ranges(
15543                        selection.start..selection.end,
15544                        selection.reversed,
15545                        action.replace_newest,
15546                        Some(Autoscroll::newest()),
15547                        window,
15548                        cx,
15549                    );
15550                }
15551                if selections.len() == 1 {
15552                    let selection = selections
15553                        .last()
15554                        .expect("ensured that there's only one selection");
15555                    let query = buffer
15556                        .text_for_range(selection.start..selection.end)
15557                        .collect::<String>();
15558                    let is_empty = query.is_empty();
15559                    let select_state = SelectNextState {
15560                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15561                        wordwise: true,
15562                        done: is_empty,
15563                    };
15564                    self.select_prev_state = Some(select_state);
15565                } else {
15566                    self.select_prev_state = None;
15567                }
15568            } else if let Some(selected_text) = selected_text {
15569                self.select_prev_state = Some(SelectNextState {
15570                    query: self
15571                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15572                    wordwise: false,
15573                    done: false,
15574                });
15575                self.select_previous(action, window, cx)?;
15576            }
15577        }
15578        Ok(())
15579    }
15580
15581    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15582    /// setting the case sensitivity based on the global
15583    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15584    /// editor's settings.
15585    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15586    where
15587        I: IntoIterator<Item = P>,
15588        P: AsRef<[u8]>,
15589    {
15590        let case_sensitive = self
15591            .select_next_is_case_sensitive
15592            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15593
15594        let mut builder = AhoCorasickBuilder::new();
15595        builder.ascii_case_insensitive(!case_sensitive);
15596        builder.build(patterns)
15597    }
15598
15599    pub fn find_next_match(
15600        &mut self,
15601        _: &FindNextMatch,
15602        window: &mut Window,
15603        cx: &mut Context<Self>,
15604    ) -> Result<()> {
15605        let selections = self.selections.disjoint_anchors_arc();
15606        match selections.first() {
15607            Some(first) if selections.len() >= 2 => {
15608                self.change_selections(Default::default(), window, cx, |s| {
15609                    s.select_ranges([first.range()]);
15610                });
15611            }
15612            _ => self.select_next(
15613                &SelectNext {
15614                    replace_newest: true,
15615                },
15616                window,
15617                cx,
15618            )?,
15619        }
15620        Ok(())
15621    }
15622
15623    pub fn find_previous_match(
15624        &mut self,
15625        _: &FindPreviousMatch,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) -> Result<()> {
15629        let selections = self.selections.disjoint_anchors_arc();
15630        match selections.last() {
15631            Some(last) if selections.len() >= 2 => {
15632                self.change_selections(Default::default(), window, cx, |s| {
15633                    s.select_ranges([last.range()]);
15634                });
15635            }
15636            _ => self.select_previous(
15637                &SelectPrevious {
15638                    replace_newest: true,
15639                },
15640                window,
15641                cx,
15642            )?,
15643        }
15644        Ok(())
15645    }
15646
15647    pub fn toggle_comments(
15648        &mut self,
15649        action: &ToggleComments,
15650        window: &mut Window,
15651        cx: &mut Context<Self>,
15652    ) {
15653        if self.read_only(cx) {
15654            return;
15655        }
15656        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15657        let text_layout_details = &self.text_layout_details(window);
15658        self.transact(window, cx, |this, window, cx| {
15659            let mut selections = this
15660                .selections
15661                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15662            let mut edits = Vec::new();
15663            let mut selection_edit_ranges = Vec::new();
15664            let mut last_toggled_row = None;
15665            let snapshot = this.buffer.read(cx).read(cx);
15666            let empty_str: Arc<str> = Arc::default();
15667            let mut suffixes_inserted = Vec::new();
15668            let ignore_indent = action.ignore_indent;
15669
15670            fn comment_prefix_range(
15671                snapshot: &MultiBufferSnapshot,
15672                row: MultiBufferRow,
15673                comment_prefix: &str,
15674                comment_prefix_whitespace: &str,
15675                ignore_indent: bool,
15676            ) -> Range<Point> {
15677                let indent_size = if ignore_indent {
15678                    0
15679                } else {
15680                    snapshot.indent_size_for_line(row).len
15681                };
15682
15683                let start = Point::new(row.0, indent_size);
15684
15685                let mut line_bytes = snapshot
15686                    .bytes_in_range(start..snapshot.max_point())
15687                    .flatten()
15688                    .copied();
15689
15690                // If this line currently begins with the line comment prefix, then record
15691                // the range containing the prefix.
15692                if line_bytes
15693                    .by_ref()
15694                    .take(comment_prefix.len())
15695                    .eq(comment_prefix.bytes())
15696                {
15697                    // Include any whitespace that matches the comment prefix.
15698                    let matching_whitespace_len = line_bytes
15699                        .zip(comment_prefix_whitespace.bytes())
15700                        .take_while(|(a, b)| a == b)
15701                        .count() as u32;
15702                    let end = Point::new(
15703                        start.row,
15704                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15705                    );
15706                    start..end
15707                } else {
15708                    start..start
15709                }
15710            }
15711
15712            fn comment_suffix_range(
15713                snapshot: &MultiBufferSnapshot,
15714                row: MultiBufferRow,
15715                comment_suffix: &str,
15716                comment_suffix_has_leading_space: bool,
15717            ) -> Range<Point> {
15718                let end = Point::new(row.0, snapshot.line_len(row));
15719                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15720
15721                let mut line_end_bytes = snapshot
15722                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15723                    .flatten()
15724                    .copied();
15725
15726                let leading_space_len = if suffix_start_column > 0
15727                    && line_end_bytes.next() == Some(b' ')
15728                    && comment_suffix_has_leading_space
15729                {
15730                    1
15731                } else {
15732                    0
15733                };
15734
15735                // If this line currently begins with the line comment prefix, then record
15736                // the range containing the prefix.
15737                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15738                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15739                    start..end
15740                } else {
15741                    end..end
15742                }
15743            }
15744
15745            // TODO: Handle selections that cross excerpts
15746            for selection in &mut selections {
15747                let start_column = snapshot
15748                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15749                    .len;
15750                let language = if let Some(language) =
15751                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15752                {
15753                    language
15754                } else {
15755                    continue;
15756                };
15757
15758                selection_edit_ranges.clear();
15759
15760                // If multiple selections contain a given row, avoid processing that
15761                // row more than once.
15762                let mut start_row = MultiBufferRow(selection.start.row);
15763                if last_toggled_row == Some(start_row) {
15764                    start_row = start_row.next_row();
15765                }
15766                let end_row =
15767                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15768                        MultiBufferRow(selection.end.row - 1)
15769                    } else {
15770                        MultiBufferRow(selection.end.row)
15771                    };
15772                last_toggled_row = Some(end_row);
15773
15774                if start_row > end_row {
15775                    continue;
15776                }
15777
15778                // If the language has line comments, toggle those.
15779                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15780
15781                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15782                if ignore_indent {
15783                    full_comment_prefixes = full_comment_prefixes
15784                        .into_iter()
15785                        .map(|s| Arc::from(s.trim_end()))
15786                        .collect();
15787                }
15788
15789                if !full_comment_prefixes.is_empty() {
15790                    let first_prefix = full_comment_prefixes
15791                        .first()
15792                        .expect("prefixes is non-empty");
15793                    let prefix_trimmed_lengths = full_comment_prefixes
15794                        .iter()
15795                        .map(|p| p.trim_end_matches(' ').len())
15796                        .collect::<SmallVec<[usize; 4]>>();
15797
15798                    let mut all_selection_lines_are_comments = true;
15799
15800                    for row in start_row.0..=end_row.0 {
15801                        let row = MultiBufferRow(row);
15802                        if start_row < end_row && snapshot.is_line_blank(row) {
15803                            continue;
15804                        }
15805
15806                        let prefix_range = full_comment_prefixes
15807                            .iter()
15808                            .zip(prefix_trimmed_lengths.iter().copied())
15809                            .map(|(prefix, trimmed_prefix_len)| {
15810                                comment_prefix_range(
15811                                    snapshot.deref(),
15812                                    row,
15813                                    &prefix[..trimmed_prefix_len],
15814                                    &prefix[trimmed_prefix_len..],
15815                                    ignore_indent,
15816                                )
15817                            })
15818                            .max_by_key(|range| range.end.column - range.start.column)
15819                            .expect("prefixes is non-empty");
15820
15821                        if prefix_range.is_empty() {
15822                            all_selection_lines_are_comments = false;
15823                        }
15824
15825                        selection_edit_ranges.push(prefix_range);
15826                    }
15827
15828                    if all_selection_lines_are_comments {
15829                        edits.extend(
15830                            selection_edit_ranges
15831                                .iter()
15832                                .cloned()
15833                                .map(|range| (range, empty_str.clone())),
15834                        );
15835                    } else {
15836                        let min_column = selection_edit_ranges
15837                            .iter()
15838                            .map(|range| range.start.column)
15839                            .min()
15840                            .unwrap_or(0);
15841                        edits.extend(selection_edit_ranges.iter().map(|range| {
15842                            let position = Point::new(range.start.row, min_column);
15843                            (position..position, first_prefix.clone())
15844                        }));
15845                    }
15846                } else if let Some(BlockCommentConfig {
15847                    start: full_comment_prefix,
15848                    end: comment_suffix,
15849                    ..
15850                }) = language.block_comment()
15851                {
15852                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15853                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15854                    let prefix_range = comment_prefix_range(
15855                        snapshot.deref(),
15856                        start_row,
15857                        comment_prefix,
15858                        comment_prefix_whitespace,
15859                        ignore_indent,
15860                    );
15861                    let suffix_range = comment_suffix_range(
15862                        snapshot.deref(),
15863                        end_row,
15864                        comment_suffix.trim_start_matches(' '),
15865                        comment_suffix.starts_with(' '),
15866                    );
15867
15868                    if prefix_range.is_empty() || suffix_range.is_empty() {
15869                        edits.push((
15870                            prefix_range.start..prefix_range.start,
15871                            full_comment_prefix.clone(),
15872                        ));
15873                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15874                        suffixes_inserted.push((end_row, comment_suffix.len()));
15875                    } else {
15876                        edits.push((prefix_range, empty_str.clone()));
15877                        edits.push((suffix_range, empty_str.clone()));
15878                    }
15879                } else {
15880                    continue;
15881                }
15882            }
15883
15884            drop(snapshot);
15885            this.buffer.update(cx, |buffer, cx| {
15886                buffer.edit(edits, None, cx);
15887            });
15888
15889            // Adjust selections so that they end before any comment suffixes that
15890            // were inserted.
15891            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15892            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15893            let snapshot = this.buffer.read(cx).read(cx);
15894            for selection in &mut selections {
15895                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15896                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15897                        Ordering::Less => {
15898                            suffixes_inserted.next();
15899                            continue;
15900                        }
15901                        Ordering::Greater => break,
15902                        Ordering::Equal => {
15903                            if selection.end.column == snapshot.line_len(row) {
15904                                if selection.is_empty() {
15905                                    selection.start.column -= suffix_len as u32;
15906                                }
15907                                selection.end.column -= suffix_len as u32;
15908                            }
15909                            break;
15910                        }
15911                    }
15912                }
15913            }
15914
15915            drop(snapshot);
15916            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15917
15918            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15919            let selections_on_single_row = selections.windows(2).all(|selections| {
15920                selections[0].start.row == selections[1].start.row
15921                    && selections[0].end.row == selections[1].end.row
15922                    && selections[0].start.row == selections[0].end.row
15923            });
15924            let selections_selecting = selections
15925                .iter()
15926                .any(|selection| selection.start != selection.end);
15927            let advance_downwards = action.advance_downwards
15928                && selections_on_single_row
15929                && !selections_selecting
15930                && !matches!(this.mode, EditorMode::SingleLine);
15931
15932            if advance_downwards {
15933                let snapshot = this.buffer.read(cx).snapshot(cx);
15934
15935                this.change_selections(Default::default(), window, cx, |s| {
15936                    s.move_cursors_with(|display_snapshot, display_point, _| {
15937                        let mut point = display_point.to_point(display_snapshot);
15938                        point.row += 1;
15939                        point = snapshot.clip_point(point, Bias::Left);
15940                        let display_point = point.to_display_point(display_snapshot);
15941                        let goal = SelectionGoal::HorizontalPosition(
15942                            display_snapshot
15943                                .x_for_display_point(display_point, text_layout_details)
15944                                .into(),
15945                        );
15946                        (display_point, goal)
15947                    })
15948                });
15949            }
15950        });
15951    }
15952
15953    pub fn select_enclosing_symbol(
15954        &mut self,
15955        _: &SelectEnclosingSymbol,
15956        window: &mut Window,
15957        cx: &mut Context<Self>,
15958    ) {
15959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15960
15961        let buffer = self.buffer.read(cx).snapshot(cx);
15962        let old_selections = self
15963            .selections
15964            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15965            .into_boxed_slice();
15966
15967        fn update_selection(
15968            selection: &Selection<MultiBufferOffset>,
15969            buffer_snap: &MultiBufferSnapshot,
15970        ) -> Option<Selection<MultiBufferOffset>> {
15971            let cursor = selection.head();
15972            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15973            for symbol in symbols.iter().rev() {
15974                let start = symbol.range.start.to_offset(buffer_snap);
15975                let end = symbol.range.end.to_offset(buffer_snap);
15976                let new_range = start..end;
15977                if start < selection.start || end > selection.end {
15978                    return Some(Selection {
15979                        id: selection.id,
15980                        start: new_range.start,
15981                        end: new_range.end,
15982                        goal: SelectionGoal::None,
15983                        reversed: selection.reversed,
15984                    });
15985                }
15986            }
15987            None
15988        }
15989
15990        let mut selected_larger_symbol = false;
15991        let new_selections = old_selections
15992            .iter()
15993            .map(|selection| match update_selection(selection, &buffer) {
15994                Some(new_selection) => {
15995                    if new_selection.range() != selection.range() {
15996                        selected_larger_symbol = true;
15997                    }
15998                    new_selection
15999                }
16000                None => selection.clone(),
16001            })
16002            .collect::<Vec<_>>();
16003
16004        if selected_larger_symbol {
16005            self.change_selections(Default::default(), window, cx, |s| {
16006                s.select(new_selections);
16007            });
16008        }
16009    }
16010
16011    pub fn select_larger_syntax_node(
16012        &mut self,
16013        _: &SelectLargerSyntaxNode,
16014        window: &mut Window,
16015        cx: &mut Context<Self>,
16016    ) {
16017        let Some(visible_row_count) = self.visible_row_count() else {
16018            return;
16019        };
16020        let old_selections: Box<[_]> = self
16021            .selections
16022            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16023            .into();
16024        if old_selections.is_empty() {
16025            return;
16026        }
16027
16028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16029
16030        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16031        let buffer = self.buffer.read(cx).snapshot(cx);
16032
16033        let mut selected_larger_node = false;
16034        let mut new_selections = old_selections
16035            .iter()
16036            .map(|selection| {
16037                let old_range = selection.start..selection.end;
16038
16039                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16040                    // manually select word at selection
16041                    if ["string_content", "inline"].contains(&node.kind()) {
16042                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16043                        // ignore if word is already selected
16044                        if !word_range.is_empty() && old_range != word_range {
16045                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16046                            // only select word if start and end point belongs to same word
16047                            if word_range == last_word_range {
16048                                selected_larger_node = true;
16049                                return Selection {
16050                                    id: selection.id,
16051                                    start: word_range.start,
16052                                    end: word_range.end,
16053                                    goal: SelectionGoal::None,
16054                                    reversed: selection.reversed,
16055                                };
16056                            }
16057                        }
16058                    }
16059                }
16060
16061                let mut new_range = old_range.clone();
16062                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16063                    new_range = range;
16064                    if !node.is_named() {
16065                        continue;
16066                    }
16067                    if !display_map.intersects_fold(new_range.start)
16068                        && !display_map.intersects_fold(new_range.end)
16069                    {
16070                        break;
16071                    }
16072                }
16073
16074                selected_larger_node |= new_range != old_range;
16075                Selection {
16076                    id: selection.id,
16077                    start: new_range.start,
16078                    end: new_range.end,
16079                    goal: SelectionGoal::None,
16080                    reversed: selection.reversed,
16081                }
16082            })
16083            .collect::<Vec<_>>();
16084
16085        if !selected_larger_node {
16086            return; // don't put this call in the history
16087        }
16088
16089        // scroll based on transformation done to the last selection created by the user
16090        let (last_old, last_new) = old_selections
16091            .last()
16092            .zip(new_selections.last().cloned())
16093            .expect("old_selections isn't empty");
16094
16095        // revert selection
16096        let is_selection_reversed = {
16097            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16098            new_selections.last_mut().expect("checked above").reversed =
16099                should_newest_selection_be_reversed;
16100            should_newest_selection_be_reversed
16101        };
16102
16103        if selected_larger_node {
16104            self.select_syntax_node_history.disable_clearing = true;
16105            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16106                s.select(new_selections.clone());
16107            });
16108            self.select_syntax_node_history.disable_clearing = false;
16109        }
16110
16111        let start_row = last_new.start.to_display_point(&display_map).row().0;
16112        let end_row = last_new.end.to_display_point(&display_map).row().0;
16113        let selection_height = end_row - start_row + 1;
16114        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16115
16116        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16117        let scroll_behavior = if fits_on_the_screen {
16118            self.request_autoscroll(Autoscroll::fit(), cx);
16119            SelectSyntaxNodeScrollBehavior::FitSelection
16120        } else if is_selection_reversed {
16121            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16122            SelectSyntaxNodeScrollBehavior::CursorTop
16123        } else {
16124            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16125            SelectSyntaxNodeScrollBehavior::CursorBottom
16126        };
16127
16128        self.select_syntax_node_history.push((
16129            old_selections,
16130            scroll_behavior,
16131            is_selection_reversed,
16132        ));
16133    }
16134
16135    pub fn select_smaller_syntax_node(
16136        &mut self,
16137        _: &SelectSmallerSyntaxNode,
16138        window: &mut Window,
16139        cx: &mut Context<Self>,
16140    ) {
16141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16142
16143        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16144            self.select_syntax_node_history.pop()
16145        {
16146            if let Some(selection) = selections.last_mut() {
16147                selection.reversed = is_selection_reversed;
16148            }
16149
16150            self.select_syntax_node_history.disable_clearing = true;
16151            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16152                s.select(selections.to_vec());
16153            });
16154            self.select_syntax_node_history.disable_clearing = false;
16155
16156            match scroll_behavior {
16157                SelectSyntaxNodeScrollBehavior::CursorTop => {
16158                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16159                }
16160                SelectSyntaxNodeScrollBehavior::FitSelection => {
16161                    self.request_autoscroll(Autoscroll::fit(), cx);
16162                }
16163                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16164                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16165                }
16166            }
16167        }
16168    }
16169
16170    pub fn unwrap_syntax_node(
16171        &mut self,
16172        _: &UnwrapSyntaxNode,
16173        window: &mut Window,
16174        cx: &mut Context<Self>,
16175    ) {
16176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16177
16178        let buffer = self.buffer.read(cx).snapshot(cx);
16179        let selections = self
16180            .selections
16181            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16182            .into_iter()
16183            // subtracting the offset requires sorting
16184            .sorted_by_key(|i| i.start);
16185
16186        let full_edits = selections
16187            .into_iter()
16188            .filter_map(|selection| {
16189                let child = if selection.is_empty()
16190                    && let Some((_, ancestor_range)) =
16191                        buffer.syntax_ancestor(selection.start..selection.end)
16192                {
16193                    ancestor_range
16194                } else {
16195                    selection.range()
16196                };
16197
16198                let mut parent = child.clone();
16199                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16200                    parent = ancestor_range;
16201                    if parent.start < child.start || parent.end > child.end {
16202                        break;
16203                    }
16204                }
16205
16206                if parent == child {
16207                    return None;
16208                }
16209                let text = buffer.text_for_range(child).collect::<String>();
16210                Some((selection.id, parent, text))
16211            })
16212            .collect::<Vec<_>>();
16213        if full_edits.is_empty() {
16214            return;
16215        }
16216
16217        self.transact(window, cx, |this, window, cx| {
16218            this.buffer.update(cx, |buffer, cx| {
16219                buffer.edit(
16220                    full_edits
16221                        .iter()
16222                        .map(|(_, p, t)| (p.clone(), t.clone()))
16223                        .collect::<Vec<_>>(),
16224                    None,
16225                    cx,
16226                );
16227            });
16228            this.change_selections(Default::default(), window, cx, |s| {
16229                let mut offset = 0;
16230                let mut selections = vec![];
16231                for (id, parent, text) in full_edits {
16232                    let start = parent.start - offset;
16233                    offset += (parent.end - parent.start) - text.len();
16234                    selections.push(Selection {
16235                        id,
16236                        start,
16237                        end: start + text.len(),
16238                        reversed: false,
16239                        goal: Default::default(),
16240                    });
16241                }
16242                s.select(selections);
16243            });
16244        });
16245    }
16246
16247    pub fn select_next_syntax_node(
16248        &mut self,
16249        _: &SelectNextSyntaxNode,
16250        window: &mut Window,
16251        cx: &mut Context<Self>,
16252    ) {
16253        let old_selections: Box<[_]> = self
16254            .selections
16255            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16256            .into();
16257        if old_selections.is_empty() {
16258            return;
16259        }
16260
16261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16262
16263        let buffer = self.buffer.read(cx).snapshot(cx);
16264        let mut selected_sibling = false;
16265
16266        let new_selections = old_selections
16267            .iter()
16268            .map(|selection| {
16269                let old_range = selection.start..selection.end;
16270
16271                let old_range =
16272                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16273                let excerpt = buffer.excerpt_containing(old_range.clone());
16274
16275                if let Some(mut excerpt) = excerpt
16276                    && let Some(node) = excerpt
16277                        .buffer()
16278                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16279                {
16280                    let new_range = excerpt.map_range_from_buffer(
16281                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16282                    );
16283                    selected_sibling = true;
16284                    Selection {
16285                        id: selection.id,
16286                        start: new_range.start,
16287                        end: new_range.end,
16288                        goal: SelectionGoal::None,
16289                        reversed: selection.reversed,
16290                    }
16291                } else {
16292                    selection.clone()
16293                }
16294            })
16295            .collect::<Vec<_>>();
16296
16297        if selected_sibling {
16298            self.change_selections(
16299                SelectionEffects::scroll(Autoscroll::fit()),
16300                window,
16301                cx,
16302                |s| {
16303                    s.select(new_selections);
16304                },
16305            );
16306        }
16307    }
16308
16309    pub fn select_prev_syntax_node(
16310        &mut self,
16311        _: &SelectPreviousSyntaxNode,
16312        window: &mut Window,
16313        cx: &mut Context<Self>,
16314    ) {
16315        let old_selections: Box<[_]> = self
16316            .selections
16317            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16318            .into();
16319        if old_selections.is_empty() {
16320            return;
16321        }
16322
16323        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16324
16325        let buffer = self.buffer.read(cx).snapshot(cx);
16326        let mut selected_sibling = false;
16327
16328        let new_selections = old_selections
16329            .iter()
16330            .map(|selection| {
16331                let old_range = selection.start..selection.end;
16332                let old_range =
16333                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16334                let excerpt = buffer.excerpt_containing(old_range.clone());
16335
16336                if let Some(mut excerpt) = excerpt
16337                    && let Some(node) = excerpt
16338                        .buffer()
16339                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16340                {
16341                    let new_range = excerpt.map_range_from_buffer(
16342                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16343                    );
16344                    selected_sibling = true;
16345                    Selection {
16346                        id: selection.id,
16347                        start: new_range.start,
16348                        end: new_range.end,
16349                        goal: SelectionGoal::None,
16350                        reversed: selection.reversed,
16351                    }
16352                } else {
16353                    selection.clone()
16354                }
16355            })
16356            .collect::<Vec<_>>();
16357
16358        if selected_sibling {
16359            self.change_selections(
16360                SelectionEffects::scroll(Autoscroll::fit()),
16361                window,
16362                cx,
16363                |s| {
16364                    s.select(new_selections);
16365                },
16366            );
16367        }
16368    }
16369
16370    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16371        if !EditorSettings::get_global(cx).gutter.runnables {
16372            self.clear_tasks();
16373            return Task::ready(());
16374        }
16375        let project = self.project().map(Entity::downgrade);
16376        let task_sources = self.lsp_task_sources(cx);
16377        let multi_buffer = self.buffer.downgrade();
16378        cx.spawn_in(window, async move |editor, cx| {
16379            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16380            let Some(project) = project.and_then(|p| p.upgrade()) else {
16381                return;
16382            };
16383            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16384                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16385            }) else {
16386                return;
16387            };
16388
16389            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16390            if hide_runnables {
16391                return;
16392            }
16393            let new_rows =
16394                cx.background_spawn({
16395                    let snapshot = display_snapshot.clone();
16396                    async move {
16397                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16398                    }
16399                })
16400                    .await;
16401            let Ok(lsp_tasks) =
16402                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16403            else {
16404                return;
16405            };
16406            let lsp_tasks = lsp_tasks.await;
16407
16408            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16409                lsp_tasks
16410                    .into_iter()
16411                    .flat_map(|(kind, tasks)| {
16412                        tasks.into_iter().filter_map(move |(location, task)| {
16413                            Some((kind.clone(), location?, task))
16414                        })
16415                    })
16416                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16417                        let buffer = location.target.buffer;
16418                        let buffer_snapshot = buffer.read(cx).snapshot();
16419                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16420                            |(excerpt_id, snapshot, _)| {
16421                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16422                                    display_snapshot
16423                                        .buffer_snapshot()
16424                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16425                                } else {
16426                                    None
16427                                }
16428                            },
16429                        );
16430                        if let Some(offset) = offset {
16431                            let task_buffer_range =
16432                                location.target.range.to_point(&buffer_snapshot);
16433                            let context_buffer_range =
16434                                task_buffer_range.to_offset(&buffer_snapshot);
16435                            let context_range = BufferOffset(context_buffer_range.start)
16436                                ..BufferOffset(context_buffer_range.end);
16437
16438                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16439                                .or_insert_with(|| RunnableTasks {
16440                                    templates: Vec::new(),
16441                                    offset,
16442                                    column: task_buffer_range.start.column,
16443                                    extra_variables: HashMap::default(),
16444                                    context_range,
16445                                })
16446                                .templates
16447                                .push((kind, task.original_task().clone()));
16448                        }
16449
16450                        acc
16451                    })
16452            }) else {
16453                return;
16454            };
16455
16456            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16457                buffer.language_settings(cx).tasks.prefer_lsp
16458            }) else {
16459                return;
16460            };
16461
16462            let rows = Self::runnable_rows(
16463                project,
16464                display_snapshot,
16465                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16466                new_rows,
16467                cx.clone(),
16468            )
16469            .await;
16470            editor
16471                .update(cx, |editor, _| {
16472                    editor.clear_tasks();
16473                    for (key, mut value) in rows {
16474                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16475                            value.templates.extend(lsp_tasks.templates);
16476                        }
16477
16478                        editor.insert_tasks(key, value);
16479                    }
16480                    for (key, value) in lsp_tasks_by_rows {
16481                        editor.insert_tasks(key, value);
16482                    }
16483                })
16484                .ok();
16485        })
16486    }
16487    fn fetch_runnable_ranges(
16488        snapshot: &DisplaySnapshot,
16489        range: Range<Anchor>,
16490    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16491        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16492    }
16493
16494    fn runnable_rows(
16495        project: Entity<Project>,
16496        snapshot: DisplaySnapshot,
16497        prefer_lsp: bool,
16498        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16499        cx: AsyncWindowContext,
16500    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16501        cx.spawn(async move |cx| {
16502            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16503            for (run_range, mut runnable) in runnable_ranges {
16504                let Some(tasks) = cx
16505                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16506                    .ok()
16507                else {
16508                    continue;
16509                };
16510                let mut tasks = tasks.await;
16511
16512                if prefer_lsp {
16513                    tasks.retain(|(task_kind, _)| {
16514                        !matches!(task_kind, TaskSourceKind::Language { .. })
16515                    });
16516                }
16517                if tasks.is_empty() {
16518                    continue;
16519                }
16520
16521                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16522                let Some(row) = snapshot
16523                    .buffer_snapshot()
16524                    .buffer_line_for_row(MultiBufferRow(point.row))
16525                    .map(|(_, range)| range.start.row)
16526                else {
16527                    continue;
16528                };
16529
16530                let context_range =
16531                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16532                runnable_rows.push((
16533                    (runnable.buffer_id, row),
16534                    RunnableTasks {
16535                        templates: tasks,
16536                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16537                        context_range,
16538                        column: point.column,
16539                        extra_variables: runnable.extra_captures,
16540                    },
16541                ));
16542            }
16543            runnable_rows
16544        })
16545    }
16546
16547    fn templates_with_tags(
16548        project: &Entity<Project>,
16549        runnable: &mut Runnable,
16550        cx: &mut App,
16551    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16552        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16553            let (worktree_id, file) = project
16554                .buffer_for_id(runnable.buffer, cx)
16555                .and_then(|buffer| buffer.read(cx).file())
16556                .map(|file| (file.worktree_id(cx), file.clone()))
16557                .unzip();
16558
16559            (
16560                project.task_store().read(cx).task_inventory().cloned(),
16561                worktree_id,
16562                file,
16563            )
16564        });
16565
16566        let tags = mem::take(&mut runnable.tags);
16567        let language = runnable.language.clone();
16568        cx.spawn(async move |cx| {
16569            let mut templates_with_tags = Vec::new();
16570            if let Some(inventory) = inventory {
16571                for RunnableTag(tag) in tags {
16572                    let new_tasks = inventory.update(cx, |inventory, cx| {
16573                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16574                    });
16575                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16576                        move |(_, template)| {
16577                            template.tags.iter().any(|source_tag| source_tag == &tag)
16578                        },
16579                    ));
16580                }
16581            }
16582            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16583
16584            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16585                // Strongest source wins; if we have worktree tag binding, prefer that to
16586                // global and language bindings;
16587                // if we have a global binding, prefer that to language binding.
16588                let first_mismatch = templates_with_tags
16589                    .iter()
16590                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16591                if let Some(index) = first_mismatch {
16592                    templates_with_tags.truncate(index);
16593                }
16594            }
16595
16596            templates_with_tags
16597        })
16598    }
16599
16600    pub fn move_to_enclosing_bracket(
16601        &mut self,
16602        _: &MoveToEnclosingBracket,
16603        window: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) {
16606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16607        self.change_selections(Default::default(), window, cx, |s| {
16608            s.move_offsets_with(|snapshot, selection| {
16609                let Some(enclosing_bracket_ranges) =
16610                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16611                else {
16612                    return;
16613                };
16614
16615                let mut best_length = usize::MAX;
16616                let mut best_inside = false;
16617                let mut best_in_bracket_range = false;
16618                let mut best_destination = None;
16619                for (open, close) in enclosing_bracket_ranges {
16620                    let close = close.to_inclusive();
16621                    let length = *close.end() - open.start;
16622                    let inside = selection.start >= open.end && selection.end <= *close.start();
16623                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16624                        || close.contains(&selection.head());
16625
16626                    // If best is next to a bracket and current isn't, skip
16627                    if !in_bracket_range && best_in_bracket_range {
16628                        continue;
16629                    }
16630
16631                    // Prefer smaller lengths unless best is inside and current isn't
16632                    if length > best_length && (best_inside || !inside) {
16633                        continue;
16634                    }
16635
16636                    best_length = length;
16637                    best_inside = inside;
16638                    best_in_bracket_range = in_bracket_range;
16639                    best_destination = Some(
16640                        if close.contains(&selection.start) && close.contains(&selection.end) {
16641                            if inside { open.end } else { open.start }
16642                        } else if inside {
16643                            *close.start()
16644                        } else {
16645                            *close.end()
16646                        },
16647                    );
16648                }
16649
16650                if let Some(destination) = best_destination {
16651                    selection.collapse_to(destination, SelectionGoal::None);
16652                }
16653            })
16654        });
16655    }
16656
16657    pub fn undo_selection(
16658        &mut self,
16659        _: &UndoSelection,
16660        window: &mut Window,
16661        cx: &mut Context<Self>,
16662    ) {
16663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16664        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16665            self.selection_history.mode = SelectionHistoryMode::Undoing;
16666            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16667                this.end_selection(window, cx);
16668                this.change_selections(
16669                    SelectionEffects::scroll(Autoscroll::newest()),
16670                    window,
16671                    cx,
16672                    |s| s.select_anchors(entry.selections.to_vec()),
16673                );
16674            });
16675            self.selection_history.mode = SelectionHistoryMode::Normal;
16676
16677            self.select_next_state = entry.select_next_state;
16678            self.select_prev_state = entry.select_prev_state;
16679            self.add_selections_state = entry.add_selections_state;
16680        }
16681    }
16682
16683    pub fn redo_selection(
16684        &mut self,
16685        _: &RedoSelection,
16686        window: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) {
16689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16690        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16691            self.selection_history.mode = SelectionHistoryMode::Redoing;
16692            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16693                this.end_selection(window, cx);
16694                this.change_selections(
16695                    SelectionEffects::scroll(Autoscroll::newest()),
16696                    window,
16697                    cx,
16698                    |s| s.select_anchors(entry.selections.to_vec()),
16699                );
16700            });
16701            self.selection_history.mode = SelectionHistoryMode::Normal;
16702
16703            self.select_next_state = entry.select_next_state;
16704            self.select_prev_state = entry.select_prev_state;
16705            self.add_selections_state = entry.add_selections_state;
16706        }
16707    }
16708
16709    pub fn expand_excerpts(
16710        &mut self,
16711        action: &ExpandExcerpts,
16712        _: &mut Window,
16713        cx: &mut Context<Self>,
16714    ) {
16715        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16716    }
16717
16718    pub fn expand_excerpts_down(
16719        &mut self,
16720        action: &ExpandExcerptsDown,
16721        _: &mut Window,
16722        cx: &mut Context<Self>,
16723    ) {
16724        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16725    }
16726
16727    pub fn expand_excerpts_up(
16728        &mut self,
16729        action: &ExpandExcerptsUp,
16730        _: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) {
16733        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16734    }
16735
16736    pub fn expand_excerpts_for_direction(
16737        &mut self,
16738        lines: u32,
16739        direction: ExpandExcerptDirection,
16740        cx: &mut Context<Self>,
16741    ) {
16742        let selections = self.selections.disjoint_anchors_arc();
16743
16744        let lines = if lines == 0 {
16745            EditorSettings::get_global(cx).expand_excerpt_lines
16746        } else {
16747            lines
16748        };
16749
16750        let snapshot = self.buffer.read(cx).snapshot(cx);
16751        let mut excerpt_ids = selections
16752            .iter()
16753            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16754            .collect::<Vec<_>>();
16755        excerpt_ids.sort();
16756        excerpt_ids.dedup();
16757
16758        if self.delegate_expand_excerpts {
16759            cx.emit(EditorEvent::ExpandExcerptsRequested {
16760                excerpt_ids,
16761                lines,
16762                direction,
16763            });
16764            return;
16765        }
16766
16767        self.buffer.update(cx, |buffer, cx| {
16768            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16769        })
16770    }
16771
16772    pub fn expand_excerpt(
16773        &mut self,
16774        excerpt: ExcerptId,
16775        direction: ExpandExcerptDirection,
16776        window: &mut Window,
16777        cx: &mut Context<Self>,
16778    ) {
16779        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16780
16781        if self.delegate_expand_excerpts {
16782            cx.emit(EditorEvent::ExpandExcerptsRequested {
16783                excerpt_ids: vec![excerpt],
16784                lines: lines_to_expand,
16785                direction,
16786            });
16787            return;
16788        }
16789
16790        let current_scroll_position = self.scroll_position(cx);
16791        let mut scroll = None;
16792
16793        if direction == ExpandExcerptDirection::Down {
16794            let multi_buffer = self.buffer.read(cx);
16795            let snapshot = multi_buffer.snapshot(cx);
16796            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16797                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16798                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16799            {
16800                let buffer_snapshot = buffer.read(cx).snapshot();
16801                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16802                let last_row = buffer_snapshot.max_point().row;
16803                let lines_below = last_row.saturating_sub(excerpt_end_row);
16804                if lines_below >= lines_to_expand {
16805                    scroll = Some(
16806                        current_scroll_position
16807                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16808                    );
16809                }
16810            }
16811        }
16812        if direction == ExpandExcerptDirection::Up
16813            && self
16814                .buffer
16815                .read(cx)
16816                .snapshot(cx)
16817                .excerpt_before(excerpt)
16818                .is_none()
16819        {
16820            scroll = Some(current_scroll_position);
16821        }
16822
16823        self.buffer.update(cx, |buffer, cx| {
16824            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16825        });
16826
16827        if let Some(new_scroll_position) = scroll {
16828            self.set_scroll_position(new_scroll_position, window, cx);
16829        }
16830    }
16831
16832    pub fn go_to_singleton_buffer_point(
16833        &mut self,
16834        point: Point,
16835        window: &mut Window,
16836        cx: &mut Context<Self>,
16837    ) {
16838        self.go_to_singleton_buffer_range(point..point, window, cx);
16839    }
16840
16841    pub fn go_to_singleton_buffer_range(
16842        &mut self,
16843        range: Range<Point>,
16844        window: &mut Window,
16845        cx: &mut Context<Self>,
16846    ) {
16847        let multibuffer = self.buffer().read(cx);
16848        let Some(buffer) = multibuffer.as_singleton() else {
16849            return;
16850        };
16851        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16852            return;
16853        };
16854        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16855            return;
16856        };
16857        self.change_selections(
16858            SelectionEffects::default().nav_history(true),
16859            window,
16860            cx,
16861            |s| s.select_anchor_ranges([start..end]),
16862        );
16863    }
16864
16865    pub fn go_to_diagnostic(
16866        &mut self,
16867        action: &GoToDiagnostic,
16868        window: &mut Window,
16869        cx: &mut Context<Self>,
16870    ) {
16871        if !self.diagnostics_enabled() {
16872            return;
16873        }
16874        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16875        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16876    }
16877
16878    pub fn go_to_prev_diagnostic(
16879        &mut self,
16880        action: &GoToPreviousDiagnostic,
16881        window: &mut Window,
16882        cx: &mut Context<Self>,
16883    ) {
16884        if !self.diagnostics_enabled() {
16885            return;
16886        }
16887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16888        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16889    }
16890
16891    pub fn go_to_diagnostic_impl(
16892        &mut self,
16893        direction: Direction,
16894        severity: GoToDiagnosticSeverityFilter,
16895        window: &mut Window,
16896        cx: &mut Context<Self>,
16897    ) {
16898        let buffer = self.buffer.read(cx).snapshot(cx);
16899        let selection = self
16900            .selections
16901            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16902
16903        let mut active_group_id = None;
16904        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16905            && active_group.active_range.start.to_offset(&buffer) == selection.start
16906        {
16907            active_group_id = Some(active_group.group_id);
16908        }
16909
16910        fn filtered<'a>(
16911            severity: GoToDiagnosticSeverityFilter,
16912            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16913        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16914            diagnostics
16915                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16916                .filter(|entry| entry.range.start != entry.range.end)
16917                .filter(|entry| !entry.diagnostic.is_unnecessary)
16918        }
16919
16920        let before = filtered(
16921            severity,
16922            buffer
16923                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16924                .filter(|entry| entry.range.start <= selection.start),
16925        );
16926        let after = filtered(
16927            severity,
16928            buffer
16929                .diagnostics_in_range(selection.start..buffer.len())
16930                .filter(|entry| entry.range.start >= selection.start),
16931        );
16932
16933        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16934        if direction == Direction::Prev {
16935            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16936            {
16937                for diagnostic in prev_diagnostics.into_iter().rev() {
16938                    if diagnostic.range.start != selection.start
16939                        || active_group_id
16940                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16941                    {
16942                        found = Some(diagnostic);
16943                        break 'outer;
16944                    }
16945                }
16946            }
16947        } else {
16948            for diagnostic in after.chain(before) {
16949                if diagnostic.range.start != selection.start
16950                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16951                {
16952                    found = Some(diagnostic);
16953                    break;
16954                }
16955            }
16956        }
16957        let Some(next_diagnostic) = found else {
16958            return;
16959        };
16960
16961        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16962        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16963            return;
16964        };
16965        let snapshot = self.snapshot(window, cx);
16966        if snapshot.intersects_fold(next_diagnostic.range.start) {
16967            self.unfold_ranges(
16968                std::slice::from_ref(&next_diagnostic.range),
16969                true,
16970                false,
16971                cx,
16972            );
16973        }
16974        self.change_selections(Default::default(), window, cx, |s| {
16975            s.select_ranges(vec![
16976                next_diagnostic.range.start..next_diagnostic.range.start,
16977            ])
16978        });
16979        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16980        self.refresh_edit_prediction(false, true, window, cx);
16981    }
16982
16983    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16985        let snapshot = self.snapshot(window, cx);
16986        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16987        self.go_to_hunk_before_or_after_position(
16988            &snapshot,
16989            selection.head(),
16990            Direction::Next,
16991            window,
16992            cx,
16993        );
16994    }
16995
16996    pub fn go_to_hunk_before_or_after_position(
16997        &mut self,
16998        snapshot: &EditorSnapshot,
16999        position: Point,
17000        direction: Direction,
17001        window: &mut Window,
17002        cx: &mut Context<Editor>,
17003    ) {
17004        let row = if direction == Direction::Next {
17005            self.hunk_after_position(snapshot, position)
17006                .map(|hunk| hunk.row_range.start)
17007        } else {
17008            self.hunk_before_position(snapshot, position)
17009        };
17010
17011        if let Some(row) = row {
17012            let destination = Point::new(row.0, 0);
17013            let autoscroll = Autoscroll::center();
17014
17015            self.unfold_ranges(&[destination..destination], false, false, cx);
17016            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17017                s.select_ranges([destination..destination]);
17018            });
17019        }
17020    }
17021
17022    fn hunk_after_position(
17023        &mut self,
17024        snapshot: &EditorSnapshot,
17025        position: Point,
17026    ) -> Option<MultiBufferDiffHunk> {
17027        snapshot
17028            .buffer_snapshot()
17029            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17030            .find(|hunk| hunk.row_range.start.0 > position.row)
17031            .or_else(|| {
17032                snapshot
17033                    .buffer_snapshot()
17034                    .diff_hunks_in_range(Point::zero()..position)
17035                    .find(|hunk| hunk.row_range.end.0 < position.row)
17036            })
17037    }
17038
17039    fn go_to_prev_hunk(
17040        &mut self,
17041        _: &GoToPreviousHunk,
17042        window: &mut Window,
17043        cx: &mut Context<Self>,
17044    ) {
17045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17046        let snapshot = self.snapshot(window, cx);
17047        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17048        self.go_to_hunk_before_or_after_position(
17049            &snapshot,
17050            selection.head(),
17051            Direction::Prev,
17052            window,
17053            cx,
17054        );
17055    }
17056
17057    fn hunk_before_position(
17058        &mut self,
17059        snapshot: &EditorSnapshot,
17060        position: Point,
17061    ) -> Option<MultiBufferRow> {
17062        snapshot
17063            .buffer_snapshot()
17064            .diff_hunk_before(position)
17065            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17066    }
17067
17068    fn go_to_next_change(
17069        &mut self,
17070        _: &GoToNextChange,
17071        window: &mut Window,
17072        cx: &mut Context<Self>,
17073    ) {
17074        if let Some(selections) = self
17075            .change_list
17076            .next_change(1, Direction::Next)
17077            .map(|s| s.to_vec())
17078        {
17079            self.change_selections(Default::default(), window, cx, |s| {
17080                let map = s.display_snapshot();
17081                s.select_display_ranges(selections.iter().map(|a| {
17082                    let point = a.to_display_point(&map);
17083                    point..point
17084                }))
17085            })
17086        }
17087    }
17088
17089    fn go_to_previous_change(
17090        &mut self,
17091        _: &GoToPreviousChange,
17092        window: &mut Window,
17093        cx: &mut Context<Self>,
17094    ) {
17095        if let Some(selections) = self
17096            .change_list
17097            .next_change(1, Direction::Prev)
17098            .map(|s| s.to_vec())
17099        {
17100            self.change_selections(Default::default(), window, cx, |s| {
17101                let map = s.display_snapshot();
17102                s.select_display_ranges(selections.iter().map(|a| {
17103                    let point = a.to_display_point(&map);
17104                    point..point
17105                }))
17106            })
17107        }
17108    }
17109
17110    pub fn go_to_next_document_highlight(
17111        &mut self,
17112        _: &GoToNextDocumentHighlight,
17113        window: &mut Window,
17114        cx: &mut Context<Self>,
17115    ) {
17116        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17117    }
17118
17119    pub fn go_to_prev_document_highlight(
17120        &mut self,
17121        _: &GoToPreviousDocumentHighlight,
17122        window: &mut Window,
17123        cx: &mut Context<Self>,
17124    ) {
17125        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17126    }
17127
17128    pub fn go_to_document_highlight_before_or_after_position(
17129        &mut self,
17130        direction: Direction,
17131        window: &mut Window,
17132        cx: &mut Context<Editor>,
17133    ) {
17134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17135        let snapshot = self.snapshot(window, cx);
17136        let buffer = &snapshot.buffer_snapshot();
17137        let position = self
17138            .selections
17139            .newest::<Point>(&snapshot.display_snapshot)
17140            .head();
17141        let anchor_position = buffer.anchor_after(position);
17142
17143        // Get all document highlights (both read and write)
17144        let mut all_highlights = Vec::new();
17145
17146        if let Some((_, read_highlights)) = self
17147            .background_highlights
17148            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17149        {
17150            all_highlights.extend(read_highlights.iter());
17151        }
17152
17153        if let Some((_, write_highlights)) = self
17154            .background_highlights
17155            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17156        {
17157            all_highlights.extend(write_highlights.iter());
17158        }
17159
17160        if all_highlights.is_empty() {
17161            return;
17162        }
17163
17164        // Sort highlights by position
17165        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17166
17167        let target_highlight = match direction {
17168            Direction::Next => {
17169                // Find the first highlight after the current position
17170                all_highlights
17171                    .iter()
17172                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17173            }
17174            Direction::Prev => {
17175                // Find the last highlight before the current position
17176                all_highlights
17177                    .iter()
17178                    .rev()
17179                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17180            }
17181        };
17182
17183        if let Some(highlight) = target_highlight {
17184            let destination = highlight.start.to_point(buffer);
17185            let autoscroll = Autoscroll::center();
17186
17187            self.unfold_ranges(&[destination..destination], false, false, cx);
17188            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17189                s.select_ranges([destination..destination]);
17190            });
17191        }
17192    }
17193
17194    fn go_to_line<T: 'static>(
17195        &mut self,
17196        position: Anchor,
17197        highlight_color: Option<Hsla>,
17198        window: &mut Window,
17199        cx: &mut Context<Self>,
17200    ) {
17201        let snapshot = self.snapshot(window, cx).display_snapshot;
17202        let position = position.to_point(&snapshot.buffer_snapshot());
17203        let start = snapshot
17204            .buffer_snapshot()
17205            .clip_point(Point::new(position.row, 0), Bias::Left);
17206        let end = start + Point::new(1, 0);
17207        let start = snapshot.buffer_snapshot().anchor_before(start);
17208        let end = snapshot.buffer_snapshot().anchor_before(end);
17209
17210        self.highlight_rows::<T>(
17211            start..end,
17212            highlight_color
17213                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17214            Default::default(),
17215            cx,
17216        );
17217
17218        if self.buffer.read(cx).is_singleton() {
17219            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17220        }
17221    }
17222
17223    pub fn go_to_definition(
17224        &mut self,
17225        _: &GoToDefinition,
17226        window: &mut Window,
17227        cx: &mut Context<Self>,
17228    ) -> Task<Result<Navigated>> {
17229        let definition =
17230            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17231        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17232        cx.spawn_in(window, async move |editor, cx| {
17233            if definition.await? == Navigated::Yes {
17234                return Ok(Navigated::Yes);
17235            }
17236            match fallback_strategy {
17237                GoToDefinitionFallback::None => Ok(Navigated::No),
17238                GoToDefinitionFallback::FindAllReferences => {
17239                    match editor.update_in(cx, |editor, window, cx| {
17240                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17241                    })? {
17242                        Some(references) => references.await,
17243                        None => Ok(Navigated::No),
17244                    }
17245                }
17246            }
17247        })
17248    }
17249
17250    pub fn go_to_declaration(
17251        &mut self,
17252        _: &GoToDeclaration,
17253        window: &mut Window,
17254        cx: &mut Context<Self>,
17255    ) -> Task<Result<Navigated>> {
17256        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17257    }
17258
17259    pub fn go_to_declaration_split(
17260        &mut self,
17261        _: &GoToDeclaration,
17262        window: &mut Window,
17263        cx: &mut Context<Self>,
17264    ) -> Task<Result<Navigated>> {
17265        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17266    }
17267
17268    pub fn go_to_implementation(
17269        &mut self,
17270        _: &GoToImplementation,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) -> Task<Result<Navigated>> {
17274        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17275    }
17276
17277    pub fn go_to_implementation_split(
17278        &mut self,
17279        _: &GoToImplementationSplit,
17280        window: &mut Window,
17281        cx: &mut Context<Self>,
17282    ) -> Task<Result<Navigated>> {
17283        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17284    }
17285
17286    pub fn go_to_type_definition(
17287        &mut self,
17288        _: &GoToTypeDefinition,
17289        window: &mut Window,
17290        cx: &mut Context<Self>,
17291    ) -> Task<Result<Navigated>> {
17292        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17293    }
17294
17295    pub fn go_to_definition_split(
17296        &mut self,
17297        _: &GoToDefinitionSplit,
17298        window: &mut Window,
17299        cx: &mut Context<Self>,
17300    ) -> Task<Result<Navigated>> {
17301        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17302    }
17303
17304    pub fn go_to_type_definition_split(
17305        &mut self,
17306        _: &GoToTypeDefinitionSplit,
17307        window: &mut Window,
17308        cx: &mut Context<Self>,
17309    ) -> Task<Result<Navigated>> {
17310        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17311    }
17312
17313    fn go_to_definition_of_kind(
17314        &mut self,
17315        kind: GotoDefinitionKind,
17316        split: bool,
17317        window: &mut Window,
17318        cx: &mut Context<Self>,
17319    ) -> Task<Result<Navigated>> {
17320        let Some(provider) = self.semantics_provider.clone() else {
17321            return Task::ready(Ok(Navigated::No));
17322        };
17323        let head = self
17324            .selections
17325            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17326            .head();
17327        let buffer = self.buffer.read(cx);
17328        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17329            return Task::ready(Ok(Navigated::No));
17330        };
17331        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17332            return Task::ready(Ok(Navigated::No));
17333        };
17334
17335        cx.spawn_in(window, async move |editor, cx| {
17336            let Some(definitions) = definitions.await? else {
17337                return Ok(Navigated::No);
17338            };
17339            let navigated = editor
17340                .update_in(cx, |editor, window, cx| {
17341                    editor.navigate_to_hover_links(
17342                        Some(kind),
17343                        definitions
17344                            .into_iter()
17345                            .filter(|location| {
17346                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17347                            })
17348                            .map(HoverLink::Text)
17349                            .collect::<Vec<_>>(),
17350                        split,
17351                        window,
17352                        cx,
17353                    )
17354                })?
17355                .await?;
17356            anyhow::Ok(navigated)
17357        })
17358    }
17359
17360    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17361        let selection = self.selections.newest_anchor();
17362        let head = selection.head();
17363        let tail = selection.tail();
17364
17365        let Some((buffer, start_position)) =
17366            self.buffer.read(cx).text_anchor_for_position(head, cx)
17367        else {
17368            return;
17369        };
17370
17371        let end_position = if head != tail {
17372            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17373                return;
17374            };
17375            Some(pos)
17376        } else {
17377            None
17378        };
17379
17380        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17381            let url = if let Some(end_pos) = end_position {
17382                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17383            } else {
17384                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17385            };
17386
17387            if let Some(url) = url {
17388                cx.update(|window, cx| {
17389                    if parse_zed_link(&url, cx).is_some() {
17390                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17391                    } else {
17392                        cx.open_url(&url);
17393                    }
17394                })?;
17395            }
17396
17397            anyhow::Ok(())
17398        });
17399
17400        url_finder.detach();
17401    }
17402
17403    pub fn open_selected_filename(
17404        &mut self,
17405        _: &OpenSelectedFilename,
17406        window: &mut Window,
17407        cx: &mut Context<Self>,
17408    ) {
17409        let Some(workspace) = self.workspace() else {
17410            return;
17411        };
17412
17413        let position = self.selections.newest_anchor().head();
17414
17415        let Some((buffer, buffer_position)) =
17416            self.buffer.read(cx).text_anchor_for_position(position, cx)
17417        else {
17418            return;
17419        };
17420
17421        let project = self.project.clone();
17422
17423        cx.spawn_in(window, async move |_, cx| {
17424            let result = find_file(&buffer, project, buffer_position, cx).await;
17425
17426            if let Some((_, path)) = result {
17427                workspace
17428                    .update_in(cx, |workspace, window, cx| {
17429                        workspace.open_resolved_path(path, window, cx)
17430                    })?
17431                    .await?;
17432            }
17433            anyhow::Ok(())
17434        })
17435        .detach();
17436    }
17437
17438    pub(crate) fn navigate_to_hover_links(
17439        &mut self,
17440        kind: Option<GotoDefinitionKind>,
17441        definitions: Vec<HoverLink>,
17442        split: bool,
17443        window: &mut Window,
17444        cx: &mut Context<Editor>,
17445    ) -> Task<Result<Navigated>> {
17446        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17447        let mut first_url_or_file = None;
17448        let definitions: Vec<_> = definitions
17449            .into_iter()
17450            .filter_map(|def| match def {
17451                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17452                HoverLink::InlayHint(lsp_location, server_id) => {
17453                    let computation =
17454                        self.compute_target_location(lsp_location, server_id, window, cx);
17455                    Some(cx.background_spawn(computation))
17456                }
17457                HoverLink::Url(url) => {
17458                    first_url_or_file = Some(Either::Left(url));
17459                    None
17460                }
17461                HoverLink::File(path) => {
17462                    first_url_or_file = Some(Either::Right(path));
17463                    None
17464                }
17465            })
17466            .collect();
17467
17468        let workspace = self.workspace();
17469
17470        cx.spawn_in(window, async move |editor, cx| {
17471            let locations: Vec<Location> = future::join_all(definitions)
17472                .await
17473                .into_iter()
17474                .filter_map(|location| location.transpose())
17475                .collect::<Result<_>>()
17476                .context("location tasks")?;
17477            let mut locations = cx.update(|_, cx| {
17478                locations
17479                    .into_iter()
17480                    .map(|location| {
17481                        let buffer = location.buffer.read(cx);
17482                        (location.buffer, location.range.to_point(buffer))
17483                    })
17484                    .into_group_map()
17485            })?;
17486            let mut num_locations = 0;
17487            for ranges in locations.values_mut() {
17488                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17489                ranges.dedup();
17490                num_locations += ranges.len();
17491            }
17492
17493            if num_locations > 1 {
17494                let tab_kind = match kind {
17495                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17496                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17497                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17498                    Some(GotoDefinitionKind::Type) => "Types",
17499                };
17500                let title = editor
17501                    .update_in(cx, |_, _, cx| {
17502                        let target = locations
17503                            .iter()
17504                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17505                            .map(|(buffer, location)| {
17506                                buffer
17507                                    .read(cx)
17508                                    .text_for_range(location.clone())
17509                                    .collect::<String>()
17510                            })
17511                            .filter(|text| !text.contains('\n'))
17512                            .unique()
17513                            .take(3)
17514                            .join(", ");
17515                        if target.is_empty() {
17516                            tab_kind.to_owned()
17517                        } else {
17518                            format!("{tab_kind} for {target}")
17519                        }
17520                    })
17521                    .context("buffer title")?;
17522
17523                let Some(workspace) = workspace else {
17524                    return Ok(Navigated::No);
17525                };
17526
17527                let opened = workspace
17528                    .update_in(cx, |workspace, window, cx| {
17529                        let allow_preview = PreviewTabsSettings::get_global(cx)
17530                            .enable_preview_multibuffer_from_code_navigation;
17531                        Self::open_locations_in_multibuffer(
17532                            workspace,
17533                            locations,
17534                            title,
17535                            split,
17536                            allow_preview,
17537                            MultibufferSelectionMode::First,
17538                            window,
17539                            cx,
17540                        )
17541                    })
17542                    .is_ok();
17543
17544                anyhow::Ok(Navigated::from_bool(opened))
17545            } else if num_locations == 0 {
17546                // If there is one url or file, open it directly
17547                match first_url_or_file {
17548                    Some(Either::Left(url)) => {
17549                        cx.update(|window, cx| {
17550                            if parse_zed_link(&url, cx).is_some() {
17551                                window
17552                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17553                            } else {
17554                                cx.open_url(&url);
17555                            }
17556                        })?;
17557                        Ok(Navigated::Yes)
17558                    }
17559                    Some(Either::Right(path)) => {
17560                        // TODO(andrew): respect preview tab settings
17561                        //               `enable_keep_preview_on_code_navigation` and
17562                        //               `enable_preview_file_from_code_navigation`
17563                        let Some(workspace) = workspace else {
17564                            return Ok(Navigated::No);
17565                        };
17566                        workspace
17567                            .update_in(cx, |workspace, window, cx| {
17568                                workspace.open_resolved_path(path, window, cx)
17569                            })?
17570                            .await?;
17571                        Ok(Navigated::Yes)
17572                    }
17573                    None => Ok(Navigated::No),
17574                }
17575            } else {
17576                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17577                let target_range = target_ranges.first().unwrap().clone();
17578
17579                editor.update_in(cx, |editor, window, cx| {
17580                    let range = target_range.to_point(target_buffer.read(cx));
17581                    let range = editor.range_for_match(&range);
17582                    let range = collapse_multiline_range(range);
17583
17584                    if !split
17585                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17586                    {
17587                        editor.go_to_singleton_buffer_range(range, window, cx);
17588                    } else {
17589                        let Some(workspace) = workspace else {
17590                            return Navigated::No;
17591                        };
17592                        let pane = workspace.read(cx).active_pane().clone();
17593                        window.defer(cx, move |window, cx| {
17594                            let target_editor: Entity<Self> =
17595                                workspace.update(cx, |workspace, cx| {
17596                                    let pane = if split {
17597                                        workspace.adjacent_pane(window, cx)
17598                                    } else {
17599                                        workspace.active_pane().clone()
17600                                    };
17601
17602                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17603                                    let keep_old_preview = preview_tabs_settings
17604                                        .enable_keep_preview_on_code_navigation;
17605                                    let allow_new_preview = preview_tabs_settings
17606                                        .enable_preview_file_from_code_navigation;
17607
17608                                    workspace.open_project_item(
17609                                        pane,
17610                                        target_buffer.clone(),
17611                                        true,
17612                                        true,
17613                                        keep_old_preview,
17614                                        allow_new_preview,
17615                                        window,
17616                                        cx,
17617                                    )
17618                                });
17619                            target_editor.update(cx, |target_editor, cx| {
17620                                // When selecting a definition in a different buffer, disable the nav history
17621                                // to avoid creating a history entry at the previous cursor location.
17622                                pane.update(cx, |pane, _| pane.disable_history());
17623                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17624                                pane.update(cx, |pane, _| pane.enable_history());
17625                            });
17626                        });
17627                    }
17628                    Navigated::Yes
17629                })
17630            }
17631        })
17632    }
17633
17634    fn compute_target_location(
17635        &self,
17636        lsp_location: lsp::Location,
17637        server_id: LanguageServerId,
17638        window: &mut Window,
17639        cx: &mut Context<Self>,
17640    ) -> Task<anyhow::Result<Option<Location>>> {
17641        let Some(project) = self.project.clone() else {
17642            return Task::ready(Ok(None));
17643        };
17644
17645        cx.spawn_in(window, async move |editor, cx| {
17646            let location_task = editor.update(cx, |_, cx| {
17647                project.update(cx, |project, cx| {
17648                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17649                })
17650            })?;
17651            let location = Some({
17652                let target_buffer_handle = location_task.await.context("open local buffer")?;
17653                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17654                    let target_start = target_buffer
17655                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17656                    let target_end = target_buffer
17657                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17658                    target_buffer.anchor_after(target_start)
17659                        ..target_buffer.anchor_before(target_end)
17660                });
17661                Location {
17662                    buffer: target_buffer_handle,
17663                    range,
17664                }
17665            });
17666            Ok(location)
17667        })
17668    }
17669
17670    fn go_to_next_reference(
17671        &mut self,
17672        _: &GoToNextReference,
17673        window: &mut Window,
17674        cx: &mut Context<Self>,
17675    ) {
17676        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17677        if let Some(task) = task {
17678            task.detach();
17679        };
17680    }
17681
17682    fn go_to_prev_reference(
17683        &mut self,
17684        _: &GoToPreviousReference,
17685        window: &mut Window,
17686        cx: &mut Context<Self>,
17687    ) {
17688        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17689        if let Some(task) = task {
17690            task.detach();
17691        };
17692    }
17693
17694    pub fn go_to_reference_before_or_after_position(
17695        &mut self,
17696        direction: Direction,
17697        count: usize,
17698        window: &mut Window,
17699        cx: &mut Context<Self>,
17700    ) -> Option<Task<Result<()>>> {
17701        let selection = self.selections.newest_anchor();
17702        let head = selection.head();
17703
17704        let multi_buffer = self.buffer.read(cx);
17705
17706        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17707        let workspace = self.workspace()?;
17708        let project = workspace.read(cx).project().clone();
17709        let references =
17710            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17711        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17712            let Some(locations) = references.await? else {
17713                return Ok(());
17714            };
17715
17716            if locations.is_empty() {
17717                // totally normal - the cursor may be on something which is not
17718                // a symbol (e.g. a keyword)
17719                log::info!("no references found under cursor");
17720                return Ok(());
17721            }
17722
17723            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17724
17725            let (locations, current_location_index) =
17726                multi_buffer.update(cx, |multi_buffer, cx| {
17727                    let mut locations = locations
17728                        .into_iter()
17729                        .filter_map(|loc| {
17730                            let start = multi_buffer.buffer_anchor_to_anchor(
17731                                &loc.buffer,
17732                                loc.range.start,
17733                                cx,
17734                            )?;
17735                            let end = multi_buffer.buffer_anchor_to_anchor(
17736                                &loc.buffer,
17737                                loc.range.end,
17738                                cx,
17739                            )?;
17740                            Some(start..end)
17741                        })
17742                        .collect::<Vec<_>>();
17743
17744                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17745                    // There is an O(n) implementation, but given this list will be
17746                    // small (usually <100 items), the extra O(log(n)) factor isn't
17747                    // worth the (surprisingly large amount of) extra complexity.
17748                    locations
17749                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17750
17751                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17752
17753                    let current_location_index = locations.iter().position(|loc| {
17754                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17755                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17756                    });
17757
17758                    (locations, current_location_index)
17759                });
17760
17761            let Some(current_location_index) = current_location_index else {
17762                // This indicates something has gone wrong, because we already
17763                // handle the "no references" case above
17764                log::error!(
17765                    "failed to find current reference under cursor. Total references: {}",
17766                    locations.len()
17767                );
17768                return Ok(());
17769            };
17770
17771            let destination_location_index = match direction {
17772                Direction::Next => (current_location_index + count) % locations.len(),
17773                Direction::Prev => {
17774                    (current_location_index + locations.len() - count % locations.len())
17775                        % locations.len()
17776                }
17777            };
17778
17779            // TODO(cameron): is this needed?
17780            // the thinking is to avoid "jumping to the current location" (avoid
17781            // polluting "jumplist" in vim terms)
17782            if current_location_index == destination_location_index {
17783                return Ok(());
17784            }
17785
17786            let Range { start, end } = locations[destination_location_index];
17787
17788            editor.update_in(cx, |editor, window, cx| {
17789                let effects = SelectionEffects::default();
17790
17791                editor.unfold_ranges(&[start..end], false, false, cx);
17792                editor.change_selections(effects, window, cx, |s| {
17793                    s.select_ranges([start..start]);
17794                });
17795            })?;
17796
17797            Ok(())
17798        }))
17799    }
17800
17801    pub fn find_all_references(
17802        &mut self,
17803        action: &FindAllReferences,
17804        window: &mut Window,
17805        cx: &mut Context<Self>,
17806    ) -> Option<Task<Result<Navigated>>> {
17807        let always_open_multibuffer = action.always_open_multibuffer;
17808        let selection = self.selections.newest_anchor();
17809        let multi_buffer = self.buffer.read(cx);
17810        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17811        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17812        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17813        let head = selection_offset.head();
17814
17815        let head_anchor = multi_buffer_snapshot.anchor_at(
17816            head,
17817            if head < selection_offset.tail() {
17818                Bias::Right
17819            } else {
17820                Bias::Left
17821            },
17822        );
17823
17824        match self
17825            .find_all_references_task_sources
17826            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17827        {
17828            Ok(_) => {
17829                log::info!(
17830                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17831                );
17832                return None;
17833            }
17834            Err(i) => {
17835                self.find_all_references_task_sources.insert(i, head_anchor);
17836            }
17837        }
17838
17839        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17840        let workspace = self.workspace()?;
17841        let project = workspace.read(cx).project().clone();
17842        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17843        Some(cx.spawn_in(window, async move |editor, cx| {
17844            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17845                if let Ok(i) = editor
17846                    .find_all_references_task_sources
17847                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17848                {
17849                    editor.find_all_references_task_sources.remove(i);
17850                }
17851            });
17852
17853            let Some(locations) = references.await? else {
17854                return anyhow::Ok(Navigated::No);
17855            };
17856            let mut locations = cx.update(|_, cx| {
17857                locations
17858                    .into_iter()
17859                    .map(|location| {
17860                        let buffer = location.buffer.read(cx);
17861                        (location.buffer, location.range.to_point(buffer))
17862                    })
17863                    // if special-casing the single-match case, remove ranges
17864                    // that intersect current selection
17865                    .filter(|(location_buffer, location)| {
17866                        if always_open_multibuffer || &buffer != location_buffer {
17867                            return true;
17868                        }
17869
17870                        !location.contains_inclusive(&selection_point.range())
17871                    })
17872                    .into_group_map()
17873            })?;
17874            if locations.is_empty() {
17875                return anyhow::Ok(Navigated::No);
17876            }
17877            for ranges in locations.values_mut() {
17878                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17879                ranges.dedup();
17880            }
17881            let mut num_locations = 0;
17882            for ranges in locations.values_mut() {
17883                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17884                ranges.dedup();
17885                num_locations += ranges.len();
17886            }
17887
17888            if num_locations == 1 && !always_open_multibuffer {
17889                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17890                let target_range = target_ranges.first().unwrap().clone();
17891
17892                return editor.update_in(cx, |editor, window, cx| {
17893                    let range = target_range.to_point(target_buffer.read(cx));
17894                    let range = editor.range_for_match(&range);
17895                    let range = range.start..range.start;
17896
17897                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17898                        editor.go_to_singleton_buffer_range(range, window, cx);
17899                    } else {
17900                        let pane = workspace.read(cx).active_pane().clone();
17901                        window.defer(cx, move |window, cx| {
17902                            let target_editor: Entity<Self> =
17903                                workspace.update(cx, |workspace, cx| {
17904                                    let pane = workspace.active_pane().clone();
17905
17906                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17907                                    let keep_old_preview = preview_tabs_settings
17908                                        .enable_keep_preview_on_code_navigation;
17909                                    let allow_new_preview = preview_tabs_settings
17910                                        .enable_preview_file_from_code_navigation;
17911
17912                                    workspace.open_project_item(
17913                                        pane,
17914                                        target_buffer.clone(),
17915                                        true,
17916                                        true,
17917                                        keep_old_preview,
17918                                        allow_new_preview,
17919                                        window,
17920                                        cx,
17921                                    )
17922                                });
17923                            target_editor.update(cx, |target_editor, cx| {
17924                                // When selecting a definition in a different buffer, disable the nav history
17925                                // to avoid creating a history entry at the previous cursor location.
17926                                pane.update(cx, |pane, _| pane.disable_history());
17927                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17928                                pane.update(cx, |pane, _| pane.enable_history());
17929                            });
17930                        });
17931                    }
17932                    Navigated::No
17933                });
17934            }
17935
17936            workspace.update_in(cx, |workspace, window, cx| {
17937                let target = locations
17938                    .iter()
17939                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17940                    .map(|(buffer, location)| {
17941                        buffer
17942                            .read(cx)
17943                            .text_for_range(location.clone())
17944                            .collect::<String>()
17945                    })
17946                    .filter(|text| !text.contains('\n'))
17947                    .unique()
17948                    .take(3)
17949                    .join(", ");
17950                let title = if target.is_empty() {
17951                    "References".to_owned()
17952                } else {
17953                    format!("References to {target}")
17954                };
17955                let allow_preview = PreviewTabsSettings::get_global(cx)
17956                    .enable_preview_multibuffer_from_code_navigation;
17957                Self::open_locations_in_multibuffer(
17958                    workspace,
17959                    locations,
17960                    title,
17961                    false,
17962                    allow_preview,
17963                    MultibufferSelectionMode::First,
17964                    window,
17965                    cx,
17966                );
17967                Navigated::Yes
17968            })
17969        }))
17970    }
17971
17972    /// Opens a multibuffer with the given project locations in it.
17973    pub fn open_locations_in_multibuffer(
17974        workspace: &mut Workspace,
17975        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17976        title: String,
17977        split: bool,
17978        allow_preview: bool,
17979        multibuffer_selection_mode: MultibufferSelectionMode,
17980        window: &mut Window,
17981        cx: &mut Context<Workspace>,
17982    ) {
17983        if locations.is_empty() {
17984            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17985            return;
17986        }
17987
17988        let capability = workspace.project().read(cx).capability();
17989        let mut ranges = <Vec<Range<Anchor>>>::new();
17990
17991        // a key to find existing multibuffer editors with the same set of locations
17992        // to prevent us from opening more and more multibuffer tabs for searches and the like
17993        let mut key = (title.clone(), vec![]);
17994        let excerpt_buffer = cx.new(|cx| {
17995            let key = &mut key.1;
17996            let mut multibuffer = MultiBuffer::new(capability);
17997            for (buffer, mut ranges_for_buffer) in locations {
17998                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17999                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18000                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18001                    PathKey::for_buffer(&buffer, cx),
18002                    buffer.clone(),
18003                    ranges_for_buffer,
18004                    multibuffer_context_lines(cx),
18005                    cx,
18006                );
18007                ranges.extend(new_ranges)
18008            }
18009
18010            multibuffer.with_title(title)
18011        });
18012        let existing = workspace.active_pane().update(cx, |pane, cx| {
18013            pane.items()
18014                .filter_map(|item| item.downcast::<Editor>())
18015                .find(|editor| {
18016                    editor
18017                        .read(cx)
18018                        .lookup_key
18019                        .as_ref()
18020                        .and_then(|it| {
18021                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18022                        })
18023                        .is_some_and(|it| *it == key)
18024                })
18025        });
18026        let was_existing = existing.is_some();
18027        let editor = existing.unwrap_or_else(|| {
18028            cx.new(|cx| {
18029                let mut editor = Editor::for_multibuffer(
18030                    excerpt_buffer,
18031                    Some(workspace.project().clone()),
18032                    window,
18033                    cx,
18034                );
18035                editor.lookup_key = Some(Box::new(key));
18036                editor
18037            })
18038        });
18039        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18040            MultibufferSelectionMode::First => {
18041                if let Some(first_range) = ranges.first() {
18042                    editor.change_selections(
18043                        SelectionEffects::no_scroll(),
18044                        window,
18045                        cx,
18046                        |selections| {
18047                            selections.clear_disjoint();
18048                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18049                        },
18050                    );
18051                }
18052                editor.highlight_background::<Self>(
18053                    &ranges,
18054                    |_, theme| theme.colors().editor_highlighted_line_background,
18055                    cx,
18056                );
18057            }
18058            MultibufferSelectionMode::All => {
18059                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18060                    selections.clear_disjoint();
18061                    selections.select_anchor_ranges(ranges);
18062                });
18063            }
18064        });
18065
18066        let item = Box::new(editor);
18067
18068        let pane = if split {
18069            workspace.adjacent_pane(window, cx)
18070        } else {
18071            workspace.active_pane().clone()
18072        };
18073        let activate_pane = split;
18074
18075        let mut destination_index = None;
18076        pane.update(cx, |pane, cx| {
18077            if allow_preview && !was_existing {
18078                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18079            }
18080            if was_existing && !allow_preview {
18081                pane.unpreview_item_if_preview(item.item_id());
18082            }
18083            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18084        });
18085    }
18086
18087    pub fn rename(
18088        &mut self,
18089        _: &Rename,
18090        window: &mut Window,
18091        cx: &mut Context<Self>,
18092    ) -> Option<Task<Result<()>>> {
18093        use language::ToOffset as _;
18094
18095        let provider = self.semantics_provider.clone()?;
18096        let selection = self.selections.newest_anchor().clone();
18097        let (cursor_buffer, cursor_buffer_position) = self
18098            .buffer
18099            .read(cx)
18100            .text_anchor_for_position(selection.head(), cx)?;
18101        let (tail_buffer, cursor_buffer_position_end) = self
18102            .buffer
18103            .read(cx)
18104            .text_anchor_for_position(selection.tail(), cx)?;
18105        if tail_buffer != cursor_buffer {
18106            return None;
18107        }
18108
18109        let snapshot = cursor_buffer.read(cx).snapshot();
18110        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18111        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18112        let prepare_rename = provider
18113            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18114            .unwrap_or_else(|| Task::ready(Ok(None)));
18115        drop(snapshot);
18116
18117        Some(cx.spawn_in(window, async move |this, cx| {
18118            let rename_range = if let Some(range) = prepare_rename.await? {
18119                Some(range)
18120            } else {
18121                this.update(cx, |this, cx| {
18122                    let buffer = this.buffer.read(cx).snapshot(cx);
18123                    let mut buffer_highlights = this
18124                        .document_highlights_for_position(selection.head(), &buffer)
18125                        .filter(|highlight| {
18126                            highlight.start.excerpt_id == selection.head().excerpt_id
18127                                && highlight.end.excerpt_id == selection.head().excerpt_id
18128                        });
18129                    buffer_highlights
18130                        .next()
18131                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18132                })?
18133            };
18134            if let Some(rename_range) = rename_range {
18135                this.update_in(cx, |this, window, cx| {
18136                    let snapshot = cursor_buffer.read(cx).snapshot();
18137                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18138                    let cursor_offset_in_rename_range =
18139                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18140                    let cursor_offset_in_rename_range_end =
18141                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18142
18143                    this.take_rename(false, window, cx);
18144                    let buffer = this.buffer.read(cx).read(cx);
18145                    let cursor_offset = selection.head().to_offset(&buffer);
18146                    let rename_start =
18147                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18148                    let rename_end = rename_start + rename_buffer_range.len();
18149                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18150                    let mut old_highlight_id = None;
18151                    let old_name: Arc<str> = buffer
18152                        .chunks(rename_start..rename_end, true)
18153                        .map(|chunk| {
18154                            if old_highlight_id.is_none() {
18155                                old_highlight_id = chunk.syntax_highlight_id;
18156                            }
18157                            chunk.text
18158                        })
18159                        .collect::<String>()
18160                        .into();
18161
18162                    drop(buffer);
18163
18164                    // Position the selection in the rename editor so that it matches the current selection.
18165                    this.show_local_selections = false;
18166                    let rename_editor = cx.new(|cx| {
18167                        let mut editor = Editor::single_line(window, cx);
18168                        editor.buffer.update(cx, |buffer, cx| {
18169                            buffer.edit(
18170                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18171                                None,
18172                                cx,
18173                            )
18174                        });
18175                        let cursor_offset_in_rename_range =
18176                            MultiBufferOffset(cursor_offset_in_rename_range);
18177                        let cursor_offset_in_rename_range_end =
18178                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18179                        let rename_selection_range = match cursor_offset_in_rename_range
18180                            .cmp(&cursor_offset_in_rename_range_end)
18181                        {
18182                            Ordering::Equal => {
18183                                editor.select_all(&SelectAll, window, cx);
18184                                return editor;
18185                            }
18186                            Ordering::Less => {
18187                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18188                            }
18189                            Ordering::Greater => {
18190                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18191                            }
18192                        };
18193                        if rename_selection_range.end.0 > old_name.len() {
18194                            editor.select_all(&SelectAll, window, cx);
18195                        } else {
18196                            editor.change_selections(Default::default(), window, cx, |s| {
18197                                s.select_ranges([rename_selection_range]);
18198                            });
18199                        }
18200                        editor
18201                    });
18202                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18203                        if e == &EditorEvent::Focused {
18204                            cx.emit(EditorEvent::FocusedIn)
18205                        }
18206                    })
18207                    .detach();
18208
18209                    let write_highlights =
18210                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18211                    let read_highlights =
18212                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18213                    let ranges = write_highlights
18214                        .iter()
18215                        .flat_map(|(_, ranges)| ranges.iter())
18216                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18217                        .cloned()
18218                        .collect();
18219
18220                    this.highlight_text::<Rename>(
18221                        ranges,
18222                        HighlightStyle {
18223                            fade_out: Some(0.6),
18224                            ..Default::default()
18225                        },
18226                        cx,
18227                    );
18228                    let rename_focus_handle = rename_editor.focus_handle(cx);
18229                    window.focus(&rename_focus_handle, cx);
18230                    let block_id = this.insert_blocks(
18231                        [BlockProperties {
18232                            style: BlockStyle::Flex,
18233                            placement: BlockPlacement::Below(range.start),
18234                            height: Some(1),
18235                            render: Arc::new({
18236                                let rename_editor = rename_editor.clone();
18237                                move |cx: &mut BlockContext| {
18238                                    let mut text_style = cx.editor_style.text.clone();
18239                                    if let Some(highlight_style) = old_highlight_id
18240                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18241                                    {
18242                                        text_style = text_style.highlight(highlight_style);
18243                                    }
18244                                    div()
18245                                        .block_mouse_except_scroll()
18246                                        .pl(cx.anchor_x)
18247                                        .child(EditorElement::new(
18248                                            &rename_editor,
18249                                            EditorStyle {
18250                                                background: cx.theme().system().transparent,
18251                                                local_player: cx.editor_style.local_player,
18252                                                text: text_style,
18253                                                scrollbar_width: cx.editor_style.scrollbar_width,
18254                                                syntax: cx.editor_style.syntax.clone(),
18255                                                status: cx.editor_style.status.clone(),
18256                                                inlay_hints_style: HighlightStyle {
18257                                                    font_weight: Some(FontWeight::BOLD),
18258                                                    ..make_inlay_hints_style(cx.app)
18259                                                },
18260                                                edit_prediction_styles: make_suggestion_styles(
18261                                                    cx.app,
18262                                                ),
18263                                                ..EditorStyle::default()
18264                                            },
18265                                        ))
18266                                        .into_any_element()
18267                                }
18268                            }),
18269                            priority: 0,
18270                        }],
18271                        Some(Autoscroll::fit()),
18272                        cx,
18273                    )[0];
18274                    this.pending_rename = Some(RenameState {
18275                        range,
18276                        old_name,
18277                        editor: rename_editor,
18278                        block_id,
18279                    });
18280                })?;
18281            }
18282
18283            Ok(())
18284        }))
18285    }
18286
18287    pub fn confirm_rename(
18288        &mut self,
18289        _: &ConfirmRename,
18290        window: &mut Window,
18291        cx: &mut Context<Self>,
18292    ) -> Option<Task<Result<()>>> {
18293        let rename = self.take_rename(false, window, cx)?;
18294        let workspace = self.workspace()?.downgrade();
18295        let (buffer, start) = self
18296            .buffer
18297            .read(cx)
18298            .text_anchor_for_position(rename.range.start, cx)?;
18299        let (end_buffer, _) = self
18300            .buffer
18301            .read(cx)
18302            .text_anchor_for_position(rename.range.end, cx)?;
18303        if buffer != end_buffer {
18304            return None;
18305        }
18306
18307        let old_name = rename.old_name;
18308        let new_name = rename.editor.read(cx).text(cx);
18309
18310        let rename = self.semantics_provider.as_ref()?.perform_rename(
18311            &buffer,
18312            start,
18313            new_name.clone(),
18314            cx,
18315        )?;
18316
18317        Some(cx.spawn_in(window, async move |editor, cx| {
18318            let project_transaction = rename.await?;
18319            Self::open_project_transaction(
18320                &editor,
18321                workspace,
18322                project_transaction,
18323                format!("Rename: {}{}", old_name, new_name),
18324                cx,
18325            )
18326            .await?;
18327
18328            editor.update(cx, |editor, cx| {
18329                editor.refresh_document_highlights(cx);
18330            })?;
18331            Ok(())
18332        }))
18333    }
18334
18335    fn take_rename(
18336        &mut self,
18337        moving_cursor: bool,
18338        window: &mut Window,
18339        cx: &mut Context<Self>,
18340    ) -> Option<RenameState> {
18341        let rename = self.pending_rename.take()?;
18342        if rename.editor.focus_handle(cx).is_focused(window) {
18343            window.focus(&self.focus_handle, cx);
18344        }
18345
18346        self.remove_blocks(
18347            [rename.block_id].into_iter().collect(),
18348            Some(Autoscroll::fit()),
18349            cx,
18350        );
18351        self.clear_highlights::<Rename>(cx);
18352        self.show_local_selections = true;
18353
18354        if moving_cursor {
18355            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18356                editor
18357                    .selections
18358                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18359                    .head()
18360            });
18361
18362            // Update the selection to match the position of the selection inside
18363            // the rename editor.
18364            let snapshot = self.buffer.read(cx).read(cx);
18365            let rename_range = rename.range.to_offset(&snapshot);
18366            let cursor_in_editor = snapshot
18367                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18368                .min(rename_range.end);
18369            drop(snapshot);
18370
18371            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18372                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18373            });
18374        } else {
18375            self.refresh_document_highlights(cx);
18376        }
18377
18378        Some(rename)
18379    }
18380
18381    pub fn pending_rename(&self) -> Option<&RenameState> {
18382        self.pending_rename.as_ref()
18383    }
18384
18385    fn format(
18386        &mut self,
18387        _: &Format,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) -> Option<Task<Result<()>>> {
18391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18392
18393        let project = match &self.project {
18394            Some(project) => project.clone(),
18395            None => return None,
18396        };
18397
18398        Some(self.perform_format(
18399            project,
18400            FormatTrigger::Manual,
18401            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18402            window,
18403            cx,
18404        ))
18405    }
18406
18407    fn format_selections(
18408        &mut self,
18409        _: &FormatSelections,
18410        window: &mut Window,
18411        cx: &mut Context<Self>,
18412    ) -> Option<Task<Result<()>>> {
18413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18414
18415        let project = match &self.project {
18416            Some(project) => project.clone(),
18417            None => return None,
18418        };
18419
18420        let ranges = self
18421            .selections
18422            .all_adjusted(&self.display_snapshot(cx))
18423            .into_iter()
18424            .map(|selection| selection.range())
18425            .collect_vec();
18426
18427        Some(self.perform_format(
18428            project,
18429            FormatTrigger::Manual,
18430            FormatTarget::Ranges(ranges),
18431            window,
18432            cx,
18433        ))
18434    }
18435
18436    fn perform_format(
18437        &mut self,
18438        project: Entity<Project>,
18439        trigger: FormatTrigger,
18440        target: FormatTarget,
18441        window: &mut Window,
18442        cx: &mut Context<Self>,
18443    ) -> Task<Result<()>> {
18444        let buffer = self.buffer.clone();
18445        let (buffers, target) = match target {
18446            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18447            FormatTarget::Ranges(selection_ranges) => {
18448                let multi_buffer = buffer.read(cx);
18449                let snapshot = multi_buffer.read(cx);
18450                let mut buffers = HashSet::default();
18451                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18452                    BTreeMap::new();
18453                for selection_range in selection_ranges {
18454                    for (buffer, buffer_range, _) in
18455                        snapshot.range_to_buffer_ranges(selection_range)
18456                    {
18457                        let buffer_id = buffer.remote_id();
18458                        let start = buffer.anchor_before(buffer_range.start);
18459                        let end = buffer.anchor_after(buffer_range.end);
18460                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18461                        buffer_id_to_ranges
18462                            .entry(buffer_id)
18463                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18464                            .or_insert_with(|| vec![start..end]);
18465                    }
18466                }
18467                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18468            }
18469        };
18470
18471        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18472        let selections_prev = transaction_id_prev
18473            .and_then(|transaction_id_prev| {
18474                // default to selections as they were after the last edit, if we have them,
18475                // instead of how they are now.
18476                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18477                // will take you back to where you made the last edit, instead of staying where you scrolled
18478                self.selection_history
18479                    .transaction(transaction_id_prev)
18480                    .map(|t| t.0.clone())
18481            })
18482            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18483
18484        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18485        let format = project.update(cx, |project, cx| {
18486            project.format(buffers, target, true, trigger, cx)
18487        });
18488
18489        cx.spawn_in(window, async move |editor, cx| {
18490            let transaction = futures::select_biased! {
18491                transaction = format.log_err().fuse() => transaction,
18492                () = timeout => {
18493                    log::warn!("timed out waiting for formatting");
18494                    None
18495                }
18496            };
18497
18498            buffer.update(cx, |buffer, cx| {
18499                if let Some(transaction) = transaction
18500                    && !buffer.is_singleton()
18501                {
18502                    buffer.push_transaction(&transaction.0, cx);
18503                }
18504                cx.notify();
18505            });
18506
18507            if let Some(transaction_id_now) =
18508                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18509            {
18510                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18511                if has_new_transaction {
18512                    editor
18513                        .update(cx, |editor, _| {
18514                            editor
18515                                .selection_history
18516                                .insert_transaction(transaction_id_now, selections_prev);
18517                        })
18518                        .ok();
18519                }
18520            }
18521
18522            Ok(())
18523        })
18524    }
18525
18526    fn organize_imports(
18527        &mut self,
18528        _: &OrganizeImports,
18529        window: &mut Window,
18530        cx: &mut Context<Self>,
18531    ) -> Option<Task<Result<()>>> {
18532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18533        let project = match &self.project {
18534            Some(project) => project.clone(),
18535            None => return None,
18536        };
18537        Some(self.perform_code_action_kind(
18538            project,
18539            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18540            window,
18541            cx,
18542        ))
18543    }
18544
18545    fn perform_code_action_kind(
18546        &mut self,
18547        project: Entity<Project>,
18548        kind: CodeActionKind,
18549        window: &mut Window,
18550        cx: &mut Context<Self>,
18551    ) -> Task<Result<()>> {
18552        let buffer = self.buffer.clone();
18553        let buffers = buffer.read(cx).all_buffers();
18554        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18555        let apply_action = project.update(cx, |project, cx| {
18556            project.apply_code_action_kind(buffers, kind, true, cx)
18557        });
18558        cx.spawn_in(window, async move |_, cx| {
18559            let transaction = futures::select_biased! {
18560                () = timeout => {
18561                    log::warn!("timed out waiting for executing code action");
18562                    None
18563                }
18564                transaction = apply_action.log_err().fuse() => transaction,
18565            };
18566            buffer.update(cx, |buffer, cx| {
18567                // check if we need this
18568                if let Some(transaction) = transaction
18569                    && !buffer.is_singleton()
18570                {
18571                    buffer.push_transaction(&transaction.0, cx);
18572                }
18573                cx.notify();
18574            });
18575            Ok(())
18576        })
18577    }
18578
18579    pub fn restart_language_server(
18580        &mut self,
18581        _: &RestartLanguageServer,
18582        _: &mut Window,
18583        cx: &mut Context<Self>,
18584    ) {
18585        if let Some(project) = self.project.clone() {
18586            self.buffer.update(cx, |multi_buffer, cx| {
18587                project.update(cx, |project, cx| {
18588                    project.restart_language_servers_for_buffers(
18589                        multi_buffer.all_buffers().into_iter().collect(),
18590                        HashSet::default(),
18591                        cx,
18592                    );
18593                });
18594            })
18595        }
18596    }
18597
18598    pub fn stop_language_server(
18599        &mut self,
18600        _: &StopLanguageServer,
18601        _: &mut Window,
18602        cx: &mut Context<Self>,
18603    ) {
18604        if let Some(project) = self.project.clone() {
18605            self.buffer.update(cx, |multi_buffer, cx| {
18606                project.update(cx, |project, cx| {
18607                    project.stop_language_servers_for_buffers(
18608                        multi_buffer.all_buffers().into_iter().collect(),
18609                        HashSet::default(),
18610                        cx,
18611                    );
18612                });
18613            });
18614            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18615        }
18616    }
18617
18618    fn cancel_language_server_work(
18619        workspace: &mut Workspace,
18620        _: &actions::CancelLanguageServerWork,
18621        _: &mut Window,
18622        cx: &mut Context<Workspace>,
18623    ) {
18624        let project = workspace.project();
18625        let buffers = workspace
18626            .active_item(cx)
18627            .and_then(|item| item.act_as::<Editor>(cx))
18628            .map_or(HashSet::default(), |editor| {
18629                editor.read(cx).buffer.read(cx).all_buffers()
18630            });
18631        project.update(cx, |project, cx| {
18632            project.cancel_language_server_work_for_buffers(buffers, cx);
18633        });
18634    }
18635
18636    fn show_character_palette(
18637        &mut self,
18638        _: &ShowCharacterPalette,
18639        window: &mut Window,
18640        _: &mut Context<Self>,
18641    ) {
18642        window.show_character_palette();
18643    }
18644
18645    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18646        if !self.diagnostics_enabled() {
18647            return;
18648        }
18649
18650        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18651            let buffer = self.buffer.read(cx).snapshot(cx);
18652            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18653            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18654            let is_valid = buffer
18655                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18656                .any(|entry| {
18657                    entry.diagnostic.is_primary
18658                        && !entry.range.is_empty()
18659                        && entry.range.start == primary_range_start
18660                        && entry.diagnostic.message == active_diagnostics.active_message
18661                });
18662
18663            if !is_valid {
18664                self.dismiss_diagnostics(cx);
18665            }
18666        }
18667    }
18668
18669    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18670        match &self.active_diagnostics {
18671            ActiveDiagnostic::Group(group) => Some(group),
18672            _ => None,
18673        }
18674    }
18675
18676    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18677        if !self.diagnostics_enabled() {
18678            return;
18679        }
18680        self.dismiss_diagnostics(cx);
18681        self.active_diagnostics = ActiveDiagnostic::All;
18682    }
18683
18684    fn activate_diagnostics(
18685        &mut self,
18686        buffer_id: BufferId,
18687        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18688        window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) {
18691        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18692            return;
18693        }
18694        self.dismiss_diagnostics(cx);
18695        let snapshot = self.snapshot(window, cx);
18696        let buffer = self.buffer.read(cx).snapshot(cx);
18697        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18698            return;
18699        };
18700
18701        let diagnostic_group = buffer
18702            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18703            .collect::<Vec<_>>();
18704
18705        let language_registry = self
18706            .project()
18707            .map(|project| project.read(cx).languages().clone());
18708
18709        let blocks = renderer.render_group(
18710            diagnostic_group,
18711            buffer_id,
18712            snapshot,
18713            cx.weak_entity(),
18714            language_registry,
18715            cx,
18716        );
18717
18718        let blocks = self.display_map.update(cx, |display_map, cx| {
18719            display_map.insert_blocks(blocks, cx).into_iter().collect()
18720        });
18721        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18722            active_range: buffer.anchor_before(diagnostic.range.start)
18723                ..buffer.anchor_after(diagnostic.range.end),
18724            active_message: diagnostic.diagnostic.message.clone(),
18725            group_id: diagnostic.diagnostic.group_id,
18726            blocks,
18727        });
18728        cx.notify();
18729    }
18730
18731    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18732        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18733            return;
18734        };
18735
18736        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18737        if let ActiveDiagnostic::Group(group) = prev {
18738            self.display_map.update(cx, |display_map, cx| {
18739                display_map.remove_blocks(group.blocks, cx);
18740            });
18741            cx.notify();
18742        }
18743    }
18744
18745    /// Disable inline diagnostics rendering for this editor.
18746    pub fn disable_inline_diagnostics(&mut self) {
18747        self.inline_diagnostics_enabled = false;
18748        self.inline_diagnostics_update = Task::ready(());
18749        self.inline_diagnostics.clear();
18750    }
18751
18752    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18753        self.diagnostics_enabled = false;
18754        self.dismiss_diagnostics(cx);
18755        self.inline_diagnostics_update = Task::ready(());
18756        self.inline_diagnostics.clear();
18757    }
18758
18759    pub fn disable_word_completions(&mut self) {
18760        self.word_completions_enabled = false;
18761    }
18762
18763    pub fn diagnostics_enabled(&self) -> bool {
18764        self.diagnostics_enabled && self.mode.is_full()
18765    }
18766
18767    pub fn inline_diagnostics_enabled(&self) -> bool {
18768        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18769    }
18770
18771    pub fn show_inline_diagnostics(&self) -> bool {
18772        self.show_inline_diagnostics
18773    }
18774
18775    pub fn toggle_inline_diagnostics(
18776        &mut self,
18777        _: &ToggleInlineDiagnostics,
18778        window: &mut Window,
18779        cx: &mut Context<Editor>,
18780    ) {
18781        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18782        self.refresh_inline_diagnostics(false, window, cx);
18783    }
18784
18785    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18786        self.diagnostics_max_severity = severity;
18787        self.display_map.update(cx, |display_map, _| {
18788            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18789        });
18790    }
18791
18792    pub fn toggle_diagnostics(
18793        &mut self,
18794        _: &ToggleDiagnostics,
18795        window: &mut Window,
18796        cx: &mut Context<Editor>,
18797    ) {
18798        if !self.diagnostics_enabled() {
18799            return;
18800        }
18801
18802        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18803            EditorSettings::get_global(cx)
18804                .diagnostics_max_severity
18805                .filter(|severity| severity != &DiagnosticSeverity::Off)
18806                .unwrap_or(DiagnosticSeverity::Hint)
18807        } else {
18808            DiagnosticSeverity::Off
18809        };
18810        self.set_max_diagnostics_severity(new_severity, cx);
18811        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18812            self.active_diagnostics = ActiveDiagnostic::None;
18813            self.inline_diagnostics_update = Task::ready(());
18814            self.inline_diagnostics.clear();
18815        } else {
18816            self.refresh_inline_diagnostics(false, window, cx);
18817        }
18818
18819        cx.notify();
18820    }
18821
18822    pub fn toggle_minimap(
18823        &mut self,
18824        _: &ToggleMinimap,
18825        window: &mut Window,
18826        cx: &mut Context<Editor>,
18827    ) {
18828        if self.supports_minimap(cx) {
18829            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18830        }
18831    }
18832
18833    fn refresh_inline_diagnostics(
18834        &mut self,
18835        debounce: bool,
18836        window: &mut Window,
18837        cx: &mut Context<Self>,
18838    ) {
18839        let max_severity = ProjectSettings::get_global(cx)
18840            .diagnostics
18841            .inline
18842            .max_severity
18843            .unwrap_or(self.diagnostics_max_severity);
18844
18845        if !self.inline_diagnostics_enabled()
18846            || !self.diagnostics_enabled()
18847            || !self.show_inline_diagnostics
18848            || max_severity == DiagnosticSeverity::Off
18849        {
18850            self.inline_diagnostics_update = Task::ready(());
18851            self.inline_diagnostics.clear();
18852            return;
18853        }
18854
18855        let debounce_ms = ProjectSettings::get_global(cx)
18856            .diagnostics
18857            .inline
18858            .update_debounce_ms;
18859        let debounce = if debounce && debounce_ms > 0 {
18860            Some(Duration::from_millis(debounce_ms))
18861        } else {
18862            None
18863        };
18864        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18865            if let Some(debounce) = debounce {
18866                cx.background_executor().timer(debounce).await;
18867            }
18868            let Some(snapshot) = editor.upgrade().map(|editor| {
18869                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18870            }) else {
18871                return;
18872            };
18873
18874            let new_inline_diagnostics = cx
18875                .background_spawn(async move {
18876                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18877                    for diagnostic_entry in
18878                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18879                    {
18880                        let message = diagnostic_entry
18881                            .diagnostic
18882                            .message
18883                            .split_once('\n')
18884                            .map(|(line, _)| line)
18885                            .map(SharedString::new)
18886                            .unwrap_or_else(|| {
18887                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18888                            });
18889                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18890                        let (Ok(i) | Err(i)) = inline_diagnostics
18891                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18892                        inline_diagnostics.insert(
18893                            i,
18894                            (
18895                                start_anchor,
18896                                InlineDiagnostic {
18897                                    message,
18898                                    group_id: diagnostic_entry.diagnostic.group_id,
18899                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18900                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18901                                    severity: diagnostic_entry.diagnostic.severity,
18902                                },
18903                            ),
18904                        );
18905                    }
18906                    inline_diagnostics
18907                })
18908                .await;
18909
18910            editor
18911                .update(cx, |editor, cx| {
18912                    editor.inline_diagnostics = new_inline_diagnostics;
18913                    cx.notify();
18914                })
18915                .ok();
18916        });
18917    }
18918
18919    fn pull_diagnostics(
18920        &mut self,
18921        buffer_id: Option<BufferId>,
18922        window: &Window,
18923        cx: &mut Context<Self>,
18924    ) -> Option<()> {
18925        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18926            return None;
18927        }
18928        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18929            .diagnostics
18930            .lsp_pull_diagnostics;
18931        if !pull_diagnostics_settings.enabled {
18932            return None;
18933        }
18934        let project = self.project()?.downgrade();
18935
18936        let mut edited_buffer_ids = HashSet::default();
18937        let mut edited_worktree_ids = HashSet::default();
18938        let edited_buffers = match buffer_id {
18939            Some(buffer_id) => {
18940                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18941                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18942                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18943                edited_worktree_ids.insert(worktree_id);
18944                vec![buffer]
18945            }
18946            None => self
18947                .buffer()
18948                .read(cx)
18949                .all_buffers()
18950                .into_iter()
18951                .filter(|buffer| {
18952                    let buffer = buffer.read(cx);
18953                    match buffer.file().map(|f| f.worktree_id(cx)) {
18954                        Some(worktree_id) => {
18955                            edited_buffer_ids.insert(buffer.remote_id());
18956                            edited_worktree_ids.insert(worktree_id);
18957                            true
18958                        }
18959                        None => false,
18960                    }
18961                })
18962                .collect::<Vec<_>>(),
18963        };
18964
18965        if edited_buffers.is_empty() {
18966            self.pull_diagnostics_task = Task::ready(());
18967            self.pull_diagnostics_background_task = Task::ready(());
18968            return None;
18969        }
18970
18971        let mut already_used_buffers = HashSet::default();
18972        let related_open_buffers = self
18973            .workspace
18974            .as_ref()
18975            .and_then(|(workspace, _)| workspace.upgrade())
18976            .into_iter()
18977            .flat_map(|workspace| workspace.read(cx).panes())
18978            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18979            .filter(|editor| editor != &cx.entity())
18980            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18981            .filter(|buffer| {
18982                let buffer = buffer.read(cx);
18983                let buffer_id = buffer.remote_id();
18984                if already_used_buffers.insert(buffer_id) {
18985                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18986                        return !edited_buffer_ids.contains(&buffer_id)
18987                            && edited_worktree_ids.contains(&worktree_id);
18988                    }
18989                }
18990                false
18991            })
18992            .collect::<Vec<_>>();
18993
18994        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18995        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18996            if buffers.is_empty() {
18997                return Task::ready(());
18998            }
18999            let project_weak = project.clone();
19000            cx.spawn_in(window, async move |_, cx| {
19001                cx.background_executor().timer(delay).await;
19002
19003                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
19004                    buffers
19005                        .into_iter()
19006                        .filter_map(|buffer| {
19007                            project_weak
19008                                .update(cx, |project, cx| {
19009                                    project.lsp_store().update(cx, |lsp_store, cx| {
19010                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19011                                    })
19012                                })
19013                                .ok()
19014                        })
19015                        .collect::<FuturesUnordered<_>>()
19016                }) else {
19017                    return;
19018                };
19019
19020                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
19021                    if let Err(e) = pull_task {
19022                        log::error!("Failed to update project diagnostics: {e:#}");
19023                    }
19024                }
19025            })
19026        };
19027
19028        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
19029        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
19030
19031        Some(())
19032    }
19033
19034    pub fn set_selections_from_remote(
19035        &mut self,
19036        selections: Vec<Selection<Anchor>>,
19037        pending_selection: Option<Selection<Anchor>>,
19038        window: &mut Window,
19039        cx: &mut Context<Self>,
19040    ) {
19041        let old_cursor_position = self.selections.newest_anchor().head();
19042        self.selections
19043            .change_with(&self.display_snapshot(cx), |s| {
19044                s.select_anchors(selections);
19045                if let Some(pending_selection) = pending_selection {
19046                    s.set_pending(pending_selection, SelectMode::Character);
19047                } else {
19048                    s.clear_pending();
19049                }
19050            });
19051        self.selections_did_change(
19052            false,
19053            &old_cursor_position,
19054            SelectionEffects::default(),
19055            window,
19056            cx,
19057        );
19058    }
19059
19060    pub fn transact(
19061        &mut self,
19062        window: &mut Window,
19063        cx: &mut Context<Self>,
19064        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19065    ) -> Option<TransactionId> {
19066        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19067            this.start_transaction_at(Instant::now(), window, cx);
19068            update(this, window, cx);
19069            this.end_transaction_at(Instant::now(), cx)
19070        })
19071    }
19072
19073    pub fn start_transaction_at(
19074        &mut self,
19075        now: Instant,
19076        window: &mut Window,
19077        cx: &mut Context<Self>,
19078    ) -> Option<TransactionId> {
19079        self.end_selection(window, cx);
19080        if let Some(tx_id) = self
19081            .buffer
19082            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19083        {
19084            self.selection_history
19085                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19086            cx.emit(EditorEvent::TransactionBegun {
19087                transaction_id: tx_id,
19088            });
19089            Some(tx_id)
19090        } else {
19091            None
19092        }
19093    }
19094
19095    pub fn end_transaction_at(
19096        &mut self,
19097        now: Instant,
19098        cx: &mut Context<Self>,
19099    ) -> Option<TransactionId> {
19100        if let Some(transaction_id) = self
19101            .buffer
19102            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19103        {
19104            if let Some((_, end_selections)) =
19105                self.selection_history.transaction_mut(transaction_id)
19106            {
19107                *end_selections = Some(self.selections.disjoint_anchors_arc());
19108            } else {
19109                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19110            }
19111
19112            cx.emit(EditorEvent::Edited { transaction_id });
19113            Some(transaction_id)
19114        } else {
19115            None
19116        }
19117    }
19118
19119    pub fn modify_transaction_selection_history(
19120        &mut self,
19121        transaction_id: TransactionId,
19122        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19123    ) -> bool {
19124        self.selection_history
19125            .transaction_mut(transaction_id)
19126            .map(modify)
19127            .is_some()
19128    }
19129
19130    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19131        if self.selection_mark_mode {
19132            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19133                s.move_with(|_, sel| {
19134                    sel.collapse_to(sel.head(), SelectionGoal::None);
19135                });
19136            })
19137        }
19138        self.selection_mark_mode = true;
19139        cx.notify();
19140    }
19141
19142    pub fn swap_selection_ends(
19143        &mut self,
19144        _: &actions::SwapSelectionEnds,
19145        window: &mut Window,
19146        cx: &mut Context<Self>,
19147    ) {
19148        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19149            s.move_with(|_, sel| {
19150                if sel.start != sel.end {
19151                    sel.reversed = !sel.reversed
19152                }
19153            });
19154        });
19155        self.request_autoscroll(Autoscroll::newest(), cx);
19156        cx.notify();
19157    }
19158
19159    pub fn toggle_focus(
19160        workspace: &mut Workspace,
19161        _: &actions::ToggleFocus,
19162        window: &mut Window,
19163        cx: &mut Context<Workspace>,
19164    ) {
19165        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19166            return;
19167        };
19168        workspace.activate_item(&item, true, true, window, cx);
19169    }
19170
19171    pub fn toggle_fold(
19172        &mut self,
19173        _: &actions::ToggleFold,
19174        window: &mut Window,
19175        cx: &mut Context<Self>,
19176    ) {
19177        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19178            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19179            let selection = self.selections.newest::<Point>(&display_map);
19180
19181            let range = if selection.is_empty() {
19182                let point = selection.head().to_display_point(&display_map);
19183                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19184                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19185                    .to_point(&display_map);
19186                start..end
19187            } else {
19188                selection.range()
19189            };
19190            if display_map.folds_in_range(range).next().is_some() {
19191                self.unfold_lines(&Default::default(), window, cx)
19192            } else {
19193                self.fold(&Default::default(), window, cx)
19194            }
19195        } else {
19196            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19197            let buffer_ids: HashSet<_> = self
19198                .selections
19199                .disjoint_anchor_ranges()
19200                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19201                .collect();
19202
19203            let should_unfold = buffer_ids
19204                .iter()
19205                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19206
19207            for buffer_id in buffer_ids {
19208                if should_unfold {
19209                    self.unfold_buffer(buffer_id, cx);
19210                } else {
19211                    self.fold_buffer(buffer_id, cx);
19212                }
19213            }
19214        }
19215    }
19216
19217    pub fn toggle_fold_recursive(
19218        &mut self,
19219        _: &actions::ToggleFoldRecursive,
19220        window: &mut Window,
19221        cx: &mut Context<Self>,
19222    ) {
19223        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19224
19225        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19226        let range = if selection.is_empty() {
19227            let point = selection.head().to_display_point(&display_map);
19228            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19229            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19230                .to_point(&display_map);
19231            start..end
19232        } else {
19233            selection.range()
19234        };
19235        if display_map.folds_in_range(range).next().is_some() {
19236            self.unfold_recursive(&Default::default(), window, cx)
19237        } else {
19238            self.fold_recursive(&Default::default(), window, cx)
19239        }
19240    }
19241
19242    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19243        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19244            let mut to_fold = Vec::new();
19245            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19246            let selections = self.selections.all_adjusted(&display_map);
19247
19248            for selection in selections {
19249                let range = selection.range().sorted();
19250                let buffer_start_row = range.start.row;
19251
19252                if range.start.row != range.end.row {
19253                    let mut found = false;
19254                    let mut row = range.start.row;
19255                    while row <= range.end.row {
19256                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19257                        {
19258                            found = true;
19259                            row = crease.range().end.row + 1;
19260                            to_fold.push(crease);
19261                        } else {
19262                            row += 1
19263                        }
19264                    }
19265                    if found {
19266                        continue;
19267                    }
19268                }
19269
19270                for row in (0..=range.start.row).rev() {
19271                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19272                        && crease.range().end.row >= buffer_start_row
19273                    {
19274                        to_fold.push(crease);
19275                        if row <= range.start.row {
19276                            break;
19277                        }
19278                    }
19279                }
19280            }
19281
19282            self.fold_creases(to_fold, true, window, cx);
19283        } else {
19284            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19285            let buffer_ids = self
19286                .selections
19287                .disjoint_anchor_ranges()
19288                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19289                .collect::<HashSet<_>>();
19290            for buffer_id in buffer_ids {
19291                self.fold_buffer(buffer_id, cx);
19292            }
19293        }
19294    }
19295
19296    pub fn toggle_fold_all(
19297        &mut self,
19298        _: &actions::ToggleFoldAll,
19299        window: &mut Window,
19300        cx: &mut Context<Self>,
19301    ) {
19302        let has_folds = if self.buffer.read(cx).is_singleton() {
19303            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19304            let has_folds = display_map
19305                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19306                .next()
19307                .is_some();
19308            has_folds
19309        } else {
19310            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19311            let has_folds = buffer_ids
19312                .iter()
19313                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19314            has_folds
19315        };
19316
19317        if has_folds {
19318            self.unfold_all(&actions::UnfoldAll, window, cx);
19319        } else {
19320            self.fold_all(&actions::FoldAll, window, cx);
19321        }
19322    }
19323
19324    fn fold_at_level(
19325        &mut self,
19326        fold_at: &FoldAtLevel,
19327        window: &mut Window,
19328        cx: &mut Context<Self>,
19329    ) {
19330        if !self.buffer.read(cx).is_singleton() {
19331            return;
19332        }
19333
19334        let fold_at_level = fold_at.0;
19335        let snapshot = self.buffer.read(cx).snapshot(cx);
19336        let mut to_fold = Vec::new();
19337        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19338
19339        let row_ranges_to_keep: Vec<Range<u32>> = self
19340            .selections
19341            .all::<Point>(&self.display_snapshot(cx))
19342            .into_iter()
19343            .map(|sel| sel.start.row..sel.end.row)
19344            .collect();
19345
19346        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19347            while start_row < end_row {
19348                match self
19349                    .snapshot(window, cx)
19350                    .crease_for_buffer_row(MultiBufferRow(start_row))
19351                {
19352                    Some(crease) => {
19353                        let nested_start_row = crease.range().start.row + 1;
19354                        let nested_end_row = crease.range().end.row;
19355
19356                        if current_level < fold_at_level {
19357                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19358                        } else if current_level == fold_at_level {
19359                            // Fold iff there is no selection completely contained within the fold region
19360                            if !row_ranges_to_keep.iter().any(|selection| {
19361                                selection.end >= nested_start_row
19362                                    && selection.start <= nested_end_row
19363                            }) {
19364                                to_fold.push(crease);
19365                            }
19366                        }
19367
19368                        start_row = nested_end_row + 1;
19369                    }
19370                    None => start_row += 1,
19371                }
19372            }
19373        }
19374
19375        self.fold_creases(to_fold, true, window, cx);
19376    }
19377
19378    pub fn fold_at_level_1(
19379        &mut self,
19380        _: &actions::FoldAtLevel1,
19381        window: &mut Window,
19382        cx: &mut Context<Self>,
19383    ) {
19384        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19385    }
19386
19387    pub fn fold_at_level_2(
19388        &mut self,
19389        _: &actions::FoldAtLevel2,
19390        window: &mut Window,
19391        cx: &mut Context<Self>,
19392    ) {
19393        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19394    }
19395
19396    pub fn fold_at_level_3(
19397        &mut self,
19398        _: &actions::FoldAtLevel3,
19399        window: &mut Window,
19400        cx: &mut Context<Self>,
19401    ) {
19402        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19403    }
19404
19405    pub fn fold_at_level_4(
19406        &mut self,
19407        _: &actions::FoldAtLevel4,
19408        window: &mut Window,
19409        cx: &mut Context<Self>,
19410    ) {
19411        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19412    }
19413
19414    pub fn fold_at_level_5(
19415        &mut self,
19416        _: &actions::FoldAtLevel5,
19417        window: &mut Window,
19418        cx: &mut Context<Self>,
19419    ) {
19420        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19421    }
19422
19423    pub fn fold_at_level_6(
19424        &mut self,
19425        _: &actions::FoldAtLevel6,
19426        window: &mut Window,
19427        cx: &mut Context<Self>,
19428    ) {
19429        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19430    }
19431
19432    pub fn fold_at_level_7(
19433        &mut self,
19434        _: &actions::FoldAtLevel7,
19435        window: &mut Window,
19436        cx: &mut Context<Self>,
19437    ) {
19438        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19439    }
19440
19441    pub fn fold_at_level_8(
19442        &mut self,
19443        _: &actions::FoldAtLevel8,
19444        window: &mut Window,
19445        cx: &mut Context<Self>,
19446    ) {
19447        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19448    }
19449
19450    pub fn fold_at_level_9(
19451        &mut self,
19452        _: &actions::FoldAtLevel9,
19453        window: &mut Window,
19454        cx: &mut Context<Self>,
19455    ) {
19456        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19457    }
19458
19459    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19460        if self.buffer.read(cx).is_singleton() {
19461            let mut fold_ranges = Vec::new();
19462            let snapshot = self.buffer.read(cx).snapshot(cx);
19463
19464            for row in 0..snapshot.max_row().0 {
19465                if let Some(foldable_range) = self
19466                    .snapshot(window, cx)
19467                    .crease_for_buffer_row(MultiBufferRow(row))
19468                {
19469                    fold_ranges.push(foldable_range);
19470                }
19471            }
19472
19473            self.fold_creases(fold_ranges, true, window, cx);
19474        } else {
19475            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19476                editor
19477                    .update_in(cx, |editor, _, cx| {
19478                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19479                            editor.fold_buffer(buffer_id, cx);
19480                        }
19481                    })
19482                    .ok();
19483            });
19484        }
19485        cx.emit(SearchEvent::ResultsCollapsedChanged(
19486            CollapseDirection::Collapsed,
19487        ));
19488    }
19489
19490    pub fn fold_function_bodies(
19491        &mut self,
19492        _: &actions::FoldFunctionBodies,
19493        window: &mut Window,
19494        cx: &mut Context<Self>,
19495    ) {
19496        let snapshot = self.buffer.read(cx).snapshot(cx);
19497
19498        let ranges = snapshot
19499            .text_object_ranges(
19500                MultiBufferOffset(0)..snapshot.len(),
19501                TreeSitterOptions::default(),
19502            )
19503            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19504            .collect::<Vec<_>>();
19505
19506        let creases = ranges
19507            .into_iter()
19508            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19509            .collect();
19510
19511        self.fold_creases(creases, true, window, cx);
19512    }
19513
19514    pub fn fold_recursive(
19515        &mut self,
19516        _: &actions::FoldRecursive,
19517        window: &mut Window,
19518        cx: &mut Context<Self>,
19519    ) {
19520        let mut to_fold = Vec::new();
19521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19522        let selections = self.selections.all_adjusted(&display_map);
19523
19524        for selection in selections {
19525            let range = selection.range().sorted();
19526            let buffer_start_row = range.start.row;
19527
19528            if range.start.row != range.end.row {
19529                let mut found = false;
19530                for row in range.start.row..=range.end.row {
19531                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19532                        found = true;
19533                        to_fold.push(crease);
19534                    }
19535                }
19536                if found {
19537                    continue;
19538                }
19539            }
19540
19541            for row in (0..=range.start.row).rev() {
19542                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19543                    if crease.range().end.row >= buffer_start_row {
19544                        to_fold.push(crease);
19545                    } else {
19546                        break;
19547                    }
19548                }
19549            }
19550        }
19551
19552        self.fold_creases(to_fold, true, window, cx);
19553    }
19554
19555    pub fn fold_at(
19556        &mut self,
19557        buffer_row: MultiBufferRow,
19558        window: &mut Window,
19559        cx: &mut Context<Self>,
19560    ) {
19561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19562
19563        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19564            let autoscroll = self
19565                .selections
19566                .all::<Point>(&display_map)
19567                .iter()
19568                .any(|selection| crease.range().overlaps(&selection.range()));
19569
19570            self.fold_creases(vec![crease], autoscroll, window, cx);
19571        }
19572    }
19573
19574    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19575        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19576            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19577            let buffer = display_map.buffer_snapshot();
19578            let selections = self.selections.all::<Point>(&display_map);
19579            let ranges = selections
19580                .iter()
19581                .map(|s| {
19582                    let range = s.display_range(&display_map).sorted();
19583                    let mut start = range.start.to_point(&display_map);
19584                    let mut end = range.end.to_point(&display_map);
19585                    start.column = 0;
19586                    end.column = buffer.line_len(MultiBufferRow(end.row));
19587                    start..end
19588                })
19589                .collect::<Vec<_>>();
19590
19591            self.unfold_ranges(&ranges, true, true, cx);
19592        } else {
19593            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19594            let buffer_ids = self
19595                .selections
19596                .disjoint_anchor_ranges()
19597                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19598                .collect::<HashSet<_>>();
19599            for buffer_id in buffer_ids {
19600                self.unfold_buffer(buffer_id, cx);
19601            }
19602        }
19603    }
19604
19605    pub fn unfold_recursive(
19606        &mut self,
19607        _: &UnfoldRecursive,
19608        _window: &mut Window,
19609        cx: &mut Context<Self>,
19610    ) {
19611        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19612        let selections = self.selections.all::<Point>(&display_map);
19613        let ranges = selections
19614            .iter()
19615            .map(|s| {
19616                let mut range = s.display_range(&display_map).sorted();
19617                *range.start.column_mut() = 0;
19618                *range.end.column_mut() = display_map.line_len(range.end.row());
19619                let start = range.start.to_point(&display_map);
19620                let end = range.end.to_point(&display_map);
19621                start..end
19622            })
19623            .collect::<Vec<_>>();
19624
19625        self.unfold_ranges(&ranges, true, true, cx);
19626    }
19627
19628    pub fn unfold_at(
19629        &mut self,
19630        buffer_row: MultiBufferRow,
19631        _window: &mut Window,
19632        cx: &mut Context<Self>,
19633    ) {
19634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19635
19636        let intersection_range = Point::new(buffer_row.0, 0)
19637            ..Point::new(
19638                buffer_row.0,
19639                display_map.buffer_snapshot().line_len(buffer_row),
19640            );
19641
19642        let autoscroll = self
19643            .selections
19644            .all::<Point>(&display_map)
19645            .iter()
19646            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19647
19648        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19649    }
19650
19651    pub fn unfold_all(
19652        &mut self,
19653        _: &actions::UnfoldAll,
19654        _window: &mut Window,
19655        cx: &mut Context<Self>,
19656    ) {
19657        if self.buffer.read(cx).is_singleton() {
19658            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19659            self.unfold_ranges(
19660                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19661                true,
19662                true,
19663                cx,
19664            );
19665        } else {
19666            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19667                editor
19668                    .update(cx, |editor, cx| {
19669                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19670                            editor.unfold_buffer(buffer_id, cx);
19671                        }
19672                    })
19673                    .ok();
19674            });
19675        }
19676        cx.emit(SearchEvent::ResultsCollapsedChanged(
19677            CollapseDirection::Expanded,
19678        ));
19679    }
19680
19681    pub fn fold_selected_ranges(
19682        &mut self,
19683        _: &FoldSelectedRanges,
19684        window: &mut Window,
19685        cx: &mut Context<Self>,
19686    ) {
19687        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19688        let selections = self.selections.all_adjusted(&display_map);
19689        let ranges = selections
19690            .into_iter()
19691            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19692            .collect::<Vec<_>>();
19693        self.fold_creases(ranges, true, window, cx);
19694    }
19695
19696    pub fn fold_ranges<T: ToOffset + Clone>(
19697        &mut self,
19698        ranges: Vec<Range<T>>,
19699        auto_scroll: bool,
19700        window: &mut Window,
19701        cx: &mut Context<Self>,
19702    ) {
19703        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19704        let ranges = ranges
19705            .into_iter()
19706            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19707            .collect::<Vec<_>>();
19708        self.fold_creases(ranges, auto_scroll, window, cx);
19709    }
19710
19711    pub fn fold_creases<T: ToOffset + Clone>(
19712        &mut self,
19713        creases: Vec<Crease<T>>,
19714        auto_scroll: bool,
19715        _window: &mut Window,
19716        cx: &mut Context<Self>,
19717    ) {
19718        if creases.is_empty() {
19719            return;
19720        }
19721
19722        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19723
19724        if auto_scroll {
19725            self.request_autoscroll(Autoscroll::fit(), cx);
19726        }
19727
19728        cx.notify();
19729
19730        self.scrollbar_marker_state.dirty = true;
19731        self.folds_did_change(cx);
19732    }
19733
19734    /// Removes any folds whose ranges intersect any of the given ranges.
19735    pub fn unfold_ranges<T: ToOffset + Clone>(
19736        &mut self,
19737        ranges: &[Range<T>],
19738        inclusive: bool,
19739        auto_scroll: bool,
19740        cx: &mut Context<Self>,
19741    ) {
19742        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19743            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19744        });
19745        self.folds_did_change(cx);
19746    }
19747
19748    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19749        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19750            return;
19751        }
19752
19753        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19754        self.display_map.update(cx, |display_map, cx| {
19755            display_map.fold_buffers([buffer_id], cx)
19756        });
19757
19758        let snapshot = self.display_snapshot(cx);
19759        self.selections.change_with(&snapshot, |selections| {
19760            selections.remove_selections_from_buffer(buffer_id);
19761        });
19762
19763        cx.emit(EditorEvent::BufferFoldToggled {
19764            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19765            folded: true,
19766        });
19767        cx.notify();
19768    }
19769
19770    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19771        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19772            return;
19773        }
19774        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19775        self.display_map.update(cx, |display_map, cx| {
19776            display_map.unfold_buffers([buffer_id], cx);
19777        });
19778        cx.emit(EditorEvent::BufferFoldToggled {
19779            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19780            folded: false,
19781        });
19782        cx.notify();
19783    }
19784
19785    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19786        self.display_map.read(cx).is_buffer_folded(buffer)
19787    }
19788
19789    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19790        self.display_map.read(cx).folded_buffers()
19791    }
19792
19793    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19794        self.display_map.update(cx, |display_map, cx| {
19795            display_map.disable_header_for_buffer(buffer_id, cx);
19796        });
19797        cx.notify();
19798    }
19799
19800    /// Removes any folds with the given ranges.
19801    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19802        &mut self,
19803        ranges: &[Range<T>],
19804        type_id: TypeId,
19805        auto_scroll: bool,
19806        cx: &mut Context<Self>,
19807    ) {
19808        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19809            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19810        });
19811        self.folds_did_change(cx);
19812    }
19813
19814    fn remove_folds_with<T: ToOffset + Clone>(
19815        &mut self,
19816        ranges: &[Range<T>],
19817        auto_scroll: bool,
19818        cx: &mut Context<Self>,
19819        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19820    ) {
19821        if ranges.is_empty() {
19822            return;
19823        }
19824
19825        let mut buffers_affected = HashSet::default();
19826        let multi_buffer = self.buffer().read(cx);
19827        for range in ranges {
19828            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19829                buffers_affected.insert(buffer.read(cx).remote_id());
19830            };
19831        }
19832
19833        self.display_map.update(cx, update);
19834
19835        if auto_scroll {
19836            self.request_autoscroll(Autoscroll::fit(), cx);
19837        }
19838
19839        cx.notify();
19840        self.scrollbar_marker_state.dirty = true;
19841        self.active_indent_guides_state.dirty = true;
19842    }
19843
19844    pub fn update_renderer_widths(
19845        &mut self,
19846        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19847        cx: &mut Context<Self>,
19848    ) -> bool {
19849        self.display_map
19850            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19851    }
19852
19853    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19854        self.display_map.read(cx).fold_placeholder.clone()
19855    }
19856
19857    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19858        self.buffer.update(cx, |buffer, cx| {
19859            buffer.set_all_diff_hunks_expanded(cx);
19860        });
19861    }
19862
19863    pub fn expand_all_diff_hunks(
19864        &mut self,
19865        _: &ExpandAllDiffHunks,
19866        _window: &mut Window,
19867        cx: &mut Context<Self>,
19868    ) {
19869        self.buffer.update(cx, |buffer, cx| {
19870            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19871        });
19872    }
19873
19874    pub fn collapse_all_diff_hunks(
19875        &mut self,
19876        _: &CollapseAllDiffHunks,
19877        _window: &mut Window,
19878        cx: &mut Context<Self>,
19879    ) {
19880        self.buffer.update(cx, |buffer, cx| {
19881            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19882        });
19883    }
19884
19885    pub fn toggle_selected_diff_hunks(
19886        &mut self,
19887        _: &ToggleSelectedDiffHunks,
19888        _window: &mut Window,
19889        cx: &mut Context<Self>,
19890    ) {
19891        let ranges: Vec<_> = self
19892            .selections
19893            .disjoint_anchors()
19894            .iter()
19895            .map(|s| s.range())
19896            .collect();
19897        self.toggle_diff_hunks_in_ranges(ranges, cx);
19898    }
19899
19900    pub fn diff_hunks_in_ranges<'a>(
19901        &'a self,
19902        ranges: &'a [Range<Anchor>],
19903        buffer: &'a MultiBufferSnapshot,
19904    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19905        ranges.iter().flat_map(move |range| {
19906            let end_excerpt_id = range.end.excerpt_id;
19907            let range = range.to_point(buffer);
19908            let mut peek_end = range.end;
19909            if range.end.row < buffer.max_row().0 {
19910                peek_end = Point::new(range.end.row + 1, 0);
19911            }
19912            buffer
19913                .diff_hunks_in_range(range.start..peek_end)
19914                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19915        })
19916    }
19917
19918    pub fn has_stageable_diff_hunks_in_ranges(
19919        &self,
19920        ranges: &[Range<Anchor>],
19921        snapshot: &MultiBufferSnapshot,
19922    ) -> bool {
19923        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19924        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19925    }
19926
19927    pub fn toggle_staged_selected_diff_hunks(
19928        &mut self,
19929        _: &::git::ToggleStaged,
19930        _: &mut Window,
19931        cx: &mut Context<Self>,
19932    ) {
19933        let snapshot = self.buffer.read(cx).snapshot(cx);
19934        let ranges: Vec<_> = self
19935            .selections
19936            .disjoint_anchors()
19937            .iter()
19938            .map(|s| s.range())
19939            .collect();
19940        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19941        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19942    }
19943
19944    pub fn set_render_diff_hunk_controls(
19945        &mut self,
19946        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19947        cx: &mut Context<Self>,
19948    ) {
19949        self.render_diff_hunk_controls = render_diff_hunk_controls;
19950        cx.notify();
19951    }
19952
19953    pub fn stage_and_next(
19954        &mut self,
19955        _: &::git::StageAndNext,
19956        window: &mut Window,
19957        cx: &mut Context<Self>,
19958    ) {
19959        self.do_stage_or_unstage_and_next(true, window, cx);
19960    }
19961
19962    pub fn unstage_and_next(
19963        &mut self,
19964        _: &::git::UnstageAndNext,
19965        window: &mut Window,
19966        cx: &mut Context<Self>,
19967    ) {
19968        self.do_stage_or_unstage_and_next(false, window, cx);
19969    }
19970
19971    pub fn stage_or_unstage_diff_hunks(
19972        &mut self,
19973        stage: bool,
19974        ranges: Vec<Range<Anchor>>,
19975        cx: &mut Context<Self>,
19976    ) {
19977        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19978        cx.spawn(async move |this, cx| {
19979            task.await?;
19980            this.update(cx, |this, cx| {
19981                let snapshot = this.buffer.read(cx).snapshot(cx);
19982                let chunk_by = this
19983                    .diff_hunks_in_ranges(&ranges, &snapshot)
19984                    .chunk_by(|hunk| hunk.buffer_id);
19985                for (buffer_id, hunks) in &chunk_by {
19986                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19987                }
19988            })
19989        })
19990        .detach_and_log_err(cx);
19991    }
19992
19993    fn save_buffers_for_ranges_if_needed(
19994        &mut self,
19995        ranges: &[Range<Anchor>],
19996        cx: &mut Context<Editor>,
19997    ) -> Task<Result<()>> {
19998        let multibuffer = self.buffer.read(cx);
19999        let snapshot = multibuffer.read(cx);
20000        let buffer_ids: HashSet<_> = ranges
20001            .iter()
20002            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20003            .collect();
20004        drop(snapshot);
20005
20006        let mut buffers = HashSet::default();
20007        for buffer_id in buffer_ids {
20008            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20009                let buffer = buffer_entity.read(cx);
20010                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20011                {
20012                    buffers.insert(buffer_entity);
20013                }
20014            }
20015        }
20016
20017        if let Some(project) = &self.project {
20018            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20019        } else {
20020            Task::ready(Ok(()))
20021        }
20022    }
20023
20024    fn do_stage_or_unstage_and_next(
20025        &mut self,
20026        stage: bool,
20027        window: &mut Window,
20028        cx: &mut Context<Self>,
20029    ) {
20030        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20031
20032        if ranges.iter().any(|range| range.start != range.end) {
20033            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20034            return;
20035        }
20036
20037        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20038        let snapshot = self.snapshot(window, cx);
20039        let position = self
20040            .selections
20041            .newest::<Point>(&snapshot.display_snapshot)
20042            .head();
20043        let mut row = snapshot
20044            .buffer_snapshot()
20045            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20046            .find(|hunk| hunk.row_range.start.0 > position.row)
20047            .map(|hunk| hunk.row_range.start);
20048
20049        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20050        // Outside of the project diff editor, wrap around to the beginning.
20051        if !all_diff_hunks_expanded {
20052            row = row.or_else(|| {
20053                snapshot
20054                    .buffer_snapshot()
20055                    .diff_hunks_in_range(Point::zero()..position)
20056                    .find(|hunk| hunk.row_range.end.0 < position.row)
20057                    .map(|hunk| hunk.row_range.start)
20058            });
20059        }
20060
20061        if let Some(row) = row {
20062            let destination = Point::new(row.0, 0);
20063            let autoscroll = Autoscroll::center();
20064
20065            self.unfold_ranges(&[destination..destination], false, false, cx);
20066            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20067                s.select_ranges([destination..destination]);
20068            });
20069        }
20070    }
20071
20072    fn do_stage_or_unstage(
20073        &self,
20074        stage: bool,
20075        buffer_id: BufferId,
20076        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20077        cx: &mut App,
20078    ) -> Option<()> {
20079        let project = self.project()?;
20080        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20081        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20082        let buffer_snapshot = buffer.read(cx).snapshot();
20083        let file_exists = buffer_snapshot
20084            .file()
20085            .is_some_and(|file| file.disk_state().exists());
20086        diff.update(cx, |diff, cx| {
20087            diff.stage_or_unstage_hunks(
20088                stage,
20089                &hunks
20090                    .map(|hunk| buffer_diff::DiffHunk {
20091                        buffer_range: hunk.buffer_range,
20092                        // We don't need to pass in word diffs here because they're only used for rendering and
20093                        // this function changes internal state
20094                        base_word_diffs: Vec::default(),
20095                        buffer_word_diffs: Vec::default(),
20096                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20097                            ..hunk.diff_base_byte_range.end.0,
20098                        secondary_status: hunk.status.secondary,
20099                        range: Point::zero()..Point::zero(), // unused
20100                    })
20101                    .collect::<Vec<_>>(),
20102                &buffer_snapshot,
20103                file_exists,
20104                cx,
20105            )
20106        });
20107        None
20108    }
20109
20110    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20111        let ranges: Vec<_> = self
20112            .selections
20113            .disjoint_anchors()
20114            .iter()
20115            .map(|s| s.range())
20116            .collect();
20117        self.buffer
20118            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20119    }
20120
20121    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20122        self.buffer.update(cx, |buffer, cx| {
20123            let ranges = vec![Anchor::min()..Anchor::max()];
20124            if !buffer.all_diff_hunks_expanded()
20125                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20126            {
20127                buffer.collapse_diff_hunks(ranges, cx);
20128                true
20129            } else {
20130                false
20131            }
20132        })
20133    }
20134
20135    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20136        if self.buffer.read(cx).all_diff_hunks_expanded() {
20137            return true;
20138        }
20139        let ranges = vec![Anchor::min()..Anchor::max()];
20140        self.buffer
20141            .read(cx)
20142            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20143    }
20144
20145    fn toggle_diff_hunks_in_ranges(
20146        &mut self,
20147        ranges: Vec<Range<Anchor>>,
20148        cx: &mut Context<Editor>,
20149    ) {
20150        self.buffer.update(cx, |buffer, cx| {
20151            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20152            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20153        })
20154    }
20155
20156    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20157        self.buffer.update(cx, |buffer, cx| {
20158            let snapshot = buffer.snapshot(cx);
20159            let excerpt_id = range.end.excerpt_id;
20160            let point_range = range.to_point(&snapshot);
20161            let expand = !buffer.single_hunk_is_expanded(range, cx);
20162            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20163        })
20164    }
20165
20166    pub(crate) fn apply_all_diff_hunks(
20167        &mut self,
20168        _: &ApplyAllDiffHunks,
20169        window: &mut Window,
20170        cx: &mut Context<Self>,
20171    ) {
20172        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20173
20174        let buffers = self.buffer.read(cx).all_buffers();
20175        for branch_buffer in buffers {
20176            branch_buffer.update(cx, |branch_buffer, cx| {
20177                branch_buffer.merge_into_base(Vec::new(), cx);
20178            });
20179        }
20180
20181        if let Some(project) = self.project.clone() {
20182            self.save(
20183                SaveOptions {
20184                    format: true,
20185                    autosave: false,
20186                },
20187                project,
20188                window,
20189                cx,
20190            )
20191            .detach_and_log_err(cx);
20192        }
20193    }
20194
20195    pub(crate) fn apply_selected_diff_hunks(
20196        &mut self,
20197        _: &ApplyDiffHunk,
20198        window: &mut Window,
20199        cx: &mut Context<Self>,
20200    ) {
20201        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20202        let snapshot = self.snapshot(window, cx);
20203        let hunks = snapshot.hunks_for_ranges(
20204            self.selections
20205                .all(&snapshot.display_snapshot)
20206                .into_iter()
20207                .map(|selection| selection.range()),
20208        );
20209        let mut ranges_by_buffer = HashMap::default();
20210        self.transact(window, cx, |editor, _window, cx| {
20211            for hunk in hunks {
20212                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20213                    ranges_by_buffer
20214                        .entry(buffer.clone())
20215                        .or_insert_with(Vec::new)
20216                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20217                }
20218            }
20219
20220            for (buffer, ranges) in ranges_by_buffer {
20221                buffer.update(cx, |buffer, cx| {
20222                    buffer.merge_into_base(ranges, cx);
20223                });
20224            }
20225        });
20226
20227        if let Some(project) = self.project.clone() {
20228            self.save(
20229                SaveOptions {
20230                    format: true,
20231                    autosave: false,
20232                },
20233                project,
20234                window,
20235                cx,
20236            )
20237            .detach_and_log_err(cx);
20238        }
20239    }
20240
20241    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20242        if hovered != self.gutter_hovered {
20243            self.gutter_hovered = hovered;
20244            cx.notify();
20245        }
20246    }
20247
20248    pub fn insert_blocks(
20249        &mut self,
20250        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20251        autoscroll: Option<Autoscroll>,
20252        cx: &mut Context<Self>,
20253    ) -> Vec<CustomBlockId> {
20254        let blocks = self
20255            .display_map
20256            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20257        if let Some(autoscroll) = autoscroll {
20258            self.request_autoscroll(autoscroll, cx);
20259        }
20260        cx.notify();
20261        blocks
20262    }
20263
20264    pub fn resize_blocks(
20265        &mut self,
20266        heights: HashMap<CustomBlockId, u32>,
20267        autoscroll: Option<Autoscroll>,
20268        cx: &mut Context<Self>,
20269    ) {
20270        self.display_map
20271            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20272        if let Some(autoscroll) = autoscroll {
20273            self.request_autoscroll(autoscroll, cx);
20274        }
20275        cx.notify();
20276    }
20277
20278    pub fn replace_blocks(
20279        &mut self,
20280        renderers: HashMap<CustomBlockId, RenderBlock>,
20281        autoscroll: Option<Autoscroll>,
20282        cx: &mut Context<Self>,
20283    ) {
20284        self.display_map
20285            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20286        if let Some(autoscroll) = autoscroll {
20287            self.request_autoscroll(autoscroll, cx);
20288        }
20289        cx.notify();
20290    }
20291
20292    pub fn remove_blocks(
20293        &mut self,
20294        block_ids: HashSet<CustomBlockId>,
20295        autoscroll: Option<Autoscroll>,
20296        cx: &mut Context<Self>,
20297    ) {
20298        self.display_map.update(cx, |display_map, cx| {
20299            display_map.remove_blocks(block_ids, cx)
20300        });
20301        if let Some(autoscroll) = autoscroll {
20302            self.request_autoscroll(autoscroll, cx);
20303        }
20304        cx.notify();
20305    }
20306
20307    pub fn row_for_block(
20308        &self,
20309        block_id: CustomBlockId,
20310        cx: &mut Context<Self>,
20311    ) -> Option<DisplayRow> {
20312        self.display_map
20313            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20314    }
20315
20316    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20317        self.focused_block = Some(focused_block);
20318    }
20319
20320    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20321        self.focused_block.take()
20322    }
20323
20324    pub fn insert_creases(
20325        &mut self,
20326        creases: impl IntoIterator<Item = Crease<Anchor>>,
20327        cx: &mut Context<Self>,
20328    ) -> Vec<CreaseId> {
20329        self.display_map
20330            .update(cx, |map, cx| map.insert_creases(creases, cx))
20331    }
20332
20333    pub fn remove_creases(
20334        &mut self,
20335        ids: impl IntoIterator<Item = CreaseId>,
20336        cx: &mut Context<Self>,
20337    ) -> Vec<(CreaseId, Range<Anchor>)> {
20338        self.display_map
20339            .update(cx, |map, cx| map.remove_creases(ids, cx))
20340    }
20341
20342    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20343        self.display_map
20344            .update(cx, |map, cx| map.snapshot(cx))
20345            .longest_row()
20346    }
20347
20348    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20349        self.display_map
20350            .update(cx, |map, cx| map.snapshot(cx))
20351            .max_point()
20352    }
20353
20354    pub fn text(&self, cx: &App) -> String {
20355        self.buffer.read(cx).read(cx).text()
20356    }
20357
20358    pub fn is_empty(&self, cx: &App) -> bool {
20359        self.buffer.read(cx).read(cx).is_empty()
20360    }
20361
20362    pub fn text_option(&self, cx: &App) -> Option<String> {
20363        let text = self.text(cx);
20364        let text = text.trim();
20365
20366        if text.is_empty() {
20367            return None;
20368        }
20369
20370        Some(text.to_string())
20371    }
20372
20373    pub fn set_text(
20374        &mut self,
20375        text: impl Into<Arc<str>>,
20376        window: &mut Window,
20377        cx: &mut Context<Self>,
20378    ) {
20379        self.transact(window, cx, |this, _, cx| {
20380            this.buffer
20381                .read(cx)
20382                .as_singleton()
20383                .expect("you can only call set_text on editors for singleton buffers")
20384                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20385        });
20386    }
20387
20388    pub fn display_text(&self, cx: &mut App) -> String {
20389        self.display_map
20390            .update(cx, |map, cx| map.snapshot(cx))
20391            .text()
20392    }
20393
20394    fn create_minimap(
20395        &self,
20396        minimap_settings: MinimapSettings,
20397        window: &mut Window,
20398        cx: &mut Context<Self>,
20399    ) -> Option<Entity<Self>> {
20400        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20401            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20402    }
20403
20404    fn initialize_new_minimap(
20405        &self,
20406        minimap_settings: MinimapSettings,
20407        window: &mut Window,
20408        cx: &mut Context<Self>,
20409    ) -> Entity<Self> {
20410        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20411        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20412
20413        let mut minimap = Editor::new_internal(
20414            EditorMode::Minimap {
20415                parent: cx.weak_entity(),
20416            },
20417            self.buffer.clone(),
20418            None,
20419            Some(self.display_map.clone()),
20420            window,
20421            cx,
20422        );
20423        minimap.scroll_manager.clone_state(&self.scroll_manager);
20424        minimap.set_text_style_refinement(TextStyleRefinement {
20425            font_size: Some(MINIMAP_FONT_SIZE),
20426            font_weight: Some(MINIMAP_FONT_WEIGHT),
20427            font_family: Some(MINIMAP_FONT_FAMILY),
20428            ..Default::default()
20429        });
20430        minimap.update_minimap_configuration(minimap_settings, cx);
20431        cx.new(|_| minimap)
20432    }
20433
20434    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20435        let current_line_highlight = minimap_settings
20436            .current_line_highlight
20437            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20438        self.set_current_line_highlight(Some(current_line_highlight));
20439    }
20440
20441    pub fn minimap(&self) -> Option<&Entity<Self>> {
20442        self.minimap
20443            .as_ref()
20444            .filter(|_| self.minimap_visibility.visible())
20445    }
20446
20447    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20448        let mut wrap_guides = smallvec![];
20449
20450        if self.show_wrap_guides == Some(false) {
20451            return wrap_guides;
20452        }
20453
20454        let settings = self.buffer.read(cx).language_settings(cx);
20455        if settings.show_wrap_guides {
20456            match self.soft_wrap_mode(cx) {
20457                SoftWrap::Column(soft_wrap) => {
20458                    wrap_guides.push((soft_wrap as usize, true));
20459                }
20460                SoftWrap::Bounded(soft_wrap) => {
20461                    wrap_guides.push((soft_wrap as usize, true));
20462                }
20463                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20464            }
20465            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20466        }
20467
20468        wrap_guides
20469    }
20470
20471    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20472        let settings = self.buffer.read(cx).language_settings(cx);
20473        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20474        match mode {
20475            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20476                SoftWrap::None
20477            }
20478            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20479            language_settings::SoftWrap::PreferredLineLength => {
20480                SoftWrap::Column(settings.preferred_line_length)
20481            }
20482            language_settings::SoftWrap::Bounded => {
20483                SoftWrap::Bounded(settings.preferred_line_length)
20484            }
20485        }
20486    }
20487
20488    pub fn set_soft_wrap_mode(
20489        &mut self,
20490        mode: language_settings::SoftWrap,
20491
20492        cx: &mut Context<Self>,
20493    ) {
20494        self.soft_wrap_mode_override = Some(mode);
20495        cx.notify();
20496    }
20497
20498    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20499        self.hard_wrap = hard_wrap;
20500        cx.notify();
20501    }
20502
20503    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20504        self.text_style_refinement = Some(style);
20505    }
20506
20507    /// called by the Element so we know what style we were most recently rendered with.
20508    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20509        // We intentionally do not inform the display map about the minimap style
20510        // so that wrapping is not recalculated and stays consistent for the editor
20511        // and its linked minimap.
20512        if !self.mode.is_minimap() {
20513            let font = style.text.font();
20514            let font_size = style.text.font_size.to_pixels(window.rem_size());
20515            let display_map = self
20516                .placeholder_display_map
20517                .as_ref()
20518                .filter(|_| self.is_empty(cx))
20519                .unwrap_or(&self.display_map);
20520
20521            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20522        }
20523        self.style = Some(style);
20524    }
20525
20526    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20527        if self.style.is_none() {
20528            self.style = Some(self.create_style(cx));
20529        }
20530        self.style.as_ref().unwrap()
20531    }
20532
20533    // Called by the element. This method is not designed to be called outside of the editor
20534    // element's layout code because it does not notify when rewrapping is computed synchronously.
20535    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20536        if self.is_empty(cx) {
20537            self.placeholder_display_map
20538                .as_ref()
20539                .map_or(false, |display_map| {
20540                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20541                })
20542        } else {
20543            self.display_map
20544                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20545        }
20546    }
20547
20548    pub fn set_soft_wrap(&mut self) {
20549        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20550    }
20551
20552    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20553        if self.soft_wrap_mode_override.is_some() {
20554            self.soft_wrap_mode_override.take();
20555        } else {
20556            let soft_wrap = match self.soft_wrap_mode(cx) {
20557                SoftWrap::GitDiff => return,
20558                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20559                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20560                    language_settings::SoftWrap::None
20561                }
20562            };
20563            self.soft_wrap_mode_override = Some(soft_wrap);
20564        }
20565        cx.notify();
20566    }
20567
20568    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20569        let Some(workspace) = self.workspace() else {
20570            return;
20571        };
20572        let fs = workspace.read(cx).app_state().fs.clone();
20573        let current_show = TabBarSettings::get_global(cx).show;
20574        update_settings_file(fs, cx, move |setting, _| {
20575            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20576        });
20577    }
20578
20579    pub fn toggle_indent_guides(
20580        &mut self,
20581        _: &ToggleIndentGuides,
20582        _: &mut Window,
20583        cx: &mut Context<Self>,
20584    ) {
20585        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20586            self.buffer
20587                .read(cx)
20588                .language_settings(cx)
20589                .indent_guides
20590                .enabled
20591        });
20592        self.show_indent_guides = Some(!currently_enabled);
20593        cx.notify();
20594    }
20595
20596    fn should_show_indent_guides(&self) -> Option<bool> {
20597        self.show_indent_guides
20598    }
20599
20600    pub fn disable_indent_guides_for_buffer(
20601        &mut self,
20602        buffer_id: BufferId,
20603        cx: &mut Context<Self>,
20604    ) {
20605        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20606        cx.notify();
20607    }
20608
20609    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20610        self.buffers_with_disabled_indent_guides
20611            .contains(&buffer_id)
20612    }
20613
20614    pub fn toggle_line_numbers(
20615        &mut self,
20616        _: &ToggleLineNumbers,
20617        _: &mut Window,
20618        cx: &mut Context<Self>,
20619    ) {
20620        let mut editor_settings = EditorSettings::get_global(cx).clone();
20621        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20622        EditorSettings::override_global(editor_settings, cx);
20623    }
20624
20625    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20626        if let Some(show_line_numbers) = self.show_line_numbers {
20627            return show_line_numbers;
20628        }
20629        EditorSettings::get_global(cx).gutter.line_numbers
20630    }
20631
20632    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20633        match (
20634            self.use_relative_line_numbers,
20635            EditorSettings::get_global(cx).relative_line_numbers,
20636        ) {
20637            (None, setting) => setting,
20638            (Some(false), _) => RelativeLineNumbers::Disabled,
20639            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20640            (Some(true), _) => RelativeLineNumbers::Enabled,
20641        }
20642    }
20643
20644    pub fn toggle_relative_line_numbers(
20645        &mut self,
20646        _: &ToggleRelativeLineNumbers,
20647        _: &mut Window,
20648        cx: &mut Context<Self>,
20649    ) {
20650        let is_relative = self.relative_line_numbers(cx);
20651        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20652    }
20653
20654    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20655        self.use_relative_line_numbers = is_relative;
20656        cx.notify();
20657    }
20658
20659    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20660        self.show_gutter = show_gutter;
20661        cx.notify();
20662    }
20663
20664    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20665        self.show_scrollbars = ScrollbarAxes {
20666            horizontal: show,
20667            vertical: show,
20668        };
20669        cx.notify();
20670    }
20671
20672    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20673        self.show_scrollbars.vertical = show;
20674        cx.notify();
20675    }
20676
20677    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20678        self.show_scrollbars.horizontal = show;
20679        cx.notify();
20680    }
20681
20682    pub fn set_minimap_visibility(
20683        &mut self,
20684        minimap_visibility: MinimapVisibility,
20685        window: &mut Window,
20686        cx: &mut Context<Self>,
20687    ) {
20688        if self.minimap_visibility != minimap_visibility {
20689            if minimap_visibility.visible() && self.minimap.is_none() {
20690                let minimap_settings = EditorSettings::get_global(cx).minimap;
20691                self.minimap =
20692                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20693            }
20694            self.minimap_visibility = minimap_visibility;
20695            cx.notify();
20696        }
20697    }
20698
20699    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20700        self.set_show_scrollbars(false, cx);
20701        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20702    }
20703
20704    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20705        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20706    }
20707
20708    /// Normally the text in full mode and auto height editors is padded on the
20709    /// left side by roughly half a character width for improved hit testing.
20710    ///
20711    /// Use this method to disable this for cases where this is not wanted (e.g.
20712    /// if you want to align the editor text with some other text above or below)
20713    /// or if you want to add this padding to single-line editors.
20714    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20715        self.offset_content = offset_content;
20716        cx.notify();
20717    }
20718
20719    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20720        self.show_line_numbers = Some(show_line_numbers);
20721        cx.notify();
20722    }
20723
20724    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20725        self.disable_expand_excerpt_buttons = true;
20726        cx.notify();
20727    }
20728
20729    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
20730        self.delegate_expand_excerpts = delegate;
20731    }
20732
20733    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20734        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20735        cx.notify();
20736    }
20737
20738    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20739        self.show_code_actions = Some(show_code_actions);
20740        cx.notify();
20741    }
20742
20743    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20744        self.show_runnables = Some(show_runnables);
20745        cx.notify();
20746    }
20747
20748    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20749        self.show_breakpoints = Some(show_breakpoints);
20750        cx.notify();
20751    }
20752
20753    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
20754        self.show_diff_review_button = show;
20755        cx.notify();
20756    }
20757
20758    pub fn show_diff_review_button(&self) -> bool {
20759        self.show_diff_review_button
20760    }
20761
20762    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20763        if self.display_map.read(cx).masked != masked {
20764            self.display_map.update(cx, |map, _| map.masked = masked);
20765        }
20766        cx.notify()
20767    }
20768
20769    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20770        self.show_wrap_guides = Some(show_wrap_guides);
20771        cx.notify();
20772    }
20773
20774    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20775        self.show_indent_guides = Some(show_indent_guides);
20776        cx.notify();
20777    }
20778
20779    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20780        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20781            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20782                && let Some(dir) = file.abs_path(cx).parent()
20783            {
20784                return Some(dir.to_owned());
20785            }
20786        }
20787
20788        None
20789    }
20790
20791    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20792        self.active_excerpt(cx)?
20793            .1
20794            .read(cx)
20795            .file()
20796            .and_then(|f| f.as_local())
20797    }
20798
20799    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20800        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20801            let buffer = buffer.read(cx);
20802            if let Some(project_path) = buffer.project_path(cx) {
20803                let project = self.project()?.read(cx);
20804                project.absolute_path(&project_path, cx)
20805            } else {
20806                buffer
20807                    .file()
20808                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20809            }
20810        })
20811    }
20812
20813    pub fn reveal_in_finder(
20814        &mut self,
20815        _: &RevealInFileManager,
20816        _window: &mut Window,
20817        cx: &mut Context<Self>,
20818    ) {
20819        if let Some(target) = self.target_file(cx) {
20820            cx.reveal_path(&target.abs_path(cx));
20821        }
20822    }
20823
20824    pub fn copy_path(
20825        &mut self,
20826        _: &zed_actions::workspace::CopyPath,
20827        _window: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) {
20830        if let Some(path) = self.target_file_abs_path(cx)
20831            && let Some(path) = path.to_str()
20832        {
20833            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20834        } else {
20835            cx.propagate();
20836        }
20837    }
20838
20839    pub fn copy_relative_path(
20840        &mut self,
20841        _: &zed_actions::workspace::CopyRelativePath,
20842        _window: &mut Window,
20843        cx: &mut Context<Self>,
20844    ) {
20845        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20846            let project = self.project()?.read(cx);
20847            let path = buffer.read(cx).file()?.path();
20848            let path = path.display(project.path_style(cx));
20849            Some(path)
20850        }) {
20851            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20852        } else {
20853            cx.propagate();
20854        }
20855    }
20856
20857    /// Returns the project path for the editor's buffer, if any buffer is
20858    /// opened in the editor.
20859    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20860        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20861            buffer.read(cx).project_path(cx)
20862        } else {
20863            None
20864        }
20865    }
20866
20867    // Returns true if the editor handled a go-to-line request
20868    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20869        maybe!({
20870            let breakpoint_store = self.breakpoint_store.as_ref()?;
20871
20872            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20873            else {
20874                self.clear_row_highlights::<ActiveDebugLine>();
20875                return None;
20876            };
20877
20878            let position = active_stack_frame.position;
20879            let buffer_id = position.buffer_id?;
20880            let snapshot = self
20881                .project
20882                .as_ref()?
20883                .read(cx)
20884                .buffer_for_id(buffer_id, cx)?
20885                .read(cx)
20886                .snapshot();
20887
20888            let mut handled = false;
20889            for (id, ExcerptRange { context, .. }) in
20890                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20891            {
20892                if context.start.cmp(&position, &snapshot).is_ge()
20893                    || context.end.cmp(&position, &snapshot).is_lt()
20894                {
20895                    continue;
20896                }
20897                let snapshot = self.buffer.read(cx).snapshot(cx);
20898                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20899
20900                handled = true;
20901                self.clear_row_highlights::<ActiveDebugLine>();
20902
20903                self.go_to_line::<ActiveDebugLine>(
20904                    multibuffer_anchor,
20905                    Some(cx.theme().colors().editor_debugger_active_line_background),
20906                    window,
20907                    cx,
20908                );
20909
20910                cx.notify();
20911            }
20912
20913            handled.then_some(())
20914        })
20915        .is_some()
20916    }
20917
20918    pub fn copy_file_name_without_extension(
20919        &mut self,
20920        _: &CopyFileNameWithoutExtension,
20921        _: &mut Window,
20922        cx: &mut Context<Self>,
20923    ) {
20924        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20925            let file = buffer.read(cx).file()?;
20926            file.path().file_stem()
20927        }) {
20928            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20929        }
20930    }
20931
20932    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20933        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20934            let file = buffer.read(cx).file()?;
20935            Some(file.file_name(cx))
20936        }) {
20937            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20938        }
20939    }
20940
20941    pub fn toggle_git_blame(
20942        &mut self,
20943        _: &::git::Blame,
20944        window: &mut Window,
20945        cx: &mut Context<Self>,
20946    ) {
20947        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20948
20949        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20950            self.start_git_blame(true, window, cx);
20951        }
20952
20953        cx.notify();
20954    }
20955
20956    pub fn toggle_git_blame_inline(
20957        &mut self,
20958        _: &ToggleGitBlameInline,
20959        window: &mut Window,
20960        cx: &mut Context<Self>,
20961    ) {
20962        self.toggle_git_blame_inline_internal(true, window, cx);
20963        cx.notify();
20964    }
20965
20966    pub fn open_git_blame_commit(
20967        &mut self,
20968        _: &OpenGitBlameCommit,
20969        window: &mut Window,
20970        cx: &mut Context<Self>,
20971    ) {
20972        self.open_git_blame_commit_internal(window, cx);
20973    }
20974
20975    fn open_git_blame_commit_internal(
20976        &mut self,
20977        window: &mut Window,
20978        cx: &mut Context<Self>,
20979    ) -> Option<()> {
20980        let blame = self.blame.as_ref()?;
20981        let snapshot = self.snapshot(window, cx);
20982        let cursor = self
20983            .selections
20984            .newest::<Point>(&snapshot.display_snapshot)
20985            .head();
20986        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20987        let (_, blame_entry) = blame
20988            .update(cx, |blame, cx| {
20989                blame
20990                    .blame_for_rows(
20991                        &[RowInfo {
20992                            buffer_id: Some(buffer.remote_id()),
20993                            buffer_row: Some(point.row),
20994                            ..Default::default()
20995                        }],
20996                        cx,
20997                    )
20998                    .next()
20999            })
21000            .flatten()?;
21001        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21002        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
21003        let workspace = self.workspace()?.downgrade();
21004        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
21005        None
21006    }
21007
21008    pub fn git_blame_inline_enabled(&self) -> bool {
21009        self.git_blame_inline_enabled
21010    }
21011
21012    pub fn toggle_selection_menu(
21013        &mut self,
21014        _: &ToggleSelectionMenu,
21015        _: &mut Window,
21016        cx: &mut Context<Self>,
21017    ) {
21018        self.show_selection_menu = self
21019            .show_selection_menu
21020            .map(|show_selections_menu| !show_selections_menu)
21021            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
21022
21023        cx.notify();
21024    }
21025
21026    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
21027        self.show_selection_menu
21028            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
21029    }
21030
21031    fn start_git_blame(
21032        &mut self,
21033        user_triggered: bool,
21034        window: &mut Window,
21035        cx: &mut Context<Self>,
21036    ) {
21037        if let Some(project) = self.project() {
21038            if let Some(buffer) = self.buffer().read(cx).as_singleton()
21039                && buffer.read(cx).file().is_none()
21040            {
21041                return;
21042            }
21043
21044            let focused = self.focus_handle(cx).contains_focused(window, cx);
21045
21046            let project = project.clone();
21047            let blame = cx
21048                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
21049            self.blame_subscription =
21050                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
21051            self.blame = Some(blame);
21052        }
21053    }
21054
21055    fn toggle_git_blame_inline_internal(
21056        &mut self,
21057        user_triggered: bool,
21058        window: &mut Window,
21059        cx: &mut Context<Self>,
21060    ) {
21061        if self.git_blame_inline_enabled {
21062            self.git_blame_inline_enabled = false;
21063            self.show_git_blame_inline = false;
21064            self.show_git_blame_inline_delay_task.take();
21065        } else {
21066            self.git_blame_inline_enabled = true;
21067            self.start_git_blame_inline(user_triggered, window, cx);
21068        }
21069
21070        cx.notify();
21071    }
21072
21073    fn start_git_blame_inline(
21074        &mut self,
21075        user_triggered: bool,
21076        window: &mut Window,
21077        cx: &mut Context<Self>,
21078    ) {
21079        self.start_git_blame(user_triggered, window, cx);
21080
21081        if ProjectSettings::get_global(cx)
21082            .git
21083            .inline_blame_delay()
21084            .is_some()
21085        {
21086            self.start_inline_blame_timer(window, cx);
21087        } else {
21088            self.show_git_blame_inline = true
21089        }
21090    }
21091
21092    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21093        self.blame.as_ref()
21094    }
21095
21096    pub fn show_git_blame_gutter(&self) -> bool {
21097        self.show_git_blame_gutter
21098    }
21099
21100    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21101        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21102    }
21103
21104    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21105        self.show_git_blame_inline
21106            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21107            && !self.newest_selection_head_on_empty_line(cx)
21108            && self.has_blame_entries(cx)
21109    }
21110
21111    fn has_blame_entries(&self, cx: &App) -> bool {
21112        self.blame()
21113            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21114    }
21115
21116    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21117        let cursor_anchor = self.selections.newest_anchor().head();
21118
21119        let snapshot = self.buffer.read(cx).snapshot(cx);
21120        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21121
21122        snapshot.line_len(buffer_row) == 0
21123    }
21124
21125    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21126        let buffer_and_selection = maybe!({
21127            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21128            let selection_range = selection.range();
21129
21130            let multi_buffer = self.buffer().read(cx);
21131            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21132            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21133
21134            let (buffer, range, _) = if selection.reversed {
21135                buffer_ranges.first()
21136            } else {
21137                buffer_ranges.last()
21138            }?;
21139
21140            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21141            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21142
21143            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21144                let selection = start_row_in_buffer..end_row_in_buffer;
21145
21146                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21147            };
21148
21149            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21150
21151            Some((
21152                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21153                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, Bias::Left, buffer)
21154                    ..buffer_diff_snapshot.row_to_base_text_row(
21155                        end_row_in_buffer,
21156                        Bias::Left,
21157                        buffer,
21158                    ),
21159            ))
21160        });
21161
21162        let Some((buffer, selection)) = buffer_and_selection else {
21163            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21164        };
21165
21166        let Some(project) = self.project() else {
21167            return Task::ready(Err(anyhow!("editor does not have project")));
21168        };
21169
21170        project.update(cx, |project, cx| {
21171            project.get_permalink_to_line(&buffer, selection, cx)
21172        })
21173    }
21174
21175    pub fn copy_permalink_to_line(
21176        &mut self,
21177        _: &CopyPermalinkToLine,
21178        window: &mut Window,
21179        cx: &mut Context<Self>,
21180    ) {
21181        let permalink_task = self.get_permalink_to_line(cx);
21182        let workspace = self.workspace();
21183
21184        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21185            Ok(permalink) => {
21186                cx.update(|_, cx| {
21187                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21188                })
21189                .ok();
21190            }
21191            Err(err) => {
21192                let message = format!("Failed to copy permalink: {err}");
21193
21194                anyhow::Result::<()>::Err(err).log_err();
21195
21196                if let Some(workspace) = workspace {
21197                    workspace
21198                        .update_in(cx, |workspace, _, cx| {
21199                            struct CopyPermalinkToLine;
21200
21201                            workspace.show_toast(
21202                                Toast::new(
21203                                    NotificationId::unique::<CopyPermalinkToLine>(),
21204                                    message,
21205                                ),
21206                                cx,
21207                            )
21208                        })
21209                        .ok();
21210                }
21211            }
21212        })
21213        .detach();
21214    }
21215
21216    pub fn copy_file_location(
21217        &mut self,
21218        _: &CopyFileLocation,
21219        _: &mut Window,
21220        cx: &mut Context<Self>,
21221    ) {
21222        let selection = self
21223            .selections
21224            .newest::<Point>(&self.display_snapshot(cx))
21225            .start
21226            .row
21227            + 1;
21228        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21229            let project = self.project()?.read(cx);
21230            let file = buffer.read(cx).file()?;
21231            let path = file.path().display(project.path_style(cx));
21232
21233            Some(format!("{path}:{selection}"))
21234        }) {
21235            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21236        }
21237    }
21238
21239    pub fn open_permalink_to_line(
21240        &mut self,
21241        _: &OpenPermalinkToLine,
21242        window: &mut Window,
21243        cx: &mut Context<Self>,
21244    ) {
21245        let permalink_task = self.get_permalink_to_line(cx);
21246        let workspace = self.workspace();
21247
21248        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21249            Ok(permalink) => {
21250                cx.update(|_, cx| {
21251                    cx.open_url(permalink.as_ref());
21252                })
21253                .ok();
21254            }
21255            Err(err) => {
21256                let message = format!("Failed to open permalink: {err}");
21257
21258                anyhow::Result::<()>::Err(err).log_err();
21259
21260                if let Some(workspace) = workspace {
21261                    workspace.update(cx, |workspace, cx| {
21262                        struct OpenPermalinkToLine;
21263
21264                        workspace.show_toast(
21265                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
21266                            cx,
21267                        )
21268                    });
21269                }
21270            }
21271        })
21272        .detach();
21273    }
21274
21275    pub fn insert_uuid_v4(
21276        &mut self,
21277        _: &InsertUuidV4,
21278        window: &mut Window,
21279        cx: &mut Context<Self>,
21280    ) {
21281        self.insert_uuid(UuidVersion::V4, window, cx);
21282    }
21283
21284    pub fn insert_uuid_v7(
21285        &mut self,
21286        _: &InsertUuidV7,
21287        window: &mut Window,
21288        cx: &mut Context<Self>,
21289    ) {
21290        self.insert_uuid(UuidVersion::V7, window, cx);
21291    }
21292
21293    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21294        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21295        self.transact(window, cx, |this, window, cx| {
21296            let edits = this
21297                .selections
21298                .all::<Point>(&this.display_snapshot(cx))
21299                .into_iter()
21300                .map(|selection| {
21301                    let uuid = match version {
21302                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21303                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21304                    };
21305
21306                    (selection.range(), uuid.to_string())
21307                });
21308            this.edit(edits, cx);
21309            this.refresh_edit_prediction(true, false, window, cx);
21310        });
21311    }
21312
21313    pub fn open_selections_in_multibuffer(
21314        &mut self,
21315        _: &OpenSelectionsInMultibuffer,
21316        window: &mut Window,
21317        cx: &mut Context<Self>,
21318    ) {
21319        let multibuffer = self.buffer.read(cx);
21320
21321        let Some(buffer) = multibuffer.as_singleton() else {
21322            return;
21323        };
21324
21325        let Some(workspace) = self.workspace() else {
21326            return;
21327        };
21328
21329        let title = multibuffer.title(cx).to_string();
21330
21331        let locations = self
21332            .selections
21333            .all_anchors(&self.display_snapshot(cx))
21334            .iter()
21335            .map(|selection| {
21336                (
21337                    buffer.clone(),
21338                    (selection.start.text_anchor..selection.end.text_anchor)
21339                        .to_point(buffer.read(cx)),
21340                )
21341            })
21342            .into_group_map();
21343
21344        cx.spawn_in(window, async move |_, cx| {
21345            workspace.update_in(cx, |workspace, window, cx| {
21346                Self::open_locations_in_multibuffer(
21347                    workspace,
21348                    locations,
21349                    format!("Selections for '{title}'"),
21350                    false,
21351                    false,
21352                    MultibufferSelectionMode::All,
21353                    window,
21354                    cx,
21355                );
21356            })
21357        })
21358        .detach();
21359    }
21360
21361    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21362    /// last highlight added will be used.
21363    ///
21364    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21365    pub fn highlight_rows<T: 'static>(
21366        &mut self,
21367        range: Range<Anchor>,
21368        color: Hsla,
21369        options: RowHighlightOptions,
21370        cx: &mut Context<Self>,
21371    ) {
21372        let snapshot = self.buffer().read(cx).snapshot(cx);
21373        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21374        let ix = row_highlights.binary_search_by(|highlight| {
21375            Ordering::Equal
21376                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21377                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21378        });
21379
21380        if let Err(mut ix) = ix {
21381            let index = post_inc(&mut self.highlight_order);
21382
21383            // If this range intersects with the preceding highlight, then merge it with
21384            // the preceding highlight. Otherwise insert a new highlight.
21385            let mut merged = false;
21386            if ix > 0 {
21387                let prev_highlight = &mut row_highlights[ix - 1];
21388                if prev_highlight
21389                    .range
21390                    .end
21391                    .cmp(&range.start, &snapshot)
21392                    .is_ge()
21393                {
21394                    ix -= 1;
21395                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21396                        prev_highlight.range.end = range.end;
21397                    }
21398                    merged = true;
21399                    prev_highlight.index = index;
21400                    prev_highlight.color = color;
21401                    prev_highlight.options = options;
21402                }
21403            }
21404
21405            if !merged {
21406                row_highlights.insert(
21407                    ix,
21408                    RowHighlight {
21409                        range,
21410                        index,
21411                        color,
21412                        options,
21413                        type_id: TypeId::of::<T>(),
21414                    },
21415                );
21416            }
21417
21418            // If any of the following highlights intersect with this one, merge them.
21419            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21420                let highlight = &row_highlights[ix];
21421                if next_highlight
21422                    .range
21423                    .start
21424                    .cmp(&highlight.range.end, &snapshot)
21425                    .is_le()
21426                {
21427                    if next_highlight
21428                        .range
21429                        .end
21430                        .cmp(&highlight.range.end, &snapshot)
21431                        .is_gt()
21432                    {
21433                        row_highlights[ix].range.end = next_highlight.range.end;
21434                    }
21435                    row_highlights.remove(ix + 1);
21436                } else {
21437                    break;
21438                }
21439            }
21440        }
21441    }
21442
21443    /// Remove any highlighted row ranges of the given type that intersect the
21444    /// given ranges.
21445    pub fn remove_highlighted_rows<T: 'static>(
21446        &mut self,
21447        ranges_to_remove: Vec<Range<Anchor>>,
21448        cx: &mut Context<Self>,
21449    ) {
21450        let snapshot = self.buffer().read(cx).snapshot(cx);
21451        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21452        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21453        row_highlights.retain(|highlight| {
21454            while let Some(range_to_remove) = ranges_to_remove.peek() {
21455                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21456                    Ordering::Less | Ordering::Equal => {
21457                        ranges_to_remove.next();
21458                    }
21459                    Ordering::Greater => {
21460                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21461                            Ordering::Less | Ordering::Equal => {
21462                                return false;
21463                            }
21464                            Ordering::Greater => break,
21465                        }
21466                    }
21467                }
21468            }
21469
21470            true
21471        })
21472    }
21473
21474    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21475    pub fn clear_row_highlights<T: 'static>(&mut self) {
21476        self.highlighted_rows.remove(&TypeId::of::<T>());
21477    }
21478
21479    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21480    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21481        self.highlighted_rows
21482            .get(&TypeId::of::<T>())
21483            .map_or(&[] as &[_], |vec| vec.as_slice())
21484            .iter()
21485            .map(|highlight| (highlight.range.clone(), highlight.color))
21486    }
21487
21488    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21489    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21490    /// Allows to ignore certain kinds of highlights.
21491    pub fn highlighted_display_rows(
21492        &self,
21493        window: &mut Window,
21494        cx: &mut App,
21495    ) -> BTreeMap<DisplayRow, LineHighlight> {
21496        let snapshot = self.snapshot(window, cx);
21497        let mut used_highlight_orders = HashMap::default();
21498        self.highlighted_rows
21499            .iter()
21500            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21501            .fold(
21502                BTreeMap::<DisplayRow, LineHighlight>::new(),
21503                |mut unique_rows, highlight| {
21504                    let start = highlight.range.start.to_display_point(&snapshot);
21505                    let end = highlight.range.end.to_display_point(&snapshot);
21506                    let start_row = start.row().0;
21507                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21508                    {
21509                        end.row().0.saturating_sub(1)
21510                    } else {
21511                        end.row().0
21512                    };
21513                    for row in start_row..=end_row {
21514                        let used_index =
21515                            used_highlight_orders.entry(row).or_insert(highlight.index);
21516                        if highlight.index >= *used_index {
21517                            *used_index = highlight.index;
21518                            unique_rows.insert(
21519                                DisplayRow(row),
21520                                LineHighlight {
21521                                    include_gutter: highlight.options.include_gutter,
21522                                    border: None,
21523                                    background: highlight.color.into(),
21524                                    type_id: Some(highlight.type_id),
21525                                },
21526                            );
21527                        }
21528                    }
21529                    unique_rows
21530                },
21531            )
21532    }
21533
21534    pub fn highlighted_display_row_for_autoscroll(
21535        &self,
21536        snapshot: &DisplaySnapshot,
21537    ) -> Option<DisplayRow> {
21538        self.highlighted_rows
21539            .values()
21540            .flat_map(|highlighted_rows| highlighted_rows.iter())
21541            .filter_map(|highlight| {
21542                if highlight.options.autoscroll {
21543                    Some(highlight.range.start.to_display_point(snapshot).row())
21544                } else {
21545                    None
21546                }
21547            })
21548            .min()
21549    }
21550
21551    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21552        self.highlight_background::<SearchWithinRange>(
21553            ranges,
21554            |_, colors| colors.colors().editor_document_highlight_read_background,
21555            cx,
21556        )
21557    }
21558
21559    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21560        self.breadcrumb_header = Some(new_header);
21561    }
21562
21563    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21564        self.clear_background_highlights::<SearchWithinRange>(cx);
21565    }
21566
21567    pub fn highlight_background<T: 'static>(
21568        &mut self,
21569        ranges: &[Range<Anchor>],
21570        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21571        cx: &mut Context<Self>,
21572    ) {
21573        self.background_highlights.insert(
21574            HighlightKey::Type(TypeId::of::<T>()),
21575            (Arc::new(color_fetcher), Arc::from(ranges)),
21576        );
21577        self.scrollbar_marker_state.dirty = true;
21578        cx.notify();
21579    }
21580
21581    pub fn highlight_background_key<T: 'static>(
21582        &mut self,
21583        key: usize,
21584        ranges: &[Range<Anchor>],
21585        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21586        cx: &mut Context<Self>,
21587    ) {
21588        self.background_highlights.insert(
21589            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21590            (Arc::new(color_fetcher), Arc::from(ranges)),
21591        );
21592        self.scrollbar_marker_state.dirty = true;
21593        cx.notify();
21594    }
21595
21596    pub fn clear_background_highlights<T: 'static>(
21597        &mut self,
21598        cx: &mut Context<Self>,
21599    ) -> Option<BackgroundHighlight> {
21600        let text_highlights = self
21601            .background_highlights
21602            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21603        if !text_highlights.1.is_empty() {
21604            self.scrollbar_marker_state.dirty = true;
21605            cx.notify();
21606        }
21607        Some(text_highlights)
21608    }
21609
21610    pub fn highlight_gutter<T: 'static>(
21611        &mut self,
21612        ranges: impl Into<Vec<Range<Anchor>>>,
21613        color_fetcher: fn(&App) -> Hsla,
21614        cx: &mut Context<Self>,
21615    ) {
21616        self.gutter_highlights
21617            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21618        cx.notify();
21619    }
21620
21621    pub fn clear_gutter_highlights<T: 'static>(
21622        &mut self,
21623        cx: &mut Context<Self>,
21624    ) -> Option<GutterHighlight> {
21625        cx.notify();
21626        self.gutter_highlights.remove(&TypeId::of::<T>())
21627    }
21628
21629    pub fn insert_gutter_highlight<T: 'static>(
21630        &mut self,
21631        range: Range<Anchor>,
21632        color_fetcher: fn(&App) -> Hsla,
21633        cx: &mut Context<Self>,
21634    ) {
21635        let snapshot = self.buffer().read(cx).snapshot(cx);
21636        let mut highlights = self
21637            .gutter_highlights
21638            .remove(&TypeId::of::<T>())
21639            .map(|(_, highlights)| highlights)
21640            .unwrap_or_default();
21641        let ix = highlights.binary_search_by(|highlight| {
21642            Ordering::Equal
21643                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21644                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21645        });
21646        if let Err(ix) = ix {
21647            highlights.insert(ix, range);
21648        }
21649        self.gutter_highlights
21650            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21651    }
21652
21653    pub fn remove_gutter_highlights<T: 'static>(
21654        &mut self,
21655        ranges_to_remove: Vec<Range<Anchor>>,
21656        cx: &mut Context<Self>,
21657    ) {
21658        let snapshot = self.buffer().read(cx).snapshot(cx);
21659        let Some((color_fetcher, mut gutter_highlights)) =
21660            self.gutter_highlights.remove(&TypeId::of::<T>())
21661        else {
21662            return;
21663        };
21664        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21665        gutter_highlights.retain(|highlight| {
21666            while let Some(range_to_remove) = ranges_to_remove.peek() {
21667                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21668                    Ordering::Less | Ordering::Equal => {
21669                        ranges_to_remove.next();
21670                    }
21671                    Ordering::Greater => {
21672                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21673                            Ordering::Less | Ordering::Equal => {
21674                                return false;
21675                            }
21676                            Ordering::Greater => break,
21677                        }
21678                    }
21679                }
21680            }
21681
21682            true
21683        });
21684        self.gutter_highlights
21685            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21686    }
21687
21688    #[cfg(feature = "test-support")]
21689    pub fn all_text_highlights(
21690        &self,
21691        window: &mut Window,
21692        cx: &mut Context<Self>,
21693    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21694        let snapshot = self.snapshot(window, cx);
21695        self.display_map.update(cx, |display_map, _| {
21696            display_map
21697                .all_text_highlights()
21698                .map(|highlight| {
21699                    let (style, ranges) = highlight.as_ref();
21700                    (
21701                        *style,
21702                        ranges
21703                            .iter()
21704                            .map(|range| range.clone().to_display_points(&snapshot))
21705                            .collect(),
21706                    )
21707                })
21708                .collect()
21709        })
21710    }
21711
21712    #[cfg(feature = "test-support")]
21713    pub fn all_text_background_highlights(
21714        &self,
21715        window: &mut Window,
21716        cx: &mut Context<Self>,
21717    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21718        let snapshot = self.snapshot(window, cx);
21719        let buffer = &snapshot.buffer_snapshot();
21720        let start = buffer.anchor_before(MultiBufferOffset(0));
21721        let end = buffer.anchor_after(buffer.len());
21722        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21723    }
21724
21725    #[cfg(any(test, feature = "test-support"))]
21726    pub fn sorted_background_highlights_in_range(
21727        &self,
21728        search_range: Range<Anchor>,
21729        display_snapshot: &DisplaySnapshot,
21730        theme: &Theme,
21731    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21732        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21733        res.sort_by(|a, b| {
21734            a.0.start
21735                .cmp(&b.0.start)
21736                .then_with(|| a.0.end.cmp(&b.0.end))
21737                .then_with(|| a.1.cmp(&b.1))
21738        });
21739        res
21740    }
21741
21742    #[cfg(feature = "test-support")]
21743    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21744        let snapshot = self.buffer().read(cx).snapshot(cx);
21745
21746        let highlights = self
21747            .background_highlights
21748            .get(&HighlightKey::Type(TypeId::of::<
21749                items::BufferSearchHighlights,
21750            >()));
21751
21752        if let Some((_color, ranges)) = highlights {
21753            ranges
21754                .iter()
21755                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21756                .collect_vec()
21757        } else {
21758            vec![]
21759        }
21760    }
21761
21762    fn document_highlights_for_position<'a>(
21763        &'a self,
21764        position: Anchor,
21765        buffer: &'a MultiBufferSnapshot,
21766    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21767        let read_highlights = self
21768            .background_highlights
21769            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21770            .map(|h| &h.1);
21771        let write_highlights = self
21772            .background_highlights
21773            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21774            .map(|h| &h.1);
21775        let left_position = position.bias_left(buffer);
21776        let right_position = position.bias_right(buffer);
21777        read_highlights
21778            .into_iter()
21779            .chain(write_highlights)
21780            .flat_map(move |ranges| {
21781                let start_ix = match ranges.binary_search_by(|probe| {
21782                    let cmp = probe.end.cmp(&left_position, buffer);
21783                    if cmp.is_ge() {
21784                        Ordering::Greater
21785                    } else {
21786                        Ordering::Less
21787                    }
21788                }) {
21789                    Ok(i) | Err(i) => i,
21790                };
21791
21792                ranges[start_ix..]
21793                    .iter()
21794                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21795            })
21796    }
21797
21798    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21799        self.background_highlights
21800            .get(&HighlightKey::Type(TypeId::of::<T>()))
21801            .is_some_and(|(_, highlights)| !highlights.is_empty())
21802    }
21803
21804    /// Returns all background highlights for a given range.
21805    ///
21806    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21807    pub fn background_highlights_in_range(
21808        &self,
21809        search_range: Range<Anchor>,
21810        display_snapshot: &DisplaySnapshot,
21811        theme: &Theme,
21812    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21813        let mut results = Vec::new();
21814        for (color_fetcher, ranges) in self.background_highlights.values() {
21815            let start_ix = match ranges.binary_search_by(|probe| {
21816                let cmp = probe
21817                    .end
21818                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21819                if cmp.is_gt() {
21820                    Ordering::Greater
21821                } else {
21822                    Ordering::Less
21823                }
21824            }) {
21825                Ok(i) | Err(i) => i,
21826            };
21827            for (index, range) in ranges[start_ix..].iter().enumerate() {
21828                if range
21829                    .start
21830                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21831                    .is_ge()
21832                {
21833                    break;
21834                }
21835
21836                let color = color_fetcher(&(start_ix + index), theme);
21837                let start = range.start.to_display_point(display_snapshot);
21838                let end = range.end.to_display_point(display_snapshot);
21839                results.push((start..end, color))
21840            }
21841        }
21842        results
21843    }
21844
21845    pub fn gutter_highlights_in_range(
21846        &self,
21847        search_range: Range<Anchor>,
21848        display_snapshot: &DisplaySnapshot,
21849        cx: &App,
21850    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21851        let mut results = Vec::new();
21852        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21853            let color = color_fetcher(cx);
21854            let start_ix = match ranges.binary_search_by(|probe| {
21855                let cmp = probe
21856                    .end
21857                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21858                if cmp.is_gt() {
21859                    Ordering::Greater
21860                } else {
21861                    Ordering::Less
21862                }
21863            }) {
21864                Ok(i) | Err(i) => i,
21865            };
21866            for range in &ranges[start_ix..] {
21867                if range
21868                    .start
21869                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21870                    .is_ge()
21871                {
21872                    break;
21873                }
21874
21875                let start = range.start.to_display_point(display_snapshot);
21876                let end = range.end.to_display_point(display_snapshot);
21877                results.push((start..end, color))
21878            }
21879        }
21880        results
21881    }
21882
21883    /// Get the text ranges corresponding to the redaction query
21884    pub fn redacted_ranges(
21885        &self,
21886        search_range: Range<Anchor>,
21887        display_snapshot: &DisplaySnapshot,
21888        cx: &App,
21889    ) -> Vec<Range<DisplayPoint>> {
21890        display_snapshot
21891            .buffer_snapshot()
21892            .redacted_ranges(search_range, |file| {
21893                if let Some(file) = file {
21894                    file.is_private()
21895                        && EditorSettings::get(
21896                            Some(SettingsLocation {
21897                                worktree_id: file.worktree_id(cx),
21898                                path: file.path().as_ref(),
21899                            }),
21900                            cx,
21901                        )
21902                        .redact_private_values
21903                } else {
21904                    false
21905                }
21906            })
21907            .map(|range| {
21908                range.start.to_display_point(display_snapshot)
21909                    ..range.end.to_display_point(display_snapshot)
21910            })
21911            .collect()
21912    }
21913
21914    pub fn highlight_text_key<T: 'static>(
21915        &mut self,
21916        key: usize,
21917        ranges: Vec<Range<Anchor>>,
21918        style: HighlightStyle,
21919        merge: bool,
21920        cx: &mut Context<Self>,
21921    ) {
21922        self.display_map.update(cx, |map, cx| {
21923            map.highlight_text(
21924                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21925                ranges,
21926                style,
21927                merge,
21928                cx,
21929            );
21930        });
21931        cx.notify();
21932    }
21933
21934    pub fn highlight_text<T: 'static>(
21935        &mut self,
21936        ranges: Vec<Range<Anchor>>,
21937        style: HighlightStyle,
21938        cx: &mut Context<Self>,
21939    ) {
21940        self.display_map.update(cx, |map, cx| {
21941            map.highlight_text(
21942                HighlightKey::Type(TypeId::of::<T>()),
21943                ranges,
21944                style,
21945                false,
21946                cx,
21947            )
21948        });
21949        cx.notify();
21950    }
21951
21952    pub fn text_highlights<'a, T: 'static>(
21953        &'a self,
21954        cx: &'a App,
21955    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21956        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21957    }
21958
21959    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21960        let cleared = self
21961            .display_map
21962            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21963        if cleared {
21964            cx.notify();
21965        }
21966    }
21967
21968    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21969        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21970            && self.focus_handle.is_focused(window)
21971    }
21972
21973    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21974        self.show_cursor_when_unfocused = is_enabled;
21975        cx.notify();
21976    }
21977
21978    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21979        cx.notify();
21980    }
21981
21982    fn on_debug_session_event(
21983        &mut self,
21984        _session: Entity<Session>,
21985        event: &SessionEvent,
21986        cx: &mut Context<Self>,
21987    ) {
21988        if let SessionEvent::InvalidateInlineValue = event {
21989            self.refresh_inline_values(cx);
21990        }
21991    }
21992
21993    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21994        let Some(project) = self.project.clone() else {
21995            return;
21996        };
21997
21998        if !self.inline_value_cache.enabled {
21999            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
22000            self.splice_inlays(&inlays, Vec::new(), cx);
22001            return;
22002        }
22003
22004        let current_execution_position = self
22005            .highlighted_rows
22006            .get(&TypeId::of::<ActiveDebugLine>())
22007            .and_then(|lines| lines.last().map(|line| line.range.end));
22008
22009        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
22010            let inline_values = editor
22011                .update(cx, |editor, cx| {
22012                    let Some(current_execution_position) = current_execution_position else {
22013                        return Some(Task::ready(Ok(Vec::new())));
22014                    };
22015
22016                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
22017                        let snapshot = buffer.snapshot(cx);
22018
22019                        let excerpt = snapshot.excerpt_containing(
22020                            current_execution_position..current_execution_position,
22021                        )?;
22022
22023                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
22024                    })?;
22025
22026                    let range =
22027                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
22028
22029                    project.inline_values(buffer, range, cx)
22030                })
22031                .ok()
22032                .flatten()?
22033                .await
22034                .context("refreshing debugger inlays")
22035                .log_err()?;
22036
22037            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
22038
22039            for (buffer_id, inline_value) in inline_values
22040                .into_iter()
22041                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
22042            {
22043                buffer_inline_values
22044                    .entry(buffer_id)
22045                    .or_default()
22046                    .push(inline_value);
22047            }
22048
22049            editor
22050                .update(cx, |editor, cx| {
22051                    let snapshot = editor.buffer.read(cx).snapshot(cx);
22052                    let mut new_inlays = Vec::default();
22053
22054                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
22055                        let buffer_id = buffer_snapshot.remote_id();
22056                        buffer_inline_values
22057                            .get(&buffer_id)
22058                            .into_iter()
22059                            .flatten()
22060                            .for_each(|hint| {
22061                                let inlay = Inlay::debugger(
22062                                    post_inc(&mut editor.next_inlay_id),
22063                                    Anchor::in_buffer(excerpt_id, hint.position),
22064                                    hint.text(),
22065                                );
22066                                if !inlay.text().chars().contains(&'\n') {
22067                                    new_inlays.push(inlay);
22068                                }
22069                            });
22070                    }
22071
22072                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22073                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22074
22075                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22076                })
22077                .ok()?;
22078            Some(())
22079        });
22080    }
22081
22082    fn on_buffer_event(
22083        &mut self,
22084        multibuffer: &Entity<MultiBuffer>,
22085        event: &multi_buffer::Event,
22086        window: &mut Window,
22087        cx: &mut Context<Self>,
22088    ) {
22089        match event {
22090            multi_buffer::Event::Edited { edited_buffer } => {
22091                self.scrollbar_marker_state.dirty = true;
22092                self.active_indent_guides_state.dirty = true;
22093                self.refresh_active_diagnostics(cx);
22094                self.refresh_code_actions(window, cx);
22095                self.refresh_single_line_folds(window, cx);
22096                self.refresh_matching_bracket_highlights(window, cx);
22097                if self.has_active_edit_prediction() {
22098                    self.update_visible_edit_prediction(window, cx);
22099                }
22100
22101                if let Some(buffer) = edited_buffer {
22102                    if buffer.read(cx).file().is_none() {
22103                        cx.emit(EditorEvent::TitleChanged);
22104                    }
22105
22106                    if self.project.is_some() {
22107                        let buffer_id = buffer.read(cx).remote_id();
22108                        self.register_buffer(buffer_id, cx);
22109                        self.update_lsp_data(Some(buffer_id), window, cx);
22110                        self.refresh_inlay_hints(
22111                            InlayHintRefreshReason::BufferEdited(buffer_id),
22112                            cx,
22113                        );
22114                    }
22115                }
22116
22117                cx.emit(EditorEvent::BufferEdited);
22118                cx.emit(SearchEvent::MatchesInvalidated);
22119
22120                let Some(project) = &self.project else { return };
22121                let (telemetry, is_via_ssh) = {
22122                    let project = project.read(cx);
22123                    let telemetry = project.client().telemetry().clone();
22124                    let is_via_ssh = project.is_via_remote_server();
22125                    (telemetry, is_via_ssh)
22126                };
22127                telemetry.log_edit_event("editor", is_via_ssh);
22128            }
22129            multi_buffer::Event::ExcerptsAdded {
22130                buffer,
22131                predecessor,
22132                excerpts,
22133            } => {
22134                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22135                let buffer_id = buffer.read(cx).remote_id();
22136                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22137                    && let Some(project) = &self.project
22138                {
22139                    update_uncommitted_diff_for_buffer(
22140                        cx.entity(),
22141                        project,
22142                        [buffer.clone()],
22143                        self.buffer.clone(),
22144                        cx,
22145                    )
22146                    .detach();
22147                }
22148                self.update_lsp_data(Some(buffer_id), window, cx);
22149                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22150                self.colorize_brackets(false, cx);
22151                cx.emit(EditorEvent::ExcerptsAdded {
22152                    buffer: buffer.clone(),
22153                    predecessor: *predecessor,
22154                    excerpts: excerpts.clone(),
22155                });
22156            }
22157            multi_buffer::Event::ExcerptsRemoved {
22158                ids,
22159                removed_buffer_ids,
22160            } => {
22161                if let Some(inlay_hints) = &mut self.inlay_hints {
22162                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22163                }
22164                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22165                for buffer_id in removed_buffer_ids {
22166                    self.registered_buffers.remove(buffer_id);
22167                }
22168                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22169                cx.emit(EditorEvent::ExcerptsRemoved {
22170                    ids: ids.clone(),
22171                    removed_buffer_ids: removed_buffer_ids.clone(),
22172                });
22173            }
22174            multi_buffer::Event::ExcerptsEdited {
22175                excerpt_ids,
22176                buffer_ids,
22177            } => {
22178                self.display_map.update(cx, |map, cx| {
22179                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22180                });
22181                cx.emit(EditorEvent::ExcerptsEdited {
22182                    ids: excerpt_ids.clone(),
22183                });
22184            }
22185            multi_buffer::Event::ExcerptsExpanded { ids } => {
22186                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22187                self.refresh_document_highlights(cx);
22188                for id in ids {
22189                    self.fetched_tree_sitter_chunks.remove(id);
22190                }
22191                self.colorize_brackets(false, cx);
22192                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22193            }
22194            multi_buffer::Event::Reparsed(buffer_id) => {
22195                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22196                self.refresh_selected_text_highlights(true, window, cx);
22197                self.colorize_brackets(true, cx);
22198                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22199
22200                cx.emit(EditorEvent::Reparsed(*buffer_id));
22201            }
22202            multi_buffer::Event::DiffHunksToggled => {
22203                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22204            }
22205            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22206                if !is_fresh_language {
22207                    self.registered_buffers.remove(&buffer_id);
22208                }
22209                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22210                cx.emit(EditorEvent::Reparsed(*buffer_id));
22211                cx.notify();
22212            }
22213            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22214            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22215            multi_buffer::Event::FileHandleChanged
22216            | multi_buffer::Event::Reloaded
22217            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22218            multi_buffer::Event::DiagnosticsUpdated => {
22219                self.update_diagnostics_state(window, cx);
22220            }
22221            _ => {}
22222        };
22223    }
22224
22225    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22226        if !self.diagnostics_enabled() {
22227            return;
22228        }
22229        self.refresh_active_diagnostics(cx);
22230        self.refresh_inline_diagnostics(true, window, cx);
22231        self.scrollbar_marker_state.dirty = true;
22232        cx.notify();
22233    }
22234
22235    pub fn start_temporary_diff_override(&mut self) {
22236        self.load_diff_task.take();
22237        self.temporary_diff_override = true;
22238    }
22239
22240    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22241        self.temporary_diff_override = false;
22242        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22243        self.buffer.update(cx, |buffer, cx| {
22244            buffer.set_all_diff_hunks_collapsed(cx);
22245        });
22246
22247        if let Some(project) = self.project.clone() {
22248            self.load_diff_task = Some(
22249                update_uncommitted_diff_for_buffer(
22250                    cx.entity(),
22251                    &project,
22252                    self.buffer.read(cx).all_buffers(),
22253                    self.buffer.clone(),
22254                    cx,
22255                )
22256                .shared(),
22257            );
22258        }
22259    }
22260
22261    fn on_display_map_changed(
22262        &mut self,
22263        _: Entity<DisplayMap>,
22264        _: &mut Window,
22265        cx: &mut Context<Self>,
22266    ) {
22267        cx.notify();
22268    }
22269
22270    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22271        if !self.mode.is_full() {
22272            return None;
22273        }
22274
22275        let theme_settings = theme::ThemeSettings::get_global(cx);
22276        let theme = cx.theme();
22277        let accent_colors = theme.accents().clone();
22278
22279        let accent_overrides = theme_settings
22280            .theme_overrides
22281            .get(theme.name.as_ref())
22282            .map(|theme_style| &theme_style.accents)
22283            .into_iter()
22284            .flatten()
22285            .chain(
22286                theme_settings
22287                    .experimental_theme_overrides
22288                    .as_ref()
22289                    .map(|overrides| &overrides.accents)
22290                    .into_iter()
22291                    .flatten(),
22292            )
22293            .flat_map(|accent| accent.0.clone())
22294            .collect();
22295
22296        Some(AccentData {
22297            colors: accent_colors,
22298            overrides: accent_overrides,
22299        })
22300    }
22301
22302    fn fetch_applicable_language_settings(
22303        &self,
22304        cx: &App,
22305    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22306        if !self.mode.is_full() {
22307            return HashMap::default();
22308        }
22309
22310        self.buffer().read(cx).all_buffers().into_iter().fold(
22311            HashMap::default(),
22312            |mut acc, buffer| {
22313                let buffer = buffer.read(cx);
22314                let language = buffer.language().map(|language| language.name());
22315                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22316                    let file = buffer.file();
22317                    v.insert(language_settings(language, file, cx).into_owned());
22318                }
22319                acc
22320            },
22321        )
22322    }
22323
22324    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22325        let new_language_settings = self.fetch_applicable_language_settings(cx);
22326        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22327        self.applicable_language_settings = new_language_settings;
22328
22329        let new_accents = self.fetch_accent_data(cx);
22330        let accents_changed = new_accents != self.accent_data;
22331        self.accent_data = new_accents;
22332
22333        if self.diagnostics_enabled() {
22334            let new_severity = EditorSettings::get_global(cx)
22335                .diagnostics_max_severity
22336                .unwrap_or(DiagnosticSeverity::Hint);
22337            self.set_max_diagnostics_severity(new_severity, cx);
22338        }
22339        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22340        self.update_edit_prediction_settings(cx);
22341        self.refresh_edit_prediction(true, false, window, cx);
22342        self.refresh_inline_values(cx);
22343        self.refresh_inlay_hints(
22344            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22345                self.selections.newest_anchor().head(),
22346                &self.buffer.read(cx).snapshot(cx),
22347                cx,
22348            )),
22349            cx,
22350        );
22351
22352        let old_cursor_shape = self.cursor_shape;
22353        let old_show_breadcrumbs = self.show_breadcrumbs;
22354
22355        {
22356            let editor_settings = EditorSettings::get_global(cx);
22357            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22358            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22359            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22360            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22361        }
22362
22363        if old_cursor_shape != self.cursor_shape {
22364            cx.emit(EditorEvent::CursorShapeChanged);
22365        }
22366
22367        if old_show_breadcrumbs != self.show_breadcrumbs {
22368            cx.emit(EditorEvent::BreadcrumbsChanged);
22369        }
22370
22371        let project_settings = ProjectSettings::get_global(cx);
22372        self.buffer_serialization = self
22373            .should_serialize_buffer()
22374            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22375
22376        if self.mode.is_full() {
22377            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22378            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22379            if self.show_inline_diagnostics != show_inline_diagnostics {
22380                self.show_inline_diagnostics = show_inline_diagnostics;
22381                self.refresh_inline_diagnostics(false, window, cx);
22382            }
22383
22384            if self.git_blame_inline_enabled != inline_blame_enabled {
22385                self.toggle_git_blame_inline_internal(false, window, cx);
22386            }
22387
22388            let minimap_settings = EditorSettings::get_global(cx).minimap;
22389            if self.minimap_visibility != MinimapVisibility::Disabled {
22390                if self.minimap_visibility.settings_visibility()
22391                    != minimap_settings.minimap_enabled()
22392                {
22393                    self.set_minimap_visibility(
22394                        MinimapVisibility::for_mode(self.mode(), cx),
22395                        window,
22396                        cx,
22397                    );
22398                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22399                    minimap_entity.update(cx, |minimap_editor, cx| {
22400                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22401                    })
22402                }
22403            }
22404
22405            if language_settings_changed || accents_changed {
22406                self.colorize_brackets(true, cx);
22407            }
22408
22409            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22410                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22411            }) {
22412                if !inlay_splice.is_empty() {
22413                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22414                }
22415                self.refresh_colors_for_visible_range(None, window, cx);
22416            }
22417        }
22418
22419        cx.notify();
22420    }
22421
22422    pub fn set_searchable(&mut self, searchable: bool) {
22423        self.searchable = searchable;
22424    }
22425
22426    pub fn searchable(&self) -> bool {
22427        self.searchable
22428    }
22429
22430    pub fn open_excerpts_in_split(
22431        &mut self,
22432        _: &OpenExcerptsSplit,
22433        window: &mut Window,
22434        cx: &mut Context<Self>,
22435    ) {
22436        self.open_excerpts_common(None, true, window, cx)
22437    }
22438
22439    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22440        self.open_excerpts_common(None, false, window, cx)
22441    }
22442
22443    fn open_excerpts_common(
22444        &mut self,
22445        jump_data: Option<JumpData>,
22446        split: bool,
22447        window: &mut Window,
22448        cx: &mut Context<Self>,
22449    ) {
22450        let Some(workspace) = self.workspace() else {
22451            cx.propagate();
22452            return;
22453        };
22454
22455        if self.buffer.read(cx).is_singleton() {
22456            cx.propagate();
22457            return;
22458        }
22459
22460        let mut new_selections_by_buffer = HashMap::default();
22461        match &jump_data {
22462            Some(JumpData::MultiBufferPoint {
22463                excerpt_id,
22464                position,
22465                anchor,
22466                line_offset_from_top,
22467            }) => {
22468                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22469                if let Some(buffer) = multi_buffer_snapshot
22470                    .buffer_id_for_excerpt(*excerpt_id)
22471                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22472                {
22473                    let buffer_snapshot = buffer.read(cx).snapshot();
22474                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22475                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22476                    } else {
22477                        buffer_snapshot.clip_point(*position, Bias::Left)
22478                    };
22479                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22480                    new_selections_by_buffer.insert(
22481                        buffer,
22482                        (
22483                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22484                            Some(*line_offset_from_top),
22485                        ),
22486                    );
22487                }
22488            }
22489            Some(JumpData::MultiBufferRow {
22490                row,
22491                line_offset_from_top,
22492            }) => {
22493                let point = MultiBufferPoint::new(row.0, 0);
22494                if let Some((buffer, buffer_point, _)) =
22495                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22496                {
22497                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22498                    new_selections_by_buffer
22499                        .entry(buffer)
22500                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22501                        .0
22502                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22503                }
22504            }
22505            None => {
22506                let selections = self
22507                    .selections
22508                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22509                let multi_buffer = self.buffer.read(cx);
22510                for selection in selections {
22511                    for (snapshot, range, _, anchor) in multi_buffer
22512                        .snapshot(cx)
22513                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22514                    {
22515                        if let Some(anchor) = anchor {
22516                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22517                            else {
22518                                continue;
22519                            };
22520                            let offset = text::ToOffset::to_offset(
22521                                &anchor.text_anchor,
22522                                &buffer_handle.read(cx).snapshot(),
22523                            );
22524                            let range = BufferOffset(offset)..BufferOffset(offset);
22525                            new_selections_by_buffer
22526                                .entry(buffer_handle)
22527                                .or_insert((Vec::new(), None))
22528                                .0
22529                                .push(range)
22530                        } else {
22531                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22532                            else {
22533                                continue;
22534                            };
22535                            new_selections_by_buffer
22536                                .entry(buffer_handle)
22537                                .or_insert((Vec::new(), None))
22538                                .0
22539                                .push(range)
22540                        }
22541                    }
22542                }
22543            }
22544        }
22545
22546        new_selections_by_buffer
22547            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
22548
22549        if new_selections_by_buffer.is_empty() {
22550            return;
22551        }
22552
22553        // We defer the pane interaction because we ourselves are a workspace item
22554        // and activating a new item causes the pane to call a method on us reentrantly,
22555        // which panics if we're on the stack.
22556        window.defer(cx, move |window, cx| {
22557            workspace.update(cx, |workspace, cx| {
22558                let pane = if split {
22559                    workspace.adjacent_pane(window, cx)
22560                } else {
22561                    workspace.active_pane().clone()
22562                };
22563
22564                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22565                    let buffer_read = buffer.read(cx);
22566                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22567                        (true, project::File::from_dyn(Some(file)).is_some())
22568                    } else {
22569                        (false, false)
22570                    };
22571
22572                    // If project file is none workspace.open_project_item will fail to open the excerpt
22573                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22574                    // so we check if there's a tab match in that case first
22575                    let editor = (!has_file || !is_project_file)
22576                        .then(|| {
22577                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22578                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22579                            // Instead, we try to activate the existing editor in the pane first.
22580                            let (editor, pane_item_index, pane_item_id) =
22581                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22582                                    let editor = item.downcast::<Editor>()?;
22583                                    let singleton_buffer =
22584                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22585                                    if singleton_buffer == buffer {
22586                                        Some((editor, i, item.item_id()))
22587                                    } else {
22588                                        None
22589                                    }
22590                                })?;
22591                            pane.update(cx, |pane, cx| {
22592                                pane.activate_item(pane_item_index, true, true, window, cx);
22593                                if !PreviewTabsSettings::get_global(cx)
22594                                    .enable_preview_from_multibuffer
22595                                {
22596                                    pane.unpreview_item_if_preview(pane_item_id);
22597                                }
22598                            });
22599                            Some(editor)
22600                        })
22601                        .flatten()
22602                        .unwrap_or_else(|| {
22603                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22604                                .enable_keep_preview_on_code_navigation;
22605                            let allow_new_preview =
22606                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22607                            workspace.open_project_item::<Self>(
22608                                pane.clone(),
22609                                buffer,
22610                                true,
22611                                true,
22612                                keep_old_preview,
22613                                allow_new_preview,
22614                                window,
22615                                cx,
22616                            )
22617                        });
22618
22619                    editor.update(cx, |editor, cx| {
22620                        if has_file && !is_project_file {
22621                            editor.set_read_only(true);
22622                        }
22623                        let autoscroll = match scroll_offset {
22624                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22625                            None => Autoscroll::newest(),
22626                        };
22627                        let nav_history = editor.nav_history.take();
22628                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22629                        let Some((&excerpt_id, _, buffer_snapshot)) =
22630                            multibuffer_snapshot.as_singleton()
22631                        else {
22632                            return;
22633                        };
22634                        editor.change_selections(
22635                            SelectionEffects::scroll(autoscroll),
22636                            window,
22637                            cx,
22638                            |s| {
22639                                s.select_ranges(ranges.into_iter().map(|range| {
22640                                    let range = buffer_snapshot.anchor_before(range.start)
22641                                        ..buffer_snapshot.anchor_after(range.end);
22642                                    multibuffer_snapshot
22643                                        .anchor_range_in_excerpt(excerpt_id, range)
22644                                        .unwrap()
22645                                }));
22646                            },
22647                        );
22648                        editor.nav_history = nav_history;
22649                    });
22650                }
22651            })
22652        });
22653    }
22654
22655    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22656        let snapshot = self.buffer.read(cx).read(cx);
22657        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22658        Some(
22659            ranges
22660                .iter()
22661                .map(move |range| {
22662                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22663                })
22664                .collect(),
22665        )
22666    }
22667
22668    fn selection_replacement_ranges(
22669        &self,
22670        range: Range<MultiBufferOffsetUtf16>,
22671        cx: &mut App,
22672    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22673        let selections = self
22674            .selections
22675            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22676        let newest_selection = selections
22677            .iter()
22678            .max_by_key(|selection| selection.id)
22679            .unwrap();
22680        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22681        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22682        let snapshot = self.buffer.read(cx).read(cx);
22683        selections
22684            .into_iter()
22685            .map(|mut selection| {
22686                selection.start.0.0 =
22687                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22688                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22689                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22690                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22691            })
22692            .collect()
22693    }
22694
22695    fn report_editor_event(
22696        &self,
22697        reported_event: ReportEditorEvent,
22698        file_extension: Option<String>,
22699        cx: &App,
22700    ) {
22701        if cfg!(any(test, feature = "test-support")) {
22702            return;
22703        }
22704
22705        let Some(project) = &self.project else { return };
22706
22707        // If None, we are in a file without an extension
22708        let file = self
22709            .buffer
22710            .read(cx)
22711            .as_singleton()
22712            .and_then(|b| b.read(cx).file());
22713        let file_extension = file_extension.or(file
22714            .as_ref()
22715            .and_then(|file| Path::new(file.file_name(cx)).extension())
22716            .and_then(|e| e.to_str())
22717            .map(|a| a.to_string()));
22718
22719        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22720            .map(|vim_mode| vim_mode.0)
22721            .unwrap_or(false);
22722
22723        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22724        let copilot_enabled = edit_predictions_provider
22725            == language::language_settings::EditPredictionProvider::Copilot;
22726        let copilot_enabled_for_language = self
22727            .buffer
22728            .read(cx)
22729            .language_settings(cx)
22730            .show_edit_predictions;
22731
22732        let project = project.read(cx);
22733        let event_type = reported_event.event_type();
22734
22735        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22736            telemetry::event!(
22737                event_type,
22738                type = if auto_saved {"autosave"} else {"manual"},
22739                file_extension,
22740                vim_mode,
22741                copilot_enabled,
22742                copilot_enabled_for_language,
22743                edit_predictions_provider,
22744                is_via_ssh = project.is_via_remote_server(),
22745            );
22746        } else {
22747            telemetry::event!(
22748                event_type,
22749                file_extension,
22750                vim_mode,
22751                copilot_enabled,
22752                copilot_enabled_for_language,
22753                edit_predictions_provider,
22754                is_via_ssh = project.is_via_remote_server(),
22755            );
22756        };
22757    }
22758
22759    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22760    /// with each line being an array of {text, highlight} objects.
22761    fn copy_highlight_json(
22762        &mut self,
22763        _: &CopyHighlightJson,
22764        window: &mut Window,
22765        cx: &mut Context<Self>,
22766    ) {
22767        #[derive(Serialize)]
22768        struct Chunk<'a> {
22769            text: String,
22770            highlight: Option<&'a str>,
22771        }
22772
22773        let snapshot = self.buffer.read(cx).snapshot(cx);
22774        let range = self
22775            .selected_text_range(false, window, cx)
22776            .and_then(|selection| {
22777                if selection.range.is_empty() {
22778                    None
22779                } else {
22780                    Some(
22781                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22782                            selection.range.start,
22783                        )))
22784                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22785                                selection.range.end,
22786                            ))),
22787                    )
22788                }
22789            })
22790            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22791
22792        let chunks = snapshot.chunks(range, true);
22793        let mut lines = Vec::new();
22794        let mut line: VecDeque<Chunk> = VecDeque::new();
22795
22796        let Some(style) = self.style.as_ref() else {
22797            return;
22798        };
22799
22800        for chunk in chunks {
22801            let highlight = chunk
22802                .syntax_highlight_id
22803                .and_then(|id| id.name(&style.syntax));
22804            let mut chunk_lines = chunk.text.split('\n').peekable();
22805            while let Some(text) = chunk_lines.next() {
22806                let mut merged_with_last_token = false;
22807                if let Some(last_token) = line.back_mut()
22808                    && last_token.highlight == highlight
22809                {
22810                    last_token.text.push_str(text);
22811                    merged_with_last_token = true;
22812                }
22813
22814                if !merged_with_last_token {
22815                    line.push_back(Chunk {
22816                        text: text.into(),
22817                        highlight,
22818                    });
22819                }
22820
22821                if chunk_lines.peek().is_some() {
22822                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22823                        line.pop_front();
22824                    }
22825                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22826                        line.pop_back();
22827                    }
22828
22829                    lines.push(mem::take(&mut line));
22830                }
22831            }
22832        }
22833
22834        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22835            return;
22836        };
22837        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22838    }
22839
22840    pub fn open_context_menu(
22841        &mut self,
22842        _: &OpenContextMenu,
22843        window: &mut Window,
22844        cx: &mut Context<Self>,
22845    ) {
22846        self.request_autoscroll(Autoscroll::newest(), cx);
22847        let position = self
22848            .selections
22849            .newest_display(&self.display_snapshot(cx))
22850            .start;
22851        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22852    }
22853
22854    pub fn replay_insert_event(
22855        &mut self,
22856        text: &str,
22857        relative_utf16_range: Option<Range<isize>>,
22858        window: &mut Window,
22859        cx: &mut Context<Self>,
22860    ) {
22861        if !self.input_enabled {
22862            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22863            return;
22864        }
22865        if let Some(relative_utf16_range) = relative_utf16_range {
22866            let selections = self
22867                .selections
22868                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22869            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22870                let new_ranges = selections.into_iter().map(|range| {
22871                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22872                        range
22873                            .head()
22874                            .0
22875                            .0
22876                            .saturating_add_signed(relative_utf16_range.start),
22877                    ));
22878                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22879                        range
22880                            .head()
22881                            .0
22882                            .0
22883                            .saturating_add_signed(relative_utf16_range.end),
22884                    ));
22885                    start..end
22886                });
22887                s.select_ranges(new_ranges);
22888            });
22889        }
22890
22891        self.handle_input(text, window, cx);
22892    }
22893
22894    pub fn is_focused(&self, window: &Window) -> bool {
22895        self.focus_handle.is_focused(window)
22896    }
22897
22898    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22899        cx.emit(EditorEvent::Focused);
22900
22901        if let Some(descendant) = self
22902            .last_focused_descendant
22903            .take()
22904            .and_then(|descendant| descendant.upgrade())
22905        {
22906            window.focus(&descendant, cx);
22907        } else {
22908            if let Some(blame) = self.blame.as_ref() {
22909                blame.update(cx, GitBlame::focus)
22910            }
22911
22912            self.blink_manager.update(cx, BlinkManager::enable);
22913            self.show_cursor_names(window, cx);
22914            self.buffer.update(cx, |buffer, cx| {
22915                buffer.finalize_last_transaction(cx);
22916                if self.leader_id.is_none() {
22917                    buffer.set_active_selections(
22918                        &self.selections.disjoint_anchors_arc(),
22919                        self.selections.line_mode(),
22920                        self.cursor_shape,
22921                        cx,
22922                    );
22923                }
22924            });
22925
22926            if let Some(position_map) = self.last_position_map.clone() {
22927                EditorElement::mouse_moved(
22928                    self,
22929                    &MouseMoveEvent {
22930                        position: window.mouse_position(),
22931                        pressed_button: None,
22932                        modifiers: window.modifiers(),
22933                    },
22934                    &position_map,
22935                    window,
22936                    cx,
22937                );
22938            }
22939        }
22940    }
22941
22942    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22943        cx.emit(EditorEvent::FocusedIn)
22944    }
22945
22946    fn handle_focus_out(
22947        &mut self,
22948        event: FocusOutEvent,
22949        _window: &mut Window,
22950        cx: &mut Context<Self>,
22951    ) {
22952        if event.blurred != self.focus_handle {
22953            self.last_focused_descendant = Some(event.blurred);
22954        }
22955        self.selection_drag_state = SelectionDragState::None;
22956        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22957    }
22958
22959    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22960        self.blink_manager.update(cx, BlinkManager::disable);
22961        self.buffer
22962            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22963
22964        if let Some(blame) = self.blame.as_ref() {
22965            blame.update(cx, GitBlame::blur)
22966        }
22967        if !self.hover_state.focused(window, cx) {
22968            hide_hover(self, cx);
22969        }
22970        if !self
22971            .context_menu
22972            .borrow()
22973            .as_ref()
22974            .is_some_and(|context_menu| context_menu.focused(window, cx))
22975        {
22976            self.hide_context_menu(window, cx);
22977        }
22978        self.take_active_edit_prediction(cx);
22979        cx.emit(EditorEvent::Blurred);
22980        cx.notify();
22981    }
22982
22983    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22984        let mut pending: String = window
22985            .pending_input_keystrokes()
22986            .into_iter()
22987            .flatten()
22988            .filter_map(|keystroke| keystroke.key_char.clone())
22989            .collect();
22990
22991        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22992            pending = "".to_string();
22993        }
22994
22995        let existing_pending = self
22996            .text_highlights::<PendingInput>(cx)
22997            .map(|(_, ranges)| ranges.to_vec());
22998        if existing_pending.is_none() && pending.is_empty() {
22999            return;
23000        }
23001        let transaction =
23002            self.transact(window, cx, |this, window, cx| {
23003                let selections = this
23004                    .selections
23005                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
23006                let edits = selections
23007                    .iter()
23008                    .map(|selection| (selection.end..selection.end, pending.clone()));
23009                this.edit(edits, cx);
23010                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23011                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
23012                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
23013                    }));
23014                });
23015                if let Some(existing_ranges) = existing_pending {
23016                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
23017                    this.edit(edits, cx);
23018                }
23019            });
23020
23021        let snapshot = self.snapshot(window, cx);
23022        let ranges = self
23023            .selections
23024            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
23025            .into_iter()
23026            .map(|selection| {
23027                snapshot.buffer_snapshot().anchor_after(selection.end)
23028                    ..snapshot
23029                        .buffer_snapshot()
23030                        .anchor_before(selection.end + pending.len())
23031            })
23032            .collect();
23033
23034        if pending.is_empty() {
23035            self.clear_highlights::<PendingInput>(cx);
23036        } else {
23037            self.highlight_text::<PendingInput>(
23038                ranges,
23039                HighlightStyle {
23040                    underline: Some(UnderlineStyle {
23041                        thickness: px(1.),
23042                        color: None,
23043                        wavy: false,
23044                    }),
23045                    ..Default::default()
23046                },
23047                cx,
23048            );
23049        }
23050
23051        self.ime_transaction = self.ime_transaction.or(transaction);
23052        if let Some(transaction) = self.ime_transaction {
23053            self.buffer.update(cx, |buffer, cx| {
23054                buffer.group_until_transaction(transaction, cx);
23055            });
23056        }
23057
23058        if self.text_highlights::<PendingInput>(cx).is_none() {
23059            self.ime_transaction.take();
23060        }
23061    }
23062
23063    pub fn register_action_renderer(
23064        &mut self,
23065        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23066    ) -> Subscription {
23067        let id = self.next_editor_action_id.post_inc();
23068        self.editor_actions
23069            .borrow_mut()
23070            .insert(id, Box::new(listener));
23071
23072        let editor_actions = self.editor_actions.clone();
23073        Subscription::new(move || {
23074            editor_actions.borrow_mut().remove(&id);
23075        })
23076    }
23077
23078    pub fn register_action<A: Action>(
23079        &mut self,
23080        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23081    ) -> Subscription {
23082        let id = self.next_editor_action_id.post_inc();
23083        let listener = Arc::new(listener);
23084        self.editor_actions.borrow_mut().insert(
23085            id,
23086            Box::new(move |_, window, _| {
23087                let listener = listener.clone();
23088                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23089                    let action = action.downcast_ref().unwrap();
23090                    if phase == DispatchPhase::Bubble {
23091                        listener(action, window, cx)
23092                    }
23093                })
23094            }),
23095        );
23096
23097        let editor_actions = self.editor_actions.clone();
23098        Subscription::new(move || {
23099            editor_actions.borrow_mut().remove(&id);
23100        })
23101    }
23102
23103    pub fn file_header_size(&self) -> u32 {
23104        FILE_HEADER_HEIGHT
23105    }
23106
23107    pub fn restore(
23108        &mut self,
23109        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23110        window: &mut Window,
23111        cx: &mut Context<Self>,
23112    ) {
23113        self.buffer().update(cx, |multi_buffer, cx| {
23114            for (buffer_id, changes) in revert_changes {
23115                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23116                    buffer.update(cx, |buffer, cx| {
23117                        buffer.edit(
23118                            changes
23119                                .into_iter()
23120                                .map(|(range, text)| (range, text.to_string())),
23121                            None,
23122                            cx,
23123                        );
23124                    });
23125                }
23126            }
23127        });
23128        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23129            selections.refresh()
23130        });
23131    }
23132
23133    pub fn to_pixel_point(
23134        &mut self,
23135        source: multi_buffer::Anchor,
23136        editor_snapshot: &EditorSnapshot,
23137        window: &mut Window,
23138        cx: &App,
23139    ) -> Option<gpui::Point<Pixels>> {
23140        let source_point = source.to_display_point(editor_snapshot);
23141        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23142    }
23143
23144    pub fn display_to_pixel_point(
23145        &mut self,
23146        source: DisplayPoint,
23147        editor_snapshot: &EditorSnapshot,
23148        window: &mut Window,
23149        cx: &App,
23150    ) -> Option<gpui::Point<Pixels>> {
23151        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23152        let text_layout_details = self.text_layout_details(window);
23153        let scroll_top = text_layout_details
23154            .scroll_anchor
23155            .scroll_position(editor_snapshot)
23156            .y;
23157
23158        if source.row().as_f64() < scroll_top.floor() {
23159            return None;
23160        }
23161        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23162        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23163        Some(gpui::Point::new(source_x, source_y))
23164    }
23165
23166    pub fn has_visible_completions_menu(&self) -> bool {
23167        !self.edit_prediction_preview_is_active()
23168            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23169                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23170            })
23171    }
23172
23173    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23174        if self.mode.is_minimap() {
23175            return;
23176        }
23177        self.addons
23178            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23179    }
23180
23181    pub fn unregister_addon<T: Addon>(&mut self) {
23182        self.addons.remove(&std::any::TypeId::of::<T>());
23183    }
23184
23185    pub fn addon<T: Addon>(&self) -> Option<&T> {
23186        let type_id = std::any::TypeId::of::<T>();
23187        self.addons
23188            .get(&type_id)
23189            .and_then(|item| item.to_any().downcast_ref::<T>())
23190    }
23191
23192    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23193        let type_id = std::any::TypeId::of::<T>();
23194        self.addons
23195            .get_mut(&type_id)
23196            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23197    }
23198
23199    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23200        let text_layout_details = self.text_layout_details(window);
23201        let style = &text_layout_details.editor_style;
23202        let font_id = window.text_system().resolve_font(&style.text.font());
23203        let font_size = style.text.font_size.to_pixels(window.rem_size());
23204        let line_height = style.text.line_height_in_pixels(window.rem_size());
23205        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23206        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23207
23208        CharacterDimensions {
23209            em_width,
23210            em_advance,
23211            line_height,
23212        }
23213    }
23214
23215    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23216        self.load_diff_task.clone()
23217    }
23218
23219    fn read_metadata_from_db(
23220        &mut self,
23221        item_id: u64,
23222        workspace_id: WorkspaceId,
23223        window: &mut Window,
23224        cx: &mut Context<Editor>,
23225    ) {
23226        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23227            && !self.mode.is_minimap()
23228            && WorkspaceSettings::get(None, cx).restore_on_startup
23229                != RestoreOnStartupBehavior::EmptyTab
23230        {
23231            let buffer_snapshot = OnceCell::new();
23232
23233            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23234                && !folds.is_empty()
23235            {
23236                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23237                let snapshot_len = snapshot.len().0;
23238
23239                // Helper: search for fingerprint in buffer, return offset if found
23240                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
23241                    // Ensure we start at a character boundary (defensive)
23242                    let search_start = snapshot
23243                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
23244                        .0;
23245                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
23246
23247                    let mut byte_offset = search_start;
23248                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
23249                        if byte_offset > search_end {
23250                            break;
23251                        }
23252                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
23253                            return Some(byte_offset);
23254                        }
23255                        byte_offset += ch.len_utf8();
23256                    }
23257                    None
23258                };
23259
23260                // Track search position to handle duplicate fingerprints correctly.
23261                // Folds are stored in document order, so we advance after each match.
23262                let mut search_start = 0usize;
23263
23264                let valid_folds: Vec<_> = folds
23265                    .into_iter()
23266                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
23267                        // Skip folds without fingerprints (old data before migration)
23268                        let sfp = start_fp?;
23269                        let efp = end_fp?;
23270                        let efp_len = efp.len();
23271
23272                        // Fast path: check if fingerprints match at stored offsets
23273                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
23274                        let start_matches = stored_start < snapshot_len
23275                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
23276                        let efp_check_pos = stored_end.saturating_sub(efp_len);
23277                        let end_matches = efp_check_pos >= stored_start
23278                            && stored_end <= snapshot_len
23279                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
23280
23281                        let (new_start, new_end) = if start_matches && end_matches {
23282                            // Offsets unchanged, use stored values
23283                            (stored_start, stored_end)
23284                        } else if sfp == efp {
23285                            // Short fold: identical fingerprints can only match once per search
23286                            // Use stored fold length to compute new_end
23287                            let new_start = find_fingerprint(&sfp, search_start)?;
23288                            let fold_len = stored_end - stored_start;
23289                            let new_end = new_start + fold_len;
23290                            (new_start, new_end)
23291                        } else {
23292                            // Slow path: search for fingerprints in buffer
23293                            let new_start = find_fingerprint(&sfp, search_start)?;
23294                            // Search for end_fp after start, then add efp_len to get actual fold end
23295                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
23296                            let new_end = efp_pos + efp_len;
23297                            (new_start, new_end)
23298                        };
23299
23300                        // Advance search position for next fold
23301                        search_start = new_end;
23302
23303                        // Validate fold makes sense (end must be after start)
23304                        if new_end <= new_start {
23305                            return None;
23306                        }
23307
23308                        Some(
23309                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
23310                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
23311                        )
23312                    })
23313                    .collect();
23314
23315                if !valid_folds.is_empty() {
23316                    self.fold_ranges(valid_folds, false, window, cx);
23317
23318                    // Migrate folds to current entity_id before workspace cleanup runs.
23319                    // Entity IDs change between sessions, but workspace cleanup deletes
23320                    // old editor rows (cascading to folds) based on current entity IDs.
23321                    let new_editor_id = cx.entity().entity_id().as_u64() as ItemId;
23322                    if new_editor_id != item_id {
23323                        cx.spawn(async move |_, _| {
23324                            DB.migrate_editor_folds(item_id, new_editor_id, workspace_id)
23325                                .await
23326                                .log_err();
23327                        })
23328                        .detach();
23329                    }
23330                }
23331            }
23332
23333            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23334                && !selections.is_empty()
23335            {
23336                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23337                // skip adding the initial selection to selection history
23338                self.selection_history.mode = SelectionHistoryMode::Skipping;
23339                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23340                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23341                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23342                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23343                    }));
23344                });
23345                self.selection_history.mode = SelectionHistoryMode::Normal;
23346            };
23347        }
23348
23349        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23350    }
23351
23352    fn update_lsp_data(
23353        &mut self,
23354        for_buffer: Option<BufferId>,
23355        window: &mut Window,
23356        cx: &mut Context<'_, Self>,
23357    ) {
23358        self.pull_diagnostics(for_buffer, window, cx);
23359        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23360    }
23361
23362    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23363        if self.ignore_lsp_data() {
23364            return;
23365        }
23366        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23367            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23368        }
23369    }
23370
23371    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23372        if self.ignore_lsp_data() {
23373            return;
23374        }
23375
23376        if !self.registered_buffers.contains_key(&buffer_id)
23377            && let Some(project) = self.project.as_ref()
23378        {
23379            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23380                project.update(cx, |project, cx| {
23381                    self.registered_buffers.insert(
23382                        buffer_id,
23383                        project.register_buffer_with_language_servers(&buffer, cx),
23384                    );
23385                });
23386            } else {
23387                self.registered_buffers.remove(&buffer_id);
23388            }
23389        }
23390    }
23391
23392    fn ignore_lsp_data(&self) -> bool {
23393        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23394        // skip any LSP updates for it.
23395        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23396    }
23397
23398    fn create_style(&self, cx: &App) -> EditorStyle {
23399        let settings = ThemeSettings::get_global(cx);
23400
23401        let mut text_style = match self.mode {
23402            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23403                color: cx.theme().colors().editor_foreground,
23404                font_family: settings.ui_font.family.clone(),
23405                font_features: settings.ui_font.features.clone(),
23406                font_fallbacks: settings.ui_font.fallbacks.clone(),
23407                font_size: rems(0.875).into(),
23408                font_weight: settings.ui_font.weight,
23409                line_height: relative(settings.buffer_line_height.value()),
23410                ..Default::default()
23411            },
23412            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23413                color: cx.theme().colors().editor_foreground,
23414                font_family: settings.buffer_font.family.clone(),
23415                font_features: settings.buffer_font.features.clone(),
23416                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23417                font_size: settings.buffer_font_size(cx).into(),
23418                font_weight: settings.buffer_font.weight,
23419                line_height: relative(settings.buffer_line_height.value()),
23420                ..Default::default()
23421            },
23422        };
23423        if let Some(text_style_refinement) = &self.text_style_refinement {
23424            text_style.refine(text_style_refinement)
23425        }
23426
23427        let background = match self.mode {
23428            EditorMode::SingleLine => cx.theme().system().transparent,
23429            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23430            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23431            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23432        };
23433
23434        EditorStyle {
23435            background,
23436            border: cx.theme().colors().border,
23437            local_player: cx.theme().players().local(),
23438            text: text_style,
23439            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23440            syntax: cx.theme().syntax().clone(),
23441            status: cx.theme().status().clone(),
23442            inlay_hints_style: make_inlay_hints_style(cx),
23443            edit_prediction_styles: make_suggestion_styles(cx),
23444            unnecessary_code_fade: settings.unnecessary_code_fade,
23445            show_underlines: self.diagnostics_enabled(),
23446        }
23447    }
23448    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
23449        let cursor = self.selections.newest_anchor().head();
23450        let multibuffer = self.buffer().read(cx);
23451        let is_singleton = multibuffer.is_singleton();
23452        let (buffer_id, symbols) = multibuffer
23453            .read(cx)
23454            .symbols_containing(cursor, Some(variant.syntax()))?;
23455        let buffer = multibuffer.buffer(buffer_id)?;
23456
23457        let buffer = buffer.read(cx);
23458        let settings = ThemeSettings::get_global(cx);
23459        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
23460        let mut breadcrumbs = if is_singleton {
23461            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
23462                buffer
23463                    .snapshot()
23464                    .resolve_file_path(
23465                        self.project
23466                            .as_ref()
23467                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
23468                            .unwrap_or_default(),
23469                        cx,
23470                    )
23471                    .unwrap_or_else(|| {
23472                        if multibuffer.is_singleton() {
23473                            multibuffer.title(cx).to_string()
23474                        } else {
23475                            "untitled".to_string()
23476                        }
23477                    })
23478            });
23479            vec![BreadcrumbText {
23480                text,
23481                highlights: None,
23482                font: Some(settings.buffer_font.clone()),
23483            }]
23484        } else {
23485            vec![]
23486        };
23487
23488        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
23489            text: symbol.text,
23490            highlights: Some(symbol.highlight_ranges),
23491            font: Some(settings.buffer_font.clone()),
23492        }));
23493        Some(breadcrumbs)
23494    }
23495}
23496
23497fn edit_for_markdown_paste<'a>(
23498    buffer: &MultiBufferSnapshot,
23499    range: Range<MultiBufferOffset>,
23500    to_insert: &'a str,
23501    url: Option<url::Url>,
23502) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23503    if url.is_none() {
23504        return (range, Cow::Borrowed(to_insert));
23505    };
23506
23507    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23508
23509    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23510        Cow::Borrowed(to_insert)
23511    } else {
23512        Cow::Owned(format!("[{old_text}]({to_insert})"))
23513    };
23514    (range, new_text)
23515}
23516
23517fn process_completion_for_edit(
23518    completion: &Completion,
23519    intent: CompletionIntent,
23520    buffer: &Entity<Buffer>,
23521    cursor_position: &text::Anchor,
23522    cx: &mut Context<Editor>,
23523) -> CompletionEdit {
23524    let buffer = buffer.read(cx);
23525    let buffer_snapshot = buffer.snapshot();
23526    let (snippet, new_text) = if completion.is_snippet() {
23527        let mut snippet_source = completion.new_text.clone();
23528        // Workaround for typescript language server issues so that methods don't expand within
23529        // strings and functions with type expressions. The previous point is used because the query
23530        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23531        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23532        let previous_point = if previous_point.column > 0 {
23533            cursor_position.to_previous_offset(&buffer_snapshot)
23534        } else {
23535            cursor_position.to_offset(&buffer_snapshot)
23536        };
23537        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23538            && scope.prefers_label_for_snippet_in_completion()
23539            && let Some(label) = completion.label()
23540            && matches!(
23541                completion.kind(),
23542                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23543            )
23544        {
23545            snippet_source = label;
23546        }
23547        match Snippet::parse(&snippet_source).log_err() {
23548            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23549            None => (None, completion.new_text.clone()),
23550        }
23551    } else {
23552        (None, completion.new_text.clone())
23553    };
23554
23555    let mut range_to_replace = {
23556        let replace_range = &completion.replace_range;
23557        if let CompletionSource::Lsp {
23558            insert_range: Some(insert_range),
23559            ..
23560        } = &completion.source
23561        {
23562            debug_assert_eq!(
23563                insert_range.start, replace_range.start,
23564                "insert_range and replace_range should start at the same position"
23565            );
23566            debug_assert!(
23567                insert_range
23568                    .start
23569                    .cmp(cursor_position, &buffer_snapshot)
23570                    .is_le(),
23571                "insert_range should start before or at cursor position"
23572            );
23573            debug_assert!(
23574                replace_range
23575                    .start
23576                    .cmp(cursor_position, &buffer_snapshot)
23577                    .is_le(),
23578                "replace_range should start before or at cursor position"
23579            );
23580
23581            let should_replace = match intent {
23582                CompletionIntent::CompleteWithInsert => false,
23583                CompletionIntent::CompleteWithReplace => true,
23584                CompletionIntent::Complete | CompletionIntent::Compose => {
23585                    let insert_mode =
23586                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23587                            .completions
23588                            .lsp_insert_mode;
23589                    match insert_mode {
23590                        LspInsertMode::Insert => false,
23591                        LspInsertMode::Replace => true,
23592                        LspInsertMode::ReplaceSubsequence => {
23593                            let mut text_to_replace = buffer.chars_for_range(
23594                                buffer.anchor_before(replace_range.start)
23595                                    ..buffer.anchor_after(replace_range.end),
23596                            );
23597                            let mut current_needle = text_to_replace.next();
23598                            for haystack_ch in completion.label.text.chars() {
23599                                if let Some(needle_ch) = current_needle
23600                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23601                                {
23602                                    current_needle = text_to_replace.next();
23603                                }
23604                            }
23605                            current_needle.is_none()
23606                        }
23607                        LspInsertMode::ReplaceSuffix => {
23608                            if replace_range
23609                                .end
23610                                .cmp(cursor_position, &buffer_snapshot)
23611                                .is_gt()
23612                            {
23613                                let range_after_cursor = *cursor_position..replace_range.end;
23614                                let text_after_cursor = buffer
23615                                    .text_for_range(
23616                                        buffer.anchor_before(range_after_cursor.start)
23617                                            ..buffer.anchor_after(range_after_cursor.end),
23618                                    )
23619                                    .collect::<String>()
23620                                    .to_ascii_lowercase();
23621                                completion
23622                                    .label
23623                                    .text
23624                                    .to_ascii_lowercase()
23625                                    .ends_with(&text_after_cursor)
23626                            } else {
23627                                true
23628                            }
23629                        }
23630                    }
23631                }
23632            };
23633
23634            if should_replace {
23635                replace_range.clone()
23636            } else {
23637                insert_range.clone()
23638            }
23639        } else {
23640            replace_range.clone()
23641        }
23642    };
23643
23644    if range_to_replace
23645        .end
23646        .cmp(cursor_position, &buffer_snapshot)
23647        .is_lt()
23648    {
23649        range_to_replace.end = *cursor_position;
23650    }
23651
23652    let replace_range = range_to_replace.to_offset(buffer);
23653    CompletionEdit {
23654        new_text,
23655        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23656        snippet,
23657    }
23658}
23659
23660struct CompletionEdit {
23661    new_text: String,
23662    replace_range: Range<BufferOffset>,
23663    snippet: Option<Snippet>,
23664}
23665
23666fn comment_delimiter_for_newline(
23667    start_point: &Point,
23668    buffer: &MultiBufferSnapshot,
23669    language: &LanguageScope,
23670) -> Option<Arc<str>> {
23671    let delimiters = language.line_comment_prefixes();
23672    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23673    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23674
23675    let num_of_whitespaces = snapshot
23676        .chars_for_range(range.clone())
23677        .take_while(|c| c.is_whitespace())
23678        .count();
23679    let comment_candidate = snapshot
23680        .chars_for_range(range.clone())
23681        .skip(num_of_whitespaces)
23682        .take(max_len_of_delimiter)
23683        .collect::<String>();
23684    let (delimiter, trimmed_len) = delimiters
23685        .iter()
23686        .filter_map(|delimiter| {
23687            let prefix = delimiter.trim_end();
23688            if comment_candidate.starts_with(prefix) {
23689                Some((delimiter, prefix.len()))
23690            } else {
23691                None
23692            }
23693        })
23694        .max_by_key(|(_, len)| *len)?;
23695
23696    if let Some(BlockCommentConfig {
23697        start: block_start, ..
23698    }) = language.block_comment()
23699    {
23700        let block_start_trimmed = block_start.trim_end();
23701        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23702            let line_content = snapshot
23703                .chars_for_range(range)
23704                .skip(num_of_whitespaces)
23705                .take(block_start_trimmed.len())
23706                .collect::<String>();
23707
23708            if line_content.starts_with(block_start_trimmed) {
23709                return None;
23710            }
23711        }
23712    }
23713
23714    let cursor_is_placed_after_comment_marker =
23715        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23716    if cursor_is_placed_after_comment_marker {
23717        Some(delimiter.clone())
23718    } else {
23719        None
23720    }
23721}
23722
23723fn documentation_delimiter_for_newline(
23724    start_point: &Point,
23725    buffer: &MultiBufferSnapshot,
23726    language: &LanguageScope,
23727    newline_config: &mut NewlineConfig,
23728) -> Option<Arc<str>> {
23729    let BlockCommentConfig {
23730        start: start_tag,
23731        end: end_tag,
23732        prefix: delimiter,
23733        tab_size: len,
23734    } = language.documentation_comment()?;
23735    let is_within_block_comment = buffer
23736        .language_scope_at(*start_point)
23737        .is_some_and(|scope| scope.override_name() == Some("comment"));
23738    if !is_within_block_comment {
23739        return None;
23740    }
23741
23742    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23743
23744    let num_of_whitespaces = snapshot
23745        .chars_for_range(range.clone())
23746        .take_while(|c| c.is_whitespace())
23747        .count();
23748
23749    // 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.
23750    let column = start_point.column;
23751    let cursor_is_after_start_tag = {
23752        let start_tag_len = start_tag.len();
23753        let start_tag_line = snapshot
23754            .chars_for_range(range.clone())
23755            .skip(num_of_whitespaces)
23756            .take(start_tag_len)
23757            .collect::<String>();
23758        if start_tag_line.starts_with(start_tag.as_ref()) {
23759            num_of_whitespaces + start_tag_len <= column as usize
23760        } else {
23761            false
23762        }
23763    };
23764
23765    let cursor_is_after_delimiter = {
23766        let delimiter_trim = delimiter.trim_end();
23767        let delimiter_line = snapshot
23768            .chars_for_range(range.clone())
23769            .skip(num_of_whitespaces)
23770            .take(delimiter_trim.len())
23771            .collect::<String>();
23772        if delimiter_line.starts_with(delimiter_trim) {
23773            num_of_whitespaces + delimiter_trim.len() <= column as usize
23774        } else {
23775            false
23776        }
23777    };
23778
23779    let mut needs_extra_line = false;
23780    let mut extra_line_additional_indent = IndentSize::spaces(0);
23781
23782    let cursor_is_before_end_tag_if_exists = {
23783        let mut char_position = 0u32;
23784        let mut end_tag_offset = None;
23785
23786        'outer: for chunk in snapshot.text_for_range(range) {
23787            if let Some(byte_pos) = chunk.find(&**end_tag) {
23788                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23789                end_tag_offset = Some(char_position + chars_before_match);
23790                break 'outer;
23791            }
23792            char_position += chunk.chars().count() as u32;
23793        }
23794
23795        if let Some(end_tag_offset) = end_tag_offset {
23796            let cursor_is_before_end_tag = column <= end_tag_offset;
23797            if cursor_is_after_start_tag {
23798                if cursor_is_before_end_tag {
23799                    needs_extra_line = true;
23800                }
23801                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23802                if cursor_is_at_start_of_end_tag {
23803                    extra_line_additional_indent.len = *len;
23804                }
23805            }
23806            cursor_is_before_end_tag
23807        } else {
23808            true
23809        }
23810    };
23811
23812    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23813        && cursor_is_before_end_tag_if_exists
23814    {
23815        let additional_indent = if cursor_is_after_start_tag {
23816            IndentSize::spaces(*len)
23817        } else {
23818            IndentSize::spaces(0)
23819        };
23820
23821        *newline_config = NewlineConfig::Newline {
23822            additional_indent,
23823            extra_line_additional_indent: if needs_extra_line {
23824                Some(extra_line_additional_indent)
23825            } else {
23826                None
23827            },
23828            prevent_auto_indent: true,
23829        };
23830        Some(delimiter.clone())
23831    } else {
23832        None
23833    }
23834}
23835
23836const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23837
23838fn list_delimiter_for_newline(
23839    start_point: &Point,
23840    buffer: &MultiBufferSnapshot,
23841    language: &LanguageScope,
23842    newline_config: &mut NewlineConfig,
23843) -> Option<Arc<str>> {
23844    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23845
23846    let num_of_whitespaces = snapshot
23847        .chars_for_range(range.clone())
23848        .take_while(|c| c.is_whitespace())
23849        .count();
23850
23851    let task_list_entries: Vec<_> = language
23852        .task_list()
23853        .into_iter()
23854        .flat_map(|config| {
23855            config
23856                .prefixes
23857                .iter()
23858                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23859        })
23860        .collect();
23861    let unordered_list_entries: Vec<_> = language
23862        .unordered_list()
23863        .iter()
23864        .map(|marker| (marker.as_ref(), marker.as_ref()))
23865        .collect();
23866
23867    let all_entries: Vec<_> = task_list_entries
23868        .into_iter()
23869        .chain(unordered_list_entries)
23870        .collect();
23871
23872    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
23873        let candidate: String = snapshot
23874            .chars_for_range(range.clone())
23875            .skip(num_of_whitespaces)
23876            .take(max_prefix_len)
23877            .collect();
23878
23879        if let Some((prefix, continuation)) = all_entries
23880            .iter()
23881            .filter(|(prefix, _)| candidate.starts_with(*prefix))
23882            .max_by_key(|(prefix, _)| prefix.len())
23883        {
23884            let end_of_prefix = num_of_whitespaces + prefix.len();
23885            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23886            let has_content_after_marker = snapshot
23887                .chars_for_range(range)
23888                .skip(end_of_prefix)
23889                .any(|c| !c.is_whitespace());
23890
23891            if has_content_after_marker && cursor_is_after_prefix {
23892                return Some((*continuation).into());
23893            }
23894
23895            if start_point.column as usize == end_of_prefix {
23896                if num_of_whitespaces == 0 {
23897                    *newline_config = NewlineConfig::ClearCurrentLine;
23898                } else {
23899                    *newline_config = NewlineConfig::UnindentCurrentLine {
23900                        continuation: (*continuation).into(),
23901                    };
23902                }
23903            }
23904
23905            return None;
23906        }
23907    }
23908
23909    let candidate: String = snapshot
23910        .chars_for_range(range.clone())
23911        .skip(num_of_whitespaces)
23912        .take(ORDERED_LIST_MAX_MARKER_LEN)
23913        .collect();
23914
23915    for ordered_config in language.ordered_list() {
23916        let regex = match Regex::new(&ordered_config.pattern) {
23917            Ok(r) => r,
23918            Err(_) => continue,
23919        };
23920
23921        if let Some(captures) = regex.captures(&candidate) {
23922            let full_match = captures.get(0)?;
23923            let marker_len = full_match.len();
23924            let end_of_prefix = num_of_whitespaces + marker_len;
23925            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23926
23927            let has_content_after_marker = snapshot
23928                .chars_for_range(range)
23929                .skip(end_of_prefix)
23930                .any(|c| !c.is_whitespace());
23931
23932            if has_content_after_marker && cursor_is_after_prefix {
23933                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
23934                let continuation = ordered_config
23935                    .format
23936                    .replace("{1}", &(number + 1).to_string());
23937                return Some(continuation.into());
23938            }
23939
23940            if start_point.column as usize == end_of_prefix {
23941                let continuation = ordered_config.format.replace("{1}", "1");
23942                if num_of_whitespaces == 0 {
23943                    *newline_config = NewlineConfig::ClearCurrentLine;
23944                } else {
23945                    *newline_config = NewlineConfig::UnindentCurrentLine {
23946                        continuation: continuation.into(),
23947                    };
23948                }
23949            }
23950
23951            return None;
23952        }
23953    }
23954
23955    None
23956}
23957
23958fn is_list_prefix_row(
23959    row: MultiBufferRow,
23960    buffer: &MultiBufferSnapshot,
23961    language: &LanguageScope,
23962) -> bool {
23963    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
23964        return false;
23965    };
23966
23967    let num_of_whitespaces = snapshot
23968        .chars_for_range(range.clone())
23969        .take_while(|c| c.is_whitespace())
23970        .count();
23971
23972    let task_list_prefixes: Vec<_> = language
23973        .task_list()
23974        .into_iter()
23975        .flat_map(|config| {
23976            config
23977                .prefixes
23978                .iter()
23979                .map(|p| p.as_ref())
23980                .collect::<Vec<_>>()
23981        })
23982        .collect();
23983    let unordered_list_markers: Vec<_> = language
23984        .unordered_list()
23985        .iter()
23986        .map(|marker| marker.as_ref())
23987        .collect();
23988    let all_prefixes: Vec<_> = task_list_prefixes
23989        .into_iter()
23990        .chain(unordered_list_markers)
23991        .collect();
23992    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
23993        let candidate: String = snapshot
23994            .chars_for_range(range.clone())
23995            .skip(num_of_whitespaces)
23996            .take(max_prefix_len)
23997            .collect();
23998        if all_prefixes
23999            .iter()
24000            .any(|prefix| candidate.starts_with(*prefix))
24001        {
24002            return true;
24003        }
24004    }
24005
24006    let ordered_list_candidate: String = snapshot
24007        .chars_for_range(range)
24008        .skip(num_of_whitespaces)
24009        .take(ORDERED_LIST_MAX_MARKER_LEN)
24010        .collect();
24011    for ordered_config in language.ordered_list() {
24012        let regex = match Regex::new(&ordered_config.pattern) {
24013            Ok(r) => r,
24014            Err(_) => continue,
24015        };
24016        if let Some(captures) = regex.captures(&ordered_list_candidate) {
24017            return captures.get(0).is_some();
24018        }
24019    }
24020
24021    false
24022}
24023
24024#[derive(Debug)]
24025enum NewlineConfig {
24026    /// Insert newline with optional additional indent and optional extra blank line
24027    Newline {
24028        additional_indent: IndentSize,
24029        extra_line_additional_indent: Option<IndentSize>,
24030        prevent_auto_indent: bool,
24031    },
24032    /// Clear the current line
24033    ClearCurrentLine,
24034    /// Unindent the current line and add continuation
24035    UnindentCurrentLine { continuation: Arc<str> },
24036}
24037
24038impl NewlineConfig {
24039    fn has_extra_line(&self) -> bool {
24040        matches!(
24041            self,
24042            Self::Newline {
24043                extra_line_additional_indent: Some(_),
24044                ..
24045            }
24046        )
24047    }
24048
24049    fn insert_extra_newline_brackets(
24050        buffer: &MultiBufferSnapshot,
24051        range: Range<MultiBufferOffset>,
24052        language: &language::LanguageScope,
24053    ) -> bool {
24054        let leading_whitespace_len = buffer
24055            .reversed_chars_at(range.start)
24056            .take_while(|c| c.is_whitespace() && *c != '\n')
24057            .map(|c| c.len_utf8())
24058            .sum::<usize>();
24059        let trailing_whitespace_len = buffer
24060            .chars_at(range.end)
24061            .take_while(|c| c.is_whitespace() && *c != '\n')
24062            .map(|c| c.len_utf8())
24063            .sum::<usize>();
24064        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
24065
24066        language.brackets().any(|(pair, enabled)| {
24067            let pair_start = pair.start.trim_end();
24068            let pair_end = pair.end.trim_start();
24069
24070            enabled
24071                && pair.newline
24072                && buffer.contains_str_at(range.end, pair_end)
24073                && buffer.contains_str_at(
24074                    range.start.saturating_sub_usize(pair_start.len()),
24075                    pair_start,
24076                )
24077        })
24078    }
24079
24080    fn insert_extra_newline_tree_sitter(
24081        buffer: &MultiBufferSnapshot,
24082        range: Range<MultiBufferOffset>,
24083    ) -> bool {
24084        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
24085            [(buffer, range, _)] => (*buffer, range.clone()),
24086            _ => return false,
24087        };
24088        let pair = {
24089            let mut result: Option<BracketMatch<usize>> = None;
24090
24091            for pair in buffer
24092                .all_bracket_ranges(range.start.0..range.end.0)
24093                .filter(move |pair| {
24094                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
24095                })
24096            {
24097                let len = pair.close_range.end - pair.open_range.start;
24098
24099                if let Some(existing) = &result {
24100                    let existing_len = existing.close_range.end - existing.open_range.start;
24101                    if len > existing_len {
24102                        continue;
24103                    }
24104                }
24105
24106                result = Some(pair);
24107            }
24108
24109            result
24110        };
24111        let Some(pair) = pair else {
24112            return false;
24113        };
24114        pair.newline_only
24115            && buffer
24116                .chars_for_range(pair.open_range.end..range.start.0)
24117                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
24118                .all(|c| c.is_whitespace() && c != '\n')
24119    }
24120}
24121
24122fn update_uncommitted_diff_for_buffer(
24123    editor: Entity<Editor>,
24124    project: &Entity<Project>,
24125    buffers: impl IntoIterator<Item = Entity<Buffer>>,
24126    buffer: Entity<MultiBuffer>,
24127    cx: &mut App,
24128) -> Task<()> {
24129    let mut tasks = Vec::new();
24130    project.update(cx, |project, cx| {
24131        for buffer in buffers {
24132            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
24133                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
24134            }
24135        }
24136    });
24137    cx.spawn(async move |cx| {
24138        let diffs = future::join_all(tasks).await;
24139        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
24140            return;
24141        }
24142
24143        buffer.update(cx, |buffer, cx| {
24144            for diff in diffs.into_iter().flatten() {
24145                buffer.add_diff(diff, cx);
24146            }
24147        });
24148    })
24149}
24150
24151fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
24152    let tab_size = tab_size.get() as usize;
24153    let mut width = offset;
24154
24155    for ch in text.chars() {
24156        width += if ch == '\t' {
24157            tab_size - (width % tab_size)
24158        } else {
24159            1
24160        };
24161    }
24162
24163    width - offset
24164}
24165
24166#[cfg(test)]
24167mod tests {
24168    use super::*;
24169
24170    #[test]
24171    fn test_string_size_with_expanded_tabs() {
24172        let nz = |val| NonZeroU32::new(val).unwrap();
24173        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
24174        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
24175        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
24176        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
24177        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
24178        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
24179        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
24180        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
24181    }
24182}
24183
24184/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
24185struct WordBreakingTokenizer<'a> {
24186    input: &'a str,
24187}
24188
24189impl<'a> WordBreakingTokenizer<'a> {
24190    fn new(input: &'a str) -> Self {
24191        Self { input }
24192    }
24193}
24194
24195fn is_char_ideographic(ch: char) -> bool {
24196    use unicode_script::Script::*;
24197    use unicode_script::UnicodeScript;
24198    matches!(ch.script(), Han | Tangut | Yi)
24199}
24200
24201fn is_grapheme_ideographic(text: &str) -> bool {
24202    text.chars().any(is_char_ideographic)
24203}
24204
24205fn is_grapheme_whitespace(text: &str) -> bool {
24206    text.chars().any(|x| x.is_whitespace())
24207}
24208
24209fn should_stay_with_preceding_ideograph(text: &str) -> bool {
24210    text.chars()
24211        .next()
24212        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
24213}
24214
24215#[derive(PartialEq, Eq, Debug, Clone, Copy)]
24216enum WordBreakToken<'a> {
24217    Word { token: &'a str, grapheme_len: usize },
24218    InlineWhitespace { token: &'a str, grapheme_len: usize },
24219    Newline,
24220}
24221
24222impl<'a> Iterator for WordBreakingTokenizer<'a> {
24223    /// Yields a span, the count of graphemes in the token, and whether it was
24224    /// whitespace. Note that it also breaks at word boundaries.
24225    type Item = WordBreakToken<'a>;
24226
24227    fn next(&mut self) -> Option<Self::Item> {
24228        use unicode_segmentation::UnicodeSegmentation;
24229        if self.input.is_empty() {
24230            return None;
24231        }
24232
24233        let mut iter = self.input.graphemes(true).peekable();
24234        let mut offset = 0;
24235        let mut grapheme_len = 0;
24236        if let Some(first_grapheme) = iter.next() {
24237            let is_newline = first_grapheme == "\n";
24238            let is_whitespace = is_grapheme_whitespace(first_grapheme);
24239            offset += first_grapheme.len();
24240            grapheme_len += 1;
24241            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
24242                if let Some(grapheme) = iter.peek().copied()
24243                    && should_stay_with_preceding_ideograph(grapheme)
24244                {
24245                    offset += grapheme.len();
24246                    grapheme_len += 1;
24247                }
24248            } else {
24249                let mut words = self.input[offset..].split_word_bound_indices().peekable();
24250                let mut next_word_bound = words.peek().copied();
24251                if next_word_bound.is_some_and(|(i, _)| i == 0) {
24252                    next_word_bound = words.next();
24253                }
24254                while let Some(grapheme) = iter.peek().copied() {
24255                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
24256                        break;
24257                    };
24258                    if is_grapheme_whitespace(grapheme) != is_whitespace
24259                        || (grapheme == "\n") != is_newline
24260                    {
24261                        break;
24262                    };
24263                    offset += grapheme.len();
24264                    grapheme_len += 1;
24265                    iter.next();
24266                }
24267            }
24268            let token = &self.input[..offset];
24269            self.input = &self.input[offset..];
24270            if token == "\n" {
24271                Some(WordBreakToken::Newline)
24272            } else if is_whitespace {
24273                Some(WordBreakToken::InlineWhitespace {
24274                    token,
24275                    grapheme_len,
24276                })
24277            } else {
24278                Some(WordBreakToken::Word {
24279                    token,
24280                    grapheme_len,
24281                })
24282            }
24283        } else {
24284            None
24285        }
24286    }
24287}
24288
24289#[test]
24290fn test_word_breaking_tokenizer() {
24291    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24292        ("", &[]),
24293        ("  ", &[whitespace("  ", 2)]),
24294        ("Ʒ", &[word("Ʒ", 1)]),
24295        ("Ǽ", &[word("Ǽ", 1)]),
24296        ("", &[word("", 1)]),
24297        ("⋑⋑", &[word("⋑⋑", 2)]),
24298        (
24299            "原理,进而",
24300            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24301        ),
24302        (
24303            "hello world",
24304            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24305        ),
24306        (
24307            "hello, world",
24308            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24309        ),
24310        (
24311            "  hello world",
24312            &[
24313                whitespace("  ", 2),
24314                word("hello", 5),
24315                whitespace(" ", 1),
24316                word("world", 5),
24317            ],
24318        ),
24319        (
24320            "这是什么 \n 钢笔",
24321            &[
24322                word("", 1),
24323                word("", 1),
24324                word("", 1),
24325                word("", 1),
24326                whitespace(" ", 1),
24327                newline(),
24328                whitespace(" ", 1),
24329                word("", 1),
24330                word("", 1),
24331            ],
24332        ),
24333        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24334    ];
24335
24336    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24337        WordBreakToken::Word {
24338            token,
24339            grapheme_len,
24340        }
24341    }
24342
24343    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24344        WordBreakToken::InlineWhitespace {
24345            token,
24346            grapheme_len,
24347        }
24348    }
24349
24350    fn newline() -> WordBreakToken<'static> {
24351        WordBreakToken::Newline
24352    }
24353
24354    for (input, result) in tests {
24355        assert_eq!(
24356            WordBreakingTokenizer::new(input)
24357                .collect::<Vec<_>>()
24358                .as_slice(),
24359            *result,
24360        );
24361    }
24362}
24363
24364fn wrap_with_prefix(
24365    first_line_prefix: String,
24366    subsequent_lines_prefix: String,
24367    unwrapped_text: String,
24368    wrap_column: usize,
24369    tab_size: NonZeroU32,
24370    preserve_existing_whitespace: bool,
24371) -> String {
24372    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24373    let subsequent_lines_prefix_len =
24374        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24375    let mut wrapped_text = String::new();
24376    let mut current_line = first_line_prefix;
24377    let mut is_first_line = true;
24378
24379    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24380    let mut current_line_len = first_line_prefix_len;
24381    let mut in_whitespace = false;
24382    for token in tokenizer {
24383        let have_preceding_whitespace = in_whitespace;
24384        match token {
24385            WordBreakToken::Word {
24386                token,
24387                grapheme_len,
24388            } => {
24389                in_whitespace = false;
24390                let current_prefix_len = if is_first_line {
24391                    first_line_prefix_len
24392                } else {
24393                    subsequent_lines_prefix_len
24394                };
24395                if current_line_len + grapheme_len > wrap_column
24396                    && current_line_len != current_prefix_len
24397                {
24398                    wrapped_text.push_str(current_line.trim_end());
24399                    wrapped_text.push('\n');
24400                    is_first_line = false;
24401                    current_line = subsequent_lines_prefix.clone();
24402                    current_line_len = subsequent_lines_prefix_len;
24403                }
24404                current_line.push_str(token);
24405                current_line_len += grapheme_len;
24406            }
24407            WordBreakToken::InlineWhitespace {
24408                mut token,
24409                mut grapheme_len,
24410            } => {
24411                in_whitespace = true;
24412                if have_preceding_whitespace && !preserve_existing_whitespace {
24413                    continue;
24414                }
24415                if !preserve_existing_whitespace {
24416                    // Keep a single whitespace grapheme as-is
24417                    if let Some(first) =
24418                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24419                    {
24420                        token = first;
24421                    } else {
24422                        token = " ";
24423                    }
24424                    grapheme_len = 1;
24425                }
24426                let current_prefix_len = if is_first_line {
24427                    first_line_prefix_len
24428                } else {
24429                    subsequent_lines_prefix_len
24430                };
24431                if current_line_len + grapheme_len > wrap_column {
24432                    wrapped_text.push_str(current_line.trim_end());
24433                    wrapped_text.push('\n');
24434                    is_first_line = false;
24435                    current_line = subsequent_lines_prefix.clone();
24436                    current_line_len = subsequent_lines_prefix_len;
24437                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24438                    current_line.push_str(token);
24439                    current_line_len += grapheme_len;
24440                }
24441            }
24442            WordBreakToken::Newline => {
24443                in_whitespace = true;
24444                let current_prefix_len = if is_first_line {
24445                    first_line_prefix_len
24446                } else {
24447                    subsequent_lines_prefix_len
24448                };
24449                if preserve_existing_whitespace {
24450                    wrapped_text.push_str(current_line.trim_end());
24451                    wrapped_text.push('\n');
24452                    is_first_line = false;
24453                    current_line = subsequent_lines_prefix.clone();
24454                    current_line_len = subsequent_lines_prefix_len;
24455                } else if have_preceding_whitespace {
24456                    continue;
24457                } else if current_line_len + 1 > wrap_column
24458                    && current_line_len != current_prefix_len
24459                {
24460                    wrapped_text.push_str(current_line.trim_end());
24461                    wrapped_text.push('\n');
24462                    is_first_line = false;
24463                    current_line = subsequent_lines_prefix.clone();
24464                    current_line_len = subsequent_lines_prefix_len;
24465                } else if current_line_len != current_prefix_len {
24466                    current_line.push(' ');
24467                    current_line_len += 1;
24468                }
24469            }
24470        }
24471    }
24472
24473    if !current_line.is_empty() {
24474        wrapped_text.push_str(&current_line);
24475    }
24476    wrapped_text
24477}
24478
24479#[test]
24480fn test_wrap_with_prefix() {
24481    assert_eq!(
24482        wrap_with_prefix(
24483            "# ".to_string(),
24484            "# ".to_string(),
24485            "abcdefg".to_string(),
24486            4,
24487            NonZeroU32::new(4).unwrap(),
24488            false,
24489        ),
24490        "# abcdefg"
24491    );
24492    assert_eq!(
24493        wrap_with_prefix(
24494            "".to_string(),
24495            "".to_string(),
24496            "\thello world".to_string(),
24497            8,
24498            NonZeroU32::new(4).unwrap(),
24499            false,
24500        ),
24501        "hello\nworld"
24502    );
24503    assert_eq!(
24504        wrap_with_prefix(
24505            "// ".to_string(),
24506            "// ".to_string(),
24507            "xx \nyy zz aa bb cc".to_string(),
24508            12,
24509            NonZeroU32::new(4).unwrap(),
24510            false,
24511        ),
24512        "// xx yy zz\n// aa bb cc"
24513    );
24514    assert_eq!(
24515        wrap_with_prefix(
24516            String::new(),
24517            String::new(),
24518            "这是什么 \n 钢笔".to_string(),
24519            3,
24520            NonZeroU32::new(4).unwrap(),
24521            false,
24522        ),
24523        "这是什\n么 钢\n"
24524    );
24525    assert_eq!(
24526        wrap_with_prefix(
24527            String::new(),
24528            String::new(),
24529            format!("foo{}bar", '\u{2009}'), // thin space
24530            80,
24531            NonZeroU32::new(4).unwrap(),
24532            false,
24533        ),
24534        format!("foo{}bar", '\u{2009}')
24535    );
24536}
24537
24538pub trait CollaborationHub {
24539    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24540    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24541    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24542}
24543
24544impl CollaborationHub for Entity<Project> {
24545    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24546        self.read(cx).collaborators()
24547    }
24548
24549    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24550        self.read(cx).user_store().read(cx).participant_indices()
24551    }
24552
24553    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24554        let this = self.read(cx);
24555        let user_ids = this.collaborators().values().map(|c| c.user_id);
24556        this.user_store().read(cx).participant_names(user_ids, cx)
24557    }
24558}
24559
24560pub trait SemanticsProvider {
24561    fn hover(
24562        &self,
24563        buffer: &Entity<Buffer>,
24564        position: text::Anchor,
24565        cx: &mut App,
24566    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24567
24568    fn inline_values(
24569        &self,
24570        buffer_handle: Entity<Buffer>,
24571        range: Range<text::Anchor>,
24572        cx: &mut App,
24573    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24574
24575    fn applicable_inlay_chunks(
24576        &self,
24577        buffer: &Entity<Buffer>,
24578        ranges: &[Range<text::Anchor>],
24579        cx: &mut App,
24580    ) -> Vec<Range<BufferRow>>;
24581
24582    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
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
24593    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24594
24595    fn document_highlights(
24596        &self,
24597        buffer: &Entity<Buffer>,
24598        position: text::Anchor,
24599        cx: &mut App,
24600    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24601
24602    fn definitions(
24603        &self,
24604        buffer: &Entity<Buffer>,
24605        position: text::Anchor,
24606        kind: GotoDefinitionKind,
24607        cx: &mut App,
24608    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24609
24610    fn range_for_rename(
24611        &self,
24612        buffer: &Entity<Buffer>,
24613        position: text::Anchor,
24614        cx: &mut App,
24615    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24616
24617    fn perform_rename(
24618        &self,
24619        buffer: &Entity<Buffer>,
24620        position: text::Anchor,
24621        new_name: String,
24622        cx: &mut App,
24623    ) -> Option<Task<Result<ProjectTransaction>>>;
24624}
24625
24626pub trait CompletionProvider {
24627    fn completions(
24628        &self,
24629        excerpt_id: ExcerptId,
24630        buffer: &Entity<Buffer>,
24631        buffer_position: text::Anchor,
24632        trigger: CompletionContext,
24633        window: &mut Window,
24634        cx: &mut Context<Editor>,
24635    ) -> Task<Result<Vec<CompletionResponse>>>;
24636
24637    fn resolve_completions(
24638        &self,
24639        _buffer: Entity<Buffer>,
24640        _completion_indices: Vec<usize>,
24641        _completions: Rc<RefCell<Box<[Completion]>>>,
24642        _cx: &mut Context<Editor>,
24643    ) -> Task<Result<bool>> {
24644        Task::ready(Ok(false))
24645    }
24646
24647    fn apply_additional_edits_for_completion(
24648        &self,
24649        _buffer: Entity<Buffer>,
24650        _completions: Rc<RefCell<Box<[Completion]>>>,
24651        _completion_index: usize,
24652        _push_to_history: bool,
24653        _cx: &mut Context<Editor>,
24654    ) -> Task<Result<Option<language::Transaction>>> {
24655        Task::ready(Ok(None))
24656    }
24657
24658    fn is_completion_trigger(
24659        &self,
24660        buffer: &Entity<Buffer>,
24661        position: language::Anchor,
24662        text: &str,
24663        trigger_in_words: bool,
24664        cx: &mut Context<Editor>,
24665    ) -> bool;
24666
24667    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24668
24669    fn sort_completions(&self) -> bool {
24670        true
24671    }
24672
24673    fn filter_completions(&self) -> bool {
24674        true
24675    }
24676
24677    fn show_snippets(&self) -> bool {
24678        false
24679    }
24680}
24681
24682pub trait CodeActionProvider {
24683    fn id(&self) -> Arc<str>;
24684
24685    fn code_actions(
24686        &self,
24687        buffer: &Entity<Buffer>,
24688        range: Range<text::Anchor>,
24689        window: &mut Window,
24690        cx: &mut App,
24691    ) -> Task<Result<Vec<CodeAction>>>;
24692
24693    fn apply_code_action(
24694        &self,
24695        buffer_handle: Entity<Buffer>,
24696        action: CodeAction,
24697        excerpt_id: ExcerptId,
24698        push_to_history: bool,
24699        window: &mut Window,
24700        cx: &mut App,
24701    ) -> Task<Result<ProjectTransaction>>;
24702}
24703
24704impl CodeActionProvider for Entity<Project> {
24705    fn id(&self) -> Arc<str> {
24706        "project".into()
24707    }
24708
24709    fn code_actions(
24710        &self,
24711        buffer: &Entity<Buffer>,
24712        range: Range<text::Anchor>,
24713        _window: &mut Window,
24714        cx: &mut App,
24715    ) -> Task<Result<Vec<CodeAction>>> {
24716        self.update(cx, |project, cx| {
24717            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24718            let code_actions = project.code_actions(buffer, range, None, cx);
24719            cx.background_spawn(async move {
24720                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24721                Ok(code_lens_actions
24722                    .context("code lens fetch")?
24723                    .into_iter()
24724                    .flatten()
24725                    .chain(
24726                        code_actions
24727                            .context("code action fetch")?
24728                            .into_iter()
24729                            .flatten(),
24730                    )
24731                    .collect())
24732            })
24733        })
24734    }
24735
24736    fn apply_code_action(
24737        &self,
24738        buffer_handle: Entity<Buffer>,
24739        action: CodeAction,
24740        _excerpt_id: ExcerptId,
24741        push_to_history: bool,
24742        _window: &mut Window,
24743        cx: &mut App,
24744    ) -> Task<Result<ProjectTransaction>> {
24745        self.update(cx, |project, cx| {
24746            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24747        })
24748    }
24749}
24750
24751fn snippet_completions(
24752    project: &Project,
24753    buffer: &Entity<Buffer>,
24754    buffer_anchor: text::Anchor,
24755    classifier: CharClassifier,
24756    cx: &mut App,
24757) -> Task<Result<CompletionResponse>> {
24758    let languages = buffer.read(cx).languages_at(buffer_anchor);
24759    let snippet_store = project.snippets().read(cx);
24760
24761    let scopes: Vec<_> = languages
24762        .iter()
24763        .filter_map(|language| {
24764            let language_name = language.lsp_id();
24765            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24766
24767            if snippets.is_empty() {
24768                None
24769            } else {
24770                Some((language.default_scope(), snippets))
24771            }
24772        })
24773        .collect();
24774
24775    if scopes.is_empty() {
24776        return Task::ready(Ok(CompletionResponse {
24777            completions: vec![],
24778            display_options: CompletionDisplayOptions::default(),
24779            is_incomplete: false,
24780        }));
24781    }
24782
24783    let snapshot = buffer.read(cx).text_snapshot();
24784    let executor = cx.background_executor().clone();
24785
24786    cx.background_spawn(async move {
24787        let is_word_char = |c| classifier.is_word(c);
24788
24789        let mut is_incomplete = false;
24790        let mut completions: Vec<Completion> = Vec::new();
24791
24792        const MAX_PREFIX_LEN: usize = 128;
24793        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24794        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24795        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24796
24797        let max_buffer_window: String = snapshot
24798            .text_for_range(window_start..buffer_offset)
24799            .collect();
24800
24801        if max_buffer_window.is_empty() {
24802            return Ok(CompletionResponse {
24803                completions: vec![],
24804                display_options: CompletionDisplayOptions::default(),
24805                is_incomplete: true,
24806            });
24807        }
24808
24809        for (_scope, snippets) in scopes.into_iter() {
24810            // Sort snippets by word count to match longer snippet prefixes first.
24811            let mut sorted_snippet_candidates = snippets
24812                .iter()
24813                .enumerate()
24814                .flat_map(|(snippet_ix, snippet)| {
24815                    snippet
24816                        .prefix
24817                        .iter()
24818                        .enumerate()
24819                        .map(move |(prefix_ix, prefix)| {
24820                            let word_count =
24821                                snippet_candidate_suffixes(prefix, is_word_char).count();
24822                            ((snippet_ix, prefix_ix), prefix, word_count)
24823                        })
24824                })
24825                .collect_vec();
24826            sorted_snippet_candidates
24827                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24828
24829            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24830
24831            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24832                .take(
24833                    sorted_snippet_candidates
24834                        .first()
24835                        .map(|(_, _, word_count)| *word_count)
24836                        .unwrap_or_default(),
24837                )
24838                .collect_vec();
24839
24840            const MAX_RESULTS: usize = 100;
24841            // Each match also remembers how many characters from the buffer it consumed
24842            let mut matches: Vec<(StringMatch, usize)> = vec![];
24843
24844            let mut snippet_list_cutoff_index = 0;
24845            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24846                let word_count = buffer_index + 1;
24847                // Increase `snippet_list_cutoff_index` until we have all of the
24848                // snippets with sufficiently many words.
24849                while sorted_snippet_candidates
24850                    .get(snippet_list_cutoff_index)
24851                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24852                        *snippet_word_count >= word_count
24853                    })
24854                {
24855                    snippet_list_cutoff_index += 1;
24856                }
24857
24858                // Take only the candidates with at least `word_count` many words
24859                let snippet_candidates_at_word_len =
24860                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24861
24862                let candidates = snippet_candidates_at_word_len
24863                    .iter()
24864                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24865                    .enumerate() // index in `sorted_snippet_candidates`
24866                    // First char must match
24867                    .filter(|(_ix, prefix)| {
24868                        itertools::equal(
24869                            prefix
24870                                .chars()
24871                                .next()
24872                                .into_iter()
24873                                .flat_map(|c| c.to_lowercase()),
24874                            buffer_window
24875                                .chars()
24876                                .next()
24877                                .into_iter()
24878                                .flat_map(|c| c.to_lowercase()),
24879                        )
24880                    })
24881                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24882                    .collect::<Vec<StringMatchCandidate>>();
24883
24884                matches.extend(
24885                    fuzzy::match_strings(
24886                        &candidates,
24887                        &buffer_window,
24888                        buffer_window.chars().any(|c| c.is_uppercase()),
24889                        true,
24890                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24891                        &Default::default(),
24892                        executor.clone(),
24893                    )
24894                    .await
24895                    .into_iter()
24896                    .map(|string_match| (string_match, buffer_window.len())),
24897                );
24898
24899                if matches.len() >= MAX_RESULTS {
24900                    break;
24901                }
24902            }
24903
24904            let to_lsp = |point: &text::Anchor| {
24905                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24906                point_to_lsp(end)
24907            };
24908            let lsp_end = to_lsp(&buffer_anchor);
24909
24910            if matches.len() >= MAX_RESULTS {
24911                is_incomplete = true;
24912            }
24913
24914            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24915                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24916                    sorted_snippet_candidates[string_match.candidate_id];
24917                let snippet = &snippets[snippet_index];
24918                let start = buffer_offset - buffer_window_len;
24919                let start = snapshot.anchor_before(start);
24920                let range = start..buffer_anchor;
24921                let lsp_start = to_lsp(&start);
24922                let lsp_range = lsp::Range {
24923                    start: lsp_start,
24924                    end: lsp_end,
24925                };
24926                Completion {
24927                    replace_range: range,
24928                    new_text: snippet.body.clone(),
24929                    source: CompletionSource::Lsp {
24930                        insert_range: None,
24931                        server_id: LanguageServerId(usize::MAX),
24932                        resolved: true,
24933                        lsp_completion: Box::new(lsp::CompletionItem {
24934                            label: snippet.prefix.first().unwrap().clone(),
24935                            kind: Some(CompletionItemKind::SNIPPET),
24936                            label_details: snippet.description.as_ref().map(|description| {
24937                                lsp::CompletionItemLabelDetails {
24938                                    detail: Some(description.clone()),
24939                                    description: None,
24940                                }
24941                            }),
24942                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24943                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24944                                lsp::InsertReplaceEdit {
24945                                    new_text: snippet.body.clone(),
24946                                    insert: lsp_range,
24947                                    replace: lsp_range,
24948                                },
24949                            )),
24950                            filter_text: Some(snippet.body.clone()),
24951                            sort_text: Some(char::MAX.to_string()),
24952                            ..lsp::CompletionItem::default()
24953                        }),
24954                        lsp_defaults: None,
24955                    },
24956                    label: CodeLabel {
24957                        text: matching_prefix.clone(),
24958                        runs: Vec::new(),
24959                        filter_range: 0..matching_prefix.len(),
24960                    },
24961                    icon_path: None,
24962                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24963                        single_line: snippet.name.clone().into(),
24964                        plain_text: snippet
24965                            .description
24966                            .clone()
24967                            .map(|description| description.into()),
24968                    }),
24969                    insert_text_mode: None,
24970                    confirm: None,
24971                    match_start: Some(start),
24972                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24973                }
24974            }));
24975        }
24976
24977        Ok(CompletionResponse {
24978            completions,
24979            display_options: CompletionDisplayOptions::default(),
24980            is_incomplete,
24981        })
24982    })
24983}
24984
24985impl CompletionProvider for Entity<Project> {
24986    fn completions(
24987        &self,
24988        _excerpt_id: ExcerptId,
24989        buffer: &Entity<Buffer>,
24990        buffer_position: text::Anchor,
24991        options: CompletionContext,
24992        _window: &mut Window,
24993        cx: &mut Context<Editor>,
24994    ) -> Task<Result<Vec<CompletionResponse>>> {
24995        self.update(cx, |project, cx| {
24996            let task = project.completions(buffer, buffer_position, options, cx);
24997            cx.background_spawn(task)
24998        })
24999    }
25000
25001    fn resolve_completions(
25002        &self,
25003        buffer: Entity<Buffer>,
25004        completion_indices: Vec<usize>,
25005        completions: Rc<RefCell<Box<[Completion]>>>,
25006        cx: &mut Context<Editor>,
25007    ) -> Task<Result<bool>> {
25008        self.update(cx, |project, cx| {
25009            project.lsp_store().update(cx, |lsp_store, cx| {
25010                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
25011            })
25012        })
25013    }
25014
25015    fn apply_additional_edits_for_completion(
25016        &self,
25017        buffer: Entity<Buffer>,
25018        completions: Rc<RefCell<Box<[Completion]>>>,
25019        completion_index: usize,
25020        push_to_history: bool,
25021        cx: &mut Context<Editor>,
25022    ) -> Task<Result<Option<language::Transaction>>> {
25023        self.update(cx, |project, cx| {
25024            project.lsp_store().update(cx, |lsp_store, cx| {
25025                lsp_store.apply_additional_edits_for_completion(
25026                    buffer,
25027                    completions,
25028                    completion_index,
25029                    push_to_history,
25030                    cx,
25031                )
25032            })
25033        })
25034    }
25035
25036    fn is_completion_trigger(
25037        &self,
25038        buffer: &Entity<Buffer>,
25039        position: language::Anchor,
25040        text: &str,
25041        trigger_in_words: bool,
25042        cx: &mut Context<Editor>,
25043    ) -> bool {
25044        let mut chars = text.chars();
25045        let char = if let Some(char) = chars.next() {
25046            char
25047        } else {
25048            return false;
25049        };
25050        if chars.next().is_some() {
25051            return false;
25052        }
25053
25054        let buffer = buffer.read(cx);
25055        let snapshot = buffer.snapshot();
25056        let classifier = snapshot
25057            .char_classifier_at(position)
25058            .scope_context(Some(CharScopeContext::Completion));
25059        if trigger_in_words && classifier.is_word(char) {
25060            return true;
25061        }
25062
25063        buffer.completion_triggers().contains(text)
25064    }
25065
25066    fn show_snippets(&self) -> bool {
25067        true
25068    }
25069}
25070
25071impl SemanticsProvider for Entity<Project> {
25072    fn hover(
25073        &self,
25074        buffer: &Entity<Buffer>,
25075        position: text::Anchor,
25076        cx: &mut App,
25077    ) -> Option<Task<Option<Vec<project::Hover>>>> {
25078        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
25079    }
25080
25081    fn document_highlights(
25082        &self,
25083        buffer: &Entity<Buffer>,
25084        position: text::Anchor,
25085        cx: &mut App,
25086    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
25087        Some(self.update(cx, |project, cx| {
25088            project.document_highlights(buffer, position, cx)
25089        }))
25090    }
25091
25092    fn definitions(
25093        &self,
25094        buffer: &Entity<Buffer>,
25095        position: text::Anchor,
25096        kind: GotoDefinitionKind,
25097        cx: &mut App,
25098    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
25099        Some(self.update(cx, |project, cx| match kind {
25100            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
25101            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
25102            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
25103            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
25104        }))
25105    }
25106
25107    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
25108        self.update(cx, |project, cx| {
25109            if project
25110                .active_debug_session(cx)
25111                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
25112            {
25113                return true;
25114            }
25115
25116            buffer.update(cx, |buffer, cx| {
25117                project.any_language_server_supports_inlay_hints(buffer, cx)
25118            })
25119        })
25120    }
25121
25122    fn inline_values(
25123        &self,
25124        buffer_handle: Entity<Buffer>,
25125        range: Range<text::Anchor>,
25126        cx: &mut App,
25127    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
25128        self.update(cx, |project, cx| {
25129            let (session, active_stack_frame) = project.active_debug_session(cx)?;
25130
25131            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
25132        })
25133    }
25134
25135    fn applicable_inlay_chunks(
25136        &self,
25137        buffer: &Entity<Buffer>,
25138        ranges: &[Range<text::Anchor>],
25139        cx: &mut App,
25140    ) -> Vec<Range<BufferRow>> {
25141        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25142            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
25143        })
25144    }
25145
25146    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
25147        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
25148            lsp_store.invalidate_inlay_hints(for_buffers)
25149        });
25150    }
25151
25152    fn inlay_hints(
25153        &self,
25154        invalidate: InvalidationStrategy,
25155        buffer: Entity<Buffer>,
25156        ranges: Vec<Range<text::Anchor>>,
25157        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
25158        cx: &mut App,
25159    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
25160        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25161            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
25162        }))
25163    }
25164
25165    fn range_for_rename(
25166        &self,
25167        buffer: &Entity<Buffer>,
25168        position: text::Anchor,
25169        cx: &mut App,
25170    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
25171        Some(self.update(cx, |project, cx| {
25172            let buffer = buffer.clone();
25173            let task = project.prepare_rename(buffer.clone(), position, cx);
25174            cx.spawn(async move |_, cx| {
25175                Ok(match task.await? {
25176                    PrepareRenameResponse::Success(range) => Some(range),
25177                    PrepareRenameResponse::InvalidPosition => None,
25178                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
25179                        // Fallback on using TreeSitter info to determine identifier range
25180                        buffer.read_with(cx, |buffer, _| {
25181                            let snapshot = buffer.snapshot();
25182                            let (range, kind) = snapshot.surrounding_word(position, None);
25183                            if kind != Some(CharKind::Word) {
25184                                return None;
25185                            }
25186                            Some(
25187                                snapshot.anchor_before(range.start)
25188                                    ..snapshot.anchor_after(range.end),
25189                            )
25190                        })
25191                    }
25192                })
25193            })
25194        }))
25195    }
25196
25197    fn perform_rename(
25198        &self,
25199        buffer: &Entity<Buffer>,
25200        position: text::Anchor,
25201        new_name: String,
25202        cx: &mut App,
25203    ) -> Option<Task<Result<ProjectTransaction>>> {
25204        Some(self.update(cx, |project, cx| {
25205            project.perform_rename(buffer.clone(), position, new_name, cx)
25206        }))
25207    }
25208}
25209
25210fn consume_contiguous_rows(
25211    contiguous_row_selections: &mut Vec<Selection<Point>>,
25212    selection: &Selection<Point>,
25213    display_map: &DisplaySnapshot,
25214    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
25215) -> (MultiBufferRow, MultiBufferRow) {
25216    contiguous_row_selections.push(selection.clone());
25217    let start_row = starting_row(selection, display_map);
25218    let mut end_row = ending_row(selection, display_map);
25219
25220    while let Some(next_selection) = selections.peek() {
25221        if next_selection.start.row <= end_row.0 {
25222            end_row = ending_row(next_selection, display_map);
25223            contiguous_row_selections.push(selections.next().unwrap().clone());
25224        } else {
25225            break;
25226        }
25227    }
25228    (start_row, end_row)
25229}
25230
25231fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25232    if selection.start.column > 0 {
25233        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
25234    } else {
25235        MultiBufferRow(selection.start.row)
25236    }
25237}
25238
25239fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25240    if next_selection.end.column > 0 || next_selection.is_empty() {
25241        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
25242    } else {
25243        MultiBufferRow(next_selection.end.row)
25244    }
25245}
25246
25247impl EditorSnapshot {
25248    pub fn remote_selections_in_range<'a>(
25249        &'a self,
25250        range: &'a Range<Anchor>,
25251        collaboration_hub: &dyn CollaborationHub,
25252        cx: &'a App,
25253    ) -> impl 'a + Iterator<Item = RemoteSelection> {
25254        let participant_names = collaboration_hub.user_names(cx);
25255        let participant_indices = collaboration_hub.user_participant_indices(cx);
25256        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
25257        let collaborators_by_replica_id = collaborators_by_peer_id
25258            .values()
25259            .map(|collaborator| (collaborator.replica_id, collaborator))
25260            .collect::<HashMap<_, _>>();
25261        self.buffer_snapshot()
25262            .selections_in_range(range, false)
25263            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
25264                if replica_id == ReplicaId::AGENT {
25265                    Some(RemoteSelection {
25266                        replica_id,
25267                        selection,
25268                        cursor_shape,
25269                        line_mode,
25270                        collaborator_id: CollaboratorId::Agent,
25271                        user_name: Some("Agent".into()),
25272                        color: cx.theme().players().agent(),
25273                    })
25274                } else {
25275                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
25276                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
25277                    let user_name = participant_names.get(&collaborator.user_id).cloned();
25278                    Some(RemoteSelection {
25279                        replica_id,
25280                        selection,
25281                        cursor_shape,
25282                        line_mode,
25283                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25284                        user_name,
25285                        color: if let Some(index) = participant_index {
25286                            cx.theme().players().color_for_participant(index.0)
25287                        } else {
25288                            cx.theme().players().absent()
25289                        },
25290                    })
25291                }
25292            })
25293    }
25294
25295    pub fn hunks_for_ranges(
25296        &self,
25297        ranges: impl IntoIterator<Item = Range<Point>>,
25298    ) -> Vec<MultiBufferDiffHunk> {
25299        let mut hunks = Vec::new();
25300        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25301            HashMap::default();
25302        for query_range in ranges {
25303            let query_rows =
25304                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25305            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25306                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25307            ) {
25308                // Include deleted hunks that are adjacent to the query range, because
25309                // otherwise they would be missed.
25310                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25311                if hunk.status().is_deleted() {
25312                    intersects_range |= hunk.row_range.start == query_rows.end;
25313                    intersects_range |= hunk.row_range.end == query_rows.start;
25314                }
25315                if intersects_range {
25316                    if !processed_buffer_rows
25317                        .entry(hunk.buffer_id)
25318                        .or_default()
25319                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25320                    {
25321                        continue;
25322                    }
25323                    hunks.push(hunk);
25324                }
25325            }
25326        }
25327
25328        hunks
25329    }
25330
25331    fn display_diff_hunks_for_rows<'a>(
25332        &'a self,
25333        display_rows: Range<DisplayRow>,
25334        folded_buffers: &'a HashSet<BufferId>,
25335    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25336        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25337        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25338
25339        self.buffer_snapshot()
25340            .diff_hunks_in_range(buffer_start..buffer_end)
25341            .filter_map(|hunk| {
25342                if folded_buffers.contains(&hunk.buffer_id) {
25343                    return None;
25344                }
25345
25346                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25347                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25348
25349                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25350                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25351
25352                let display_hunk = if hunk_display_start.column() != 0 {
25353                    DisplayDiffHunk::Folded {
25354                        display_row: hunk_display_start.row(),
25355                    }
25356                } else {
25357                    let mut end_row = hunk_display_end.row();
25358                    if hunk_display_end.column() > 0 {
25359                        end_row.0 += 1;
25360                    }
25361                    let is_created_file = hunk.is_created_file();
25362
25363                    DisplayDiffHunk::Unfolded {
25364                        status: hunk.status(),
25365                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25366                            ..hunk.diff_base_byte_range.end.0,
25367                        word_diffs: hunk.word_diffs,
25368                        display_row_range: hunk_display_start.row()..end_row,
25369                        multi_buffer_range: Anchor::range_in_buffer(
25370                            hunk.excerpt_id,
25371                            hunk.buffer_range,
25372                        ),
25373                        is_created_file,
25374                    }
25375                };
25376
25377                Some(display_hunk)
25378            })
25379    }
25380
25381    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25382        self.display_snapshot
25383            .buffer_snapshot()
25384            .language_at(position)
25385    }
25386
25387    pub fn is_focused(&self) -> bool {
25388        self.is_focused
25389    }
25390
25391    pub fn placeholder_text(&self) -> Option<String> {
25392        self.placeholder_display_snapshot
25393            .as_ref()
25394            .map(|display_map| display_map.text())
25395    }
25396
25397    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25398        self.scroll_anchor.scroll_position(&self.display_snapshot)
25399    }
25400
25401    pub fn gutter_dimensions(
25402        &self,
25403        font_id: FontId,
25404        font_size: Pixels,
25405        style: &EditorStyle,
25406        window: &mut Window,
25407        cx: &App,
25408    ) -> GutterDimensions {
25409        if self.show_gutter
25410            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25411            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25412        {
25413            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25414                matches!(
25415                    ProjectSettings::get_global(cx).git.git_gutter,
25416                    GitGutterSetting::TrackedFiles
25417                )
25418            });
25419            let gutter_settings = EditorSettings::get_global(cx).gutter;
25420            let show_line_numbers = self
25421                .show_line_numbers
25422                .unwrap_or(gutter_settings.line_numbers);
25423            let line_gutter_width = if show_line_numbers {
25424                // Avoid flicker-like gutter resizes when the line number gains another digit by
25425                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25426                let min_width_for_number_on_gutter =
25427                    ch_advance * gutter_settings.min_line_number_digits as f32;
25428                self.max_line_number_width(style, window)
25429                    .max(min_width_for_number_on_gutter)
25430            } else {
25431                0.0.into()
25432            };
25433
25434            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25435            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25436
25437            let git_blame_entries_width =
25438                self.git_blame_gutter_max_author_length
25439                    .map(|max_author_length| {
25440                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25441                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25442
25443                        /// The number of characters to dedicate to gaps and margins.
25444                        const SPACING_WIDTH: usize = 4;
25445
25446                        let max_char_count = max_author_length.min(renderer.max_author_length())
25447                            + ::git::SHORT_SHA_LENGTH
25448                            + MAX_RELATIVE_TIMESTAMP.len()
25449                            + SPACING_WIDTH;
25450
25451                        ch_advance * max_char_count
25452                    });
25453
25454            let is_singleton = self.buffer_snapshot().is_singleton();
25455
25456            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25457            left_padding += if !is_singleton {
25458                ch_width * 4.0
25459            } else if show_runnables || show_breakpoints {
25460                ch_width * 3.0
25461            } else if show_git_gutter && show_line_numbers {
25462                ch_width * 2.0
25463            } else if show_git_gutter || show_line_numbers {
25464                ch_width
25465            } else {
25466                px(0.)
25467            };
25468
25469            let shows_folds = is_singleton && gutter_settings.folds;
25470
25471            let right_padding = if shows_folds && show_line_numbers {
25472                ch_width * 4.0
25473            } else if shows_folds || (!is_singleton && show_line_numbers) {
25474                ch_width * 3.0
25475            } else if show_line_numbers {
25476                ch_width
25477            } else {
25478                px(0.)
25479            };
25480
25481            GutterDimensions {
25482                left_padding,
25483                right_padding,
25484                width: line_gutter_width + left_padding + right_padding,
25485                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25486                git_blame_entries_width,
25487            }
25488        } else if self.offset_content {
25489            GutterDimensions::default_with_margin(font_id, font_size, cx)
25490        } else {
25491            GutterDimensions::default()
25492        }
25493    }
25494
25495    pub fn render_crease_toggle(
25496        &self,
25497        buffer_row: MultiBufferRow,
25498        row_contains_cursor: bool,
25499        editor: Entity<Editor>,
25500        window: &mut Window,
25501        cx: &mut App,
25502    ) -> Option<AnyElement> {
25503        let folded = self.is_line_folded(buffer_row);
25504        let mut is_foldable = false;
25505
25506        if let Some(crease) = self
25507            .crease_snapshot
25508            .query_row(buffer_row, self.buffer_snapshot())
25509        {
25510            is_foldable = true;
25511            match crease {
25512                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25513                    if let Some(render_toggle) = render_toggle {
25514                        let toggle_callback =
25515                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25516                                if folded {
25517                                    editor.update(cx, |editor, cx| {
25518                                        editor.fold_at(buffer_row, window, cx)
25519                                    });
25520                                } else {
25521                                    editor.update(cx, |editor, cx| {
25522                                        editor.unfold_at(buffer_row, window, cx)
25523                                    });
25524                                }
25525                            });
25526                        return Some((render_toggle)(
25527                            buffer_row,
25528                            folded,
25529                            toggle_callback,
25530                            window,
25531                            cx,
25532                        ));
25533                    }
25534                }
25535            }
25536        }
25537
25538        is_foldable |= self.starts_indent(buffer_row);
25539
25540        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25541            Some(
25542                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25543                    .toggle_state(folded)
25544                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25545                        if folded {
25546                            this.unfold_at(buffer_row, window, cx);
25547                        } else {
25548                            this.fold_at(buffer_row, window, cx);
25549                        }
25550                    }))
25551                    .into_any_element(),
25552            )
25553        } else {
25554            None
25555        }
25556    }
25557
25558    pub fn render_crease_trailer(
25559        &self,
25560        buffer_row: MultiBufferRow,
25561        window: &mut Window,
25562        cx: &mut App,
25563    ) -> Option<AnyElement> {
25564        let folded = self.is_line_folded(buffer_row);
25565        if let Crease::Inline { render_trailer, .. } = self
25566            .crease_snapshot
25567            .query_row(buffer_row, self.buffer_snapshot())?
25568        {
25569            let render_trailer = render_trailer.as_ref()?;
25570            Some(render_trailer(buffer_row, folded, window, cx))
25571        } else {
25572            None
25573        }
25574    }
25575
25576    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25577        let digit_count = self.widest_line_number().ilog10() + 1;
25578        column_pixels(style, digit_count as usize, window)
25579    }
25580
25581    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
25582    ///
25583    /// This is positive if `base` is before `line`.
25584    fn relative_line_delta(
25585        &self,
25586        current_selection_head: DisplayRow,
25587        first_visible_row: DisplayRow,
25588        consider_wrapped_lines: bool,
25589    ) -> i64 {
25590        let current_selection_head = current_selection_head.as_display_point().to_point(self);
25591        let first_visible_row = first_visible_row.as_display_point().to_point(self);
25592
25593        if consider_wrapped_lines {
25594            let wrap_snapshot = self.wrap_snapshot();
25595            let base_wrap_row = wrap_snapshot
25596                .make_wrap_point(current_selection_head, Bias::Left)
25597                .row();
25598            let wrap_row = wrap_snapshot
25599                .make_wrap_point(first_visible_row, Bias::Left)
25600                .row();
25601            wrap_row.0 as i64 - base_wrap_row.0 as i64
25602        } else {
25603            let folds = if current_selection_head < first_visible_row {
25604                self.folds_in_range(current_selection_head..first_visible_row)
25605            } else {
25606                self.folds_in_range(first_visible_row..current_selection_head)
25607            };
25608
25609            let folded_lines = folds
25610                .map(|fold| {
25611                    let range = fold.range.0.to_point(self);
25612                    range.end.row.saturating_sub(range.start.row)
25613                })
25614                .sum::<u32>() as i64;
25615
25616            first_visible_row.row as i64 - current_selection_head.row as i64 + folded_lines
25617        }
25618    }
25619
25620    /// Returns the unsigned relative line number to display for each row in `rows`.
25621    ///
25622    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
25623    pub fn calculate_relative_line_numbers(
25624        &self,
25625        rows: &Range<DisplayRow>,
25626        current_selection_head: DisplayRow,
25627        count_wrapped_lines: bool,
25628    ) -> HashMap<DisplayRow, u32> {
25629        let initial_offset =
25630            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
25631        let current_selection_point = current_selection_head.as_display_point().to_point(self);
25632
25633        self.row_infos(rows.start)
25634            .take(rows.len())
25635            .enumerate()
25636            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
25637            .filter(|(_row, row_info)| {
25638                row_info.buffer_row.is_some()
25639                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
25640            })
25641            .enumerate()
25642            .filter(|(_, (row, row_info))| {
25643                // We want to check here that
25644                // - the row is not the current selection head to ensure the current
25645                // line has absolute numbering
25646                // - similarly, should the selection head live in a soft-wrapped line
25647                // and we are not counting those, that the parent line keeps its
25648                // absolute number
25649                // - lastly, if we are in a deleted line, it is fine to number this
25650                // relative with 0, as otherwise it would have no line number at all
25651                (*row != current_selection_head
25652                    && (count_wrapped_lines
25653                        || row_info.buffer_row != Some(current_selection_point.row)))
25654                    || row_info
25655                        .diff_status
25656                        .is_some_and(|status| status.is_deleted())
25657            })
25658            .map(|(i, (row, _))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
25659            .collect()
25660    }
25661}
25662
25663pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25664    let font_size = style.text.font_size.to_pixels(window.rem_size());
25665    let layout = window.text_system().shape_line(
25666        SharedString::from(" ".repeat(column)),
25667        font_size,
25668        &[TextRun {
25669            len: column,
25670            font: style.text.font(),
25671            color: Hsla::default(),
25672            ..Default::default()
25673        }],
25674        None,
25675    );
25676
25677    layout.width
25678}
25679
25680impl Deref for EditorSnapshot {
25681    type Target = DisplaySnapshot;
25682
25683    fn deref(&self) -> &Self::Target {
25684        &self.display_snapshot
25685    }
25686}
25687
25688#[derive(Clone, Debug, PartialEq, Eq)]
25689pub enum EditorEvent {
25690    InputIgnored {
25691        text: Arc<str>,
25692    },
25693    InputHandled {
25694        utf16_range_to_replace: Option<Range<isize>>,
25695        text: Arc<str>,
25696    },
25697    ExcerptsAdded {
25698        buffer: Entity<Buffer>,
25699        predecessor: ExcerptId,
25700        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25701    },
25702    ExcerptsRemoved {
25703        ids: Vec<ExcerptId>,
25704        removed_buffer_ids: Vec<BufferId>,
25705    },
25706    BufferFoldToggled {
25707        ids: Vec<ExcerptId>,
25708        folded: bool,
25709    },
25710    ExcerptsEdited {
25711        ids: Vec<ExcerptId>,
25712    },
25713    ExcerptsExpanded {
25714        ids: Vec<ExcerptId>,
25715    },
25716    ExpandExcerptsRequested {
25717        excerpt_ids: Vec<ExcerptId>,
25718        lines: u32,
25719        direction: ExpandExcerptDirection,
25720    },
25721    BufferEdited,
25722    Edited {
25723        transaction_id: clock::Lamport,
25724    },
25725    Reparsed(BufferId),
25726    Focused,
25727    FocusedIn,
25728    Blurred,
25729    DirtyChanged,
25730    Saved,
25731    TitleChanged,
25732    SelectionsChanged {
25733        local: bool,
25734    },
25735    ScrollPositionChanged {
25736        local: bool,
25737        autoscroll: bool,
25738    },
25739    TransactionUndone {
25740        transaction_id: clock::Lamport,
25741    },
25742    TransactionBegun {
25743        transaction_id: clock::Lamport,
25744    },
25745    CursorShapeChanged,
25746    BreadcrumbsChanged,
25747    PushedToNavHistory {
25748        anchor: Anchor,
25749        is_deactivate: bool,
25750    },
25751}
25752
25753impl EventEmitter<EditorEvent> for Editor {}
25754
25755impl Focusable for Editor {
25756    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25757        self.focus_handle.clone()
25758    }
25759}
25760
25761impl Render for Editor {
25762    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25763        EditorElement::new(&cx.entity(), self.create_style(cx))
25764    }
25765}
25766
25767impl EntityInputHandler for Editor {
25768    fn text_for_range(
25769        &mut self,
25770        range_utf16: Range<usize>,
25771        adjusted_range: &mut Option<Range<usize>>,
25772        _: &mut Window,
25773        cx: &mut Context<Self>,
25774    ) -> Option<String> {
25775        let snapshot = self.buffer.read(cx).read(cx);
25776        let start = snapshot.clip_offset_utf16(
25777            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25778            Bias::Left,
25779        );
25780        let end = snapshot.clip_offset_utf16(
25781            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25782            Bias::Right,
25783        );
25784        if (start.0.0..end.0.0) != range_utf16 {
25785            adjusted_range.replace(start.0.0..end.0.0);
25786        }
25787        Some(snapshot.text_for_range(start..end).collect())
25788    }
25789
25790    fn selected_text_range(
25791        &mut self,
25792        ignore_disabled_input: bool,
25793        _: &mut Window,
25794        cx: &mut Context<Self>,
25795    ) -> Option<UTF16Selection> {
25796        // Prevent the IME menu from appearing when holding down an alphabetic key
25797        // while input is disabled.
25798        if !ignore_disabled_input && !self.input_enabled {
25799            return None;
25800        }
25801
25802        let selection = self
25803            .selections
25804            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25805        let range = selection.range();
25806
25807        Some(UTF16Selection {
25808            range: range.start.0.0..range.end.0.0,
25809            reversed: selection.reversed,
25810        })
25811    }
25812
25813    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25814        let snapshot = self.buffer.read(cx).read(cx);
25815        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25816        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25817    }
25818
25819    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25820        self.clear_highlights::<InputComposition>(cx);
25821        self.ime_transaction.take();
25822    }
25823
25824    fn replace_text_in_range(
25825        &mut self,
25826        range_utf16: Option<Range<usize>>,
25827        text: &str,
25828        window: &mut Window,
25829        cx: &mut Context<Self>,
25830    ) {
25831        if !self.input_enabled {
25832            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25833            return;
25834        }
25835
25836        self.transact(window, cx, |this, window, cx| {
25837            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25838                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25839                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25840                Some(this.selection_replacement_ranges(range_utf16, cx))
25841            } else {
25842                this.marked_text_ranges(cx)
25843            };
25844
25845            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25846                let newest_selection_id = this.selections.newest_anchor().id;
25847                this.selections
25848                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25849                    .iter()
25850                    .zip(ranges_to_replace.iter())
25851                    .find_map(|(selection, range)| {
25852                        if selection.id == newest_selection_id {
25853                            Some(
25854                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25855                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25856                            )
25857                        } else {
25858                            None
25859                        }
25860                    })
25861            });
25862
25863            cx.emit(EditorEvent::InputHandled {
25864                utf16_range_to_replace: range_to_replace,
25865                text: text.into(),
25866            });
25867
25868            if let Some(new_selected_ranges) = new_selected_ranges {
25869                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25870                    selections.select_ranges(new_selected_ranges)
25871                });
25872                this.backspace(&Default::default(), window, cx);
25873            }
25874
25875            this.handle_input(text, window, cx);
25876        });
25877
25878        if let Some(transaction) = self.ime_transaction {
25879            self.buffer.update(cx, |buffer, cx| {
25880                buffer.group_until_transaction(transaction, cx);
25881            });
25882        }
25883
25884        self.unmark_text(window, cx);
25885    }
25886
25887    fn replace_and_mark_text_in_range(
25888        &mut self,
25889        range_utf16: Option<Range<usize>>,
25890        text: &str,
25891        new_selected_range_utf16: Option<Range<usize>>,
25892        window: &mut Window,
25893        cx: &mut Context<Self>,
25894    ) {
25895        if !self.input_enabled {
25896            return;
25897        }
25898
25899        let transaction = self.transact(window, cx, |this, window, cx| {
25900            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25901                let snapshot = this.buffer.read(cx).read(cx);
25902                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25903                    for marked_range in &mut marked_ranges {
25904                        marked_range.end = marked_range.start + relative_range_utf16.end;
25905                        marked_range.start += relative_range_utf16.start;
25906                        marked_range.start =
25907                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25908                        marked_range.end =
25909                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25910                    }
25911                }
25912                Some(marked_ranges)
25913            } else if let Some(range_utf16) = range_utf16 {
25914                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25915                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25916                Some(this.selection_replacement_ranges(range_utf16, cx))
25917            } else {
25918                None
25919            };
25920
25921            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25922                let newest_selection_id = this.selections.newest_anchor().id;
25923                this.selections
25924                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25925                    .iter()
25926                    .zip(ranges_to_replace.iter())
25927                    .find_map(|(selection, range)| {
25928                        if selection.id == newest_selection_id {
25929                            Some(
25930                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25931                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25932                            )
25933                        } else {
25934                            None
25935                        }
25936                    })
25937            });
25938
25939            cx.emit(EditorEvent::InputHandled {
25940                utf16_range_to_replace: range_to_replace,
25941                text: text.into(),
25942            });
25943
25944            if let Some(ranges) = ranges_to_replace {
25945                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25946                    s.select_ranges(ranges)
25947                });
25948            }
25949
25950            let marked_ranges = {
25951                let snapshot = this.buffer.read(cx).read(cx);
25952                this.selections
25953                    .disjoint_anchors_arc()
25954                    .iter()
25955                    .map(|selection| {
25956                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25957                    })
25958                    .collect::<Vec<_>>()
25959            };
25960
25961            if text.is_empty() {
25962                this.unmark_text(window, cx);
25963            } else {
25964                this.highlight_text::<InputComposition>(
25965                    marked_ranges.clone(),
25966                    HighlightStyle {
25967                        underline: Some(UnderlineStyle {
25968                            thickness: px(1.),
25969                            color: None,
25970                            wavy: false,
25971                        }),
25972                        ..Default::default()
25973                    },
25974                    cx,
25975                );
25976            }
25977
25978            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25979            let use_autoclose = this.use_autoclose;
25980            let use_auto_surround = this.use_auto_surround;
25981            this.set_use_autoclose(false);
25982            this.set_use_auto_surround(false);
25983            this.handle_input(text, window, cx);
25984            this.set_use_autoclose(use_autoclose);
25985            this.set_use_auto_surround(use_auto_surround);
25986
25987            if let Some(new_selected_range) = new_selected_range_utf16 {
25988                let snapshot = this.buffer.read(cx).read(cx);
25989                let new_selected_ranges = marked_ranges
25990                    .into_iter()
25991                    .map(|marked_range| {
25992                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25993                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25994                            insertion_start.0 + new_selected_range.start,
25995                        ));
25996                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25997                            insertion_start.0 + new_selected_range.end,
25998                        ));
25999                        snapshot.clip_offset_utf16(new_start, Bias::Left)
26000                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
26001                    })
26002                    .collect::<Vec<_>>();
26003
26004                drop(snapshot);
26005                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
26006                    selections.select_ranges(new_selected_ranges)
26007                });
26008            }
26009        });
26010
26011        self.ime_transaction = self.ime_transaction.or(transaction);
26012        if let Some(transaction) = self.ime_transaction {
26013            self.buffer.update(cx, |buffer, cx| {
26014                buffer.group_until_transaction(transaction, cx);
26015            });
26016        }
26017
26018        if self.text_highlights::<InputComposition>(cx).is_none() {
26019            self.ime_transaction.take();
26020        }
26021    }
26022
26023    fn bounds_for_range(
26024        &mut self,
26025        range_utf16: Range<usize>,
26026        element_bounds: gpui::Bounds<Pixels>,
26027        window: &mut Window,
26028        cx: &mut Context<Self>,
26029    ) -> Option<gpui::Bounds<Pixels>> {
26030        let text_layout_details = self.text_layout_details(window);
26031        let CharacterDimensions {
26032            em_width,
26033            em_advance,
26034            line_height,
26035        } = self.character_dimensions(window);
26036
26037        let snapshot = self.snapshot(window, cx);
26038        let scroll_position = snapshot.scroll_position();
26039        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
26040
26041        let start =
26042            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
26043        let x = Pixels::from(
26044            ScrollOffset::from(
26045                snapshot.x_for_display_point(start, &text_layout_details)
26046                    + self.gutter_dimensions.full_width(),
26047            ) - scroll_left,
26048        );
26049        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
26050
26051        Some(Bounds {
26052            origin: element_bounds.origin + point(x, y),
26053            size: size(em_width, line_height),
26054        })
26055    }
26056
26057    fn character_index_for_point(
26058        &mut self,
26059        point: gpui::Point<Pixels>,
26060        _window: &mut Window,
26061        _cx: &mut Context<Self>,
26062    ) -> Option<usize> {
26063        let position_map = self.last_position_map.as_ref()?;
26064        if !position_map.text_hitbox.contains(&point) {
26065            return None;
26066        }
26067        let display_point = position_map.point_for_position(point).previous_valid;
26068        let anchor = position_map
26069            .snapshot
26070            .display_point_to_anchor(display_point, Bias::Left);
26071        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
26072        Some(utf16_offset.0.0)
26073    }
26074
26075    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
26076        self.input_enabled
26077    }
26078}
26079
26080trait SelectionExt {
26081    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
26082    fn spanned_rows(
26083        &self,
26084        include_end_if_at_line_start: bool,
26085        map: &DisplaySnapshot,
26086    ) -> Range<MultiBufferRow>;
26087}
26088
26089impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
26090    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
26091        let start = self
26092            .start
26093            .to_point(map.buffer_snapshot())
26094            .to_display_point(map);
26095        let end = self
26096            .end
26097            .to_point(map.buffer_snapshot())
26098            .to_display_point(map);
26099        if self.reversed {
26100            end..start
26101        } else {
26102            start..end
26103        }
26104    }
26105
26106    fn spanned_rows(
26107        &self,
26108        include_end_if_at_line_start: bool,
26109        map: &DisplaySnapshot,
26110    ) -> Range<MultiBufferRow> {
26111        let start = self.start.to_point(map.buffer_snapshot());
26112        let mut end = self.end.to_point(map.buffer_snapshot());
26113        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
26114            end.row -= 1;
26115        }
26116
26117        let buffer_start = map.prev_line_boundary(start).0;
26118        let buffer_end = map.next_line_boundary(end).0;
26119        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
26120    }
26121}
26122
26123impl<T: InvalidationRegion> InvalidationStack<T> {
26124    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
26125    where
26126        S: Clone + ToOffset,
26127    {
26128        while let Some(region) = self.last() {
26129            let all_selections_inside_invalidation_ranges =
26130                if selections.len() == region.ranges().len() {
26131                    selections
26132                        .iter()
26133                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
26134                        .all(|(selection, invalidation_range)| {
26135                            let head = selection.head().to_offset(buffer);
26136                            invalidation_range.start <= head && invalidation_range.end >= head
26137                        })
26138                } else {
26139                    false
26140                };
26141
26142            if all_selections_inside_invalidation_ranges {
26143                break;
26144            } else {
26145                self.pop();
26146            }
26147        }
26148    }
26149}
26150
26151impl<T> Default for InvalidationStack<T> {
26152    fn default() -> Self {
26153        Self(Default::default())
26154    }
26155}
26156
26157impl<T> Deref for InvalidationStack<T> {
26158    type Target = Vec<T>;
26159
26160    fn deref(&self) -> &Self::Target {
26161        &self.0
26162    }
26163}
26164
26165impl<T> DerefMut for InvalidationStack<T> {
26166    fn deref_mut(&mut self) -> &mut Self::Target {
26167        &mut self.0
26168    }
26169}
26170
26171impl InvalidationRegion for SnippetState {
26172    fn ranges(&self) -> &[Range<Anchor>] {
26173        &self.ranges[self.active_index]
26174    }
26175}
26176
26177fn edit_prediction_edit_text(
26178    current_snapshot: &BufferSnapshot,
26179    edits: &[(Range<Anchor>, impl AsRef<str>)],
26180    edit_preview: &EditPreview,
26181    include_deletions: bool,
26182    cx: &App,
26183) -> HighlightedText {
26184    let edits = edits
26185        .iter()
26186        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
26187        .collect::<Vec<_>>();
26188
26189    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
26190}
26191
26192fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
26193    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
26194    // Just show the raw edit text with basic styling
26195    let mut text = String::new();
26196    let mut highlights = Vec::new();
26197
26198    let insertion_highlight_style = HighlightStyle {
26199        color: Some(cx.theme().colors().text),
26200        ..Default::default()
26201    };
26202
26203    for (_, edit_text) in edits {
26204        let start_offset = text.len();
26205        text.push_str(edit_text);
26206        let end_offset = text.len();
26207
26208        if start_offset < end_offset {
26209            highlights.push((start_offset..end_offset, insertion_highlight_style));
26210        }
26211    }
26212
26213    HighlightedText {
26214        text: text.into(),
26215        highlights,
26216    }
26217}
26218
26219pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
26220    match severity {
26221        lsp::DiagnosticSeverity::ERROR => colors.error,
26222        lsp::DiagnosticSeverity::WARNING => colors.warning,
26223        lsp::DiagnosticSeverity::INFORMATION => colors.info,
26224        lsp::DiagnosticSeverity::HINT => colors.info,
26225        _ => colors.ignored,
26226    }
26227}
26228
26229pub fn styled_runs_for_code_label<'a>(
26230    label: &'a CodeLabel,
26231    syntax_theme: &'a theme::SyntaxTheme,
26232    local_player: &'a theme::PlayerColor,
26233) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
26234    let fade_out = HighlightStyle {
26235        fade_out: Some(0.35),
26236        ..Default::default()
26237    };
26238
26239    let mut prev_end = label.filter_range.end;
26240    label
26241        .runs
26242        .iter()
26243        .enumerate()
26244        .flat_map(move |(ix, (range, highlight_id))| {
26245            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
26246                HighlightStyle {
26247                    color: Some(local_player.cursor),
26248                    ..Default::default()
26249                }
26250            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
26251                HighlightStyle {
26252                    background_color: Some(local_player.selection),
26253                    ..Default::default()
26254                }
26255            } else if let Some(style) = highlight_id.style(syntax_theme) {
26256                style
26257            } else {
26258                return Default::default();
26259            };
26260            let muted_style = style.highlight(fade_out);
26261
26262            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
26263            if range.start >= label.filter_range.end {
26264                if range.start > prev_end {
26265                    runs.push((prev_end..range.start, fade_out));
26266                }
26267                runs.push((range.clone(), muted_style));
26268            } else if range.end <= label.filter_range.end {
26269                runs.push((range.clone(), style));
26270            } else {
26271                runs.push((range.start..label.filter_range.end, style));
26272                runs.push((label.filter_range.end..range.end, muted_style));
26273            }
26274            prev_end = cmp::max(prev_end, range.end);
26275
26276            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
26277                runs.push((prev_end..label.text.len(), fade_out));
26278            }
26279
26280            runs
26281        })
26282}
26283
26284pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
26285    let mut prev_index = 0;
26286    let mut prev_codepoint: Option<char> = None;
26287    text.char_indices()
26288        .chain([(text.len(), '\0')])
26289        .filter_map(move |(index, codepoint)| {
26290            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26291            let is_boundary = index == text.len()
26292                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
26293                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
26294            if is_boundary {
26295                let chunk = &text[prev_index..index];
26296                prev_index = index;
26297                Some(chunk)
26298            } else {
26299                None
26300            }
26301        })
26302}
26303
26304/// Given a string of text immediately before the cursor, iterates over possible
26305/// strings a snippet could match to. More precisely: returns an iterator over
26306/// suffixes of `text` created by splitting at word boundaries (before & after
26307/// every non-word character).
26308///
26309/// Shorter suffixes are returned first.
26310pub(crate) fn snippet_candidate_suffixes(
26311    text: &str,
26312    is_word_char: impl Fn(char) -> bool,
26313) -> impl std::iter::Iterator<Item = &str> {
26314    let mut prev_index = text.len();
26315    let mut prev_codepoint = None;
26316    text.char_indices()
26317        .rev()
26318        .chain([(0, '\0')])
26319        .filter_map(move |(index, codepoint)| {
26320            let prev_index = std::mem::replace(&mut prev_index, index);
26321            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26322            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
26323                None
26324            } else {
26325                let chunk = &text[prev_index..]; // go to end of string
26326                Some(chunk)
26327            }
26328        })
26329}
26330
26331pub trait RangeToAnchorExt: Sized {
26332    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
26333
26334    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
26335        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
26336        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
26337    }
26338}
26339
26340impl<T: ToOffset> RangeToAnchorExt for Range<T> {
26341    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
26342        let start_offset = self.start.to_offset(snapshot);
26343        let end_offset = self.end.to_offset(snapshot);
26344        if start_offset == end_offset {
26345            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
26346        } else {
26347            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
26348        }
26349    }
26350}
26351
26352pub trait RowExt {
26353    fn as_f64(&self) -> f64;
26354
26355    fn next_row(&self) -> Self;
26356
26357    fn previous_row(&self) -> Self;
26358
26359    fn minus(&self, other: Self) -> u32;
26360}
26361
26362impl RowExt for DisplayRow {
26363    fn as_f64(&self) -> f64 {
26364        self.0 as _
26365    }
26366
26367    fn next_row(&self) -> Self {
26368        Self(self.0 + 1)
26369    }
26370
26371    fn previous_row(&self) -> Self {
26372        Self(self.0.saturating_sub(1))
26373    }
26374
26375    fn minus(&self, other: Self) -> u32 {
26376        self.0 - other.0
26377    }
26378}
26379
26380impl RowExt for MultiBufferRow {
26381    fn as_f64(&self) -> f64 {
26382        self.0 as _
26383    }
26384
26385    fn next_row(&self) -> Self {
26386        Self(self.0 + 1)
26387    }
26388
26389    fn previous_row(&self) -> Self {
26390        Self(self.0.saturating_sub(1))
26391    }
26392
26393    fn minus(&self, other: Self) -> u32 {
26394        self.0 - other.0
26395    }
26396}
26397
26398trait RowRangeExt {
26399    type Row;
26400
26401    fn len(&self) -> usize;
26402
26403    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26404}
26405
26406impl RowRangeExt for Range<MultiBufferRow> {
26407    type Row = MultiBufferRow;
26408
26409    fn len(&self) -> usize {
26410        (self.end.0 - self.start.0) as usize
26411    }
26412
26413    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26414        (self.start.0..self.end.0).map(MultiBufferRow)
26415    }
26416}
26417
26418impl RowRangeExt for Range<DisplayRow> {
26419    type Row = DisplayRow;
26420
26421    fn len(&self) -> usize {
26422        (self.end.0 - self.start.0) as usize
26423    }
26424
26425    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26426        (self.start.0..self.end.0).map(DisplayRow)
26427    }
26428}
26429
26430/// If select range has more than one line, we
26431/// just point the cursor to range.start.
26432fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26433    if range.start.row == range.end.row {
26434        range
26435    } else {
26436        range.start..range.start
26437    }
26438}
26439pub struct KillRing(ClipboardItem);
26440impl Global for KillRing {}
26441
26442const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26443
26444enum BreakpointPromptEditAction {
26445    Log,
26446    Condition,
26447    HitCondition,
26448}
26449
26450struct BreakpointPromptEditor {
26451    pub(crate) prompt: Entity<Editor>,
26452    editor: WeakEntity<Editor>,
26453    breakpoint_anchor: Anchor,
26454    breakpoint: Breakpoint,
26455    edit_action: BreakpointPromptEditAction,
26456    block_ids: HashSet<CustomBlockId>,
26457    editor_margins: Arc<Mutex<EditorMargins>>,
26458    _subscriptions: Vec<Subscription>,
26459}
26460
26461impl BreakpointPromptEditor {
26462    const MAX_LINES: u8 = 4;
26463
26464    fn new(
26465        editor: WeakEntity<Editor>,
26466        breakpoint_anchor: Anchor,
26467        breakpoint: Breakpoint,
26468        edit_action: BreakpointPromptEditAction,
26469        window: &mut Window,
26470        cx: &mut Context<Self>,
26471    ) -> Self {
26472        let base_text = match edit_action {
26473            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26474            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26475            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26476        }
26477        .map(|msg| msg.to_string())
26478        .unwrap_or_default();
26479
26480        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26481        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26482
26483        let prompt = cx.new(|cx| {
26484            let mut prompt = Editor::new(
26485                EditorMode::AutoHeight {
26486                    min_lines: 1,
26487                    max_lines: Some(Self::MAX_LINES as usize),
26488                },
26489                buffer,
26490                None,
26491                window,
26492                cx,
26493            );
26494            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26495            prompt.set_show_cursor_when_unfocused(false, cx);
26496            prompt.set_placeholder_text(
26497                match edit_action {
26498                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26499                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26500                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26501                },
26502                window,
26503                cx,
26504            );
26505
26506            prompt
26507        });
26508
26509        Self {
26510            prompt,
26511            editor,
26512            breakpoint_anchor,
26513            breakpoint,
26514            edit_action,
26515            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26516            block_ids: Default::default(),
26517            _subscriptions: vec![],
26518        }
26519    }
26520
26521    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26522        self.block_ids.extend(block_ids)
26523    }
26524
26525    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26526        if let Some(editor) = self.editor.upgrade() {
26527            let message = self
26528                .prompt
26529                .read(cx)
26530                .buffer
26531                .read(cx)
26532                .as_singleton()
26533                .expect("A multi buffer in breakpoint prompt isn't possible")
26534                .read(cx)
26535                .as_rope()
26536                .to_string();
26537
26538            editor.update(cx, |editor, cx| {
26539                editor.edit_breakpoint_at_anchor(
26540                    self.breakpoint_anchor,
26541                    self.breakpoint.clone(),
26542                    match self.edit_action {
26543                        BreakpointPromptEditAction::Log => {
26544                            BreakpointEditAction::EditLogMessage(message.into())
26545                        }
26546                        BreakpointPromptEditAction::Condition => {
26547                            BreakpointEditAction::EditCondition(message.into())
26548                        }
26549                        BreakpointPromptEditAction::HitCondition => {
26550                            BreakpointEditAction::EditHitCondition(message.into())
26551                        }
26552                    },
26553                    cx,
26554                );
26555
26556                editor.remove_blocks(self.block_ids.clone(), None, cx);
26557                cx.focus_self(window);
26558            });
26559        }
26560    }
26561
26562    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26563        self.editor
26564            .update(cx, |editor, cx| {
26565                editor.remove_blocks(self.block_ids.clone(), None, cx);
26566                window.focus(&editor.focus_handle, cx);
26567            })
26568            .log_err();
26569    }
26570
26571    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26572        let settings = ThemeSettings::get_global(cx);
26573        let text_style = TextStyle {
26574            color: if self.prompt.read(cx).read_only(cx) {
26575                cx.theme().colors().text_disabled
26576            } else {
26577                cx.theme().colors().text
26578            },
26579            font_family: settings.buffer_font.family.clone(),
26580            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26581            font_size: settings.buffer_font_size(cx).into(),
26582            font_weight: settings.buffer_font.weight,
26583            line_height: relative(settings.buffer_line_height.value()),
26584            ..Default::default()
26585        };
26586        EditorElement::new(
26587            &self.prompt,
26588            EditorStyle {
26589                background: cx.theme().colors().editor_background,
26590                local_player: cx.theme().players().local(),
26591                text: text_style,
26592                ..Default::default()
26593            },
26594        )
26595    }
26596}
26597
26598impl Render for BreakpointPromptEditor {
26599    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26600        let editor_margins = *self.editor_margins.lock();
26601        let gutter_dimensions = editor_margins.gutter;
26602        h_flex()
26603            .key_context("Editor")
26604            .bg(cx.theme().colors().editor_background)
26605            .border_y_1()
26606            .border_color(cx.theme().status().info_border)
26607            .size_full()
26608            .py(window.line_height() / 2.5)
26609            .on_action(cx.listener(Self::confirm))
26610            .on_action(cx.listener(Self::cancel))
26611            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26612            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26613    }
26614}
26615
26616impl Focusable for BreakpointPromptEditor {
26617    fn focus_handle(&self, cx: &App) -> FocusHandle {
26618        self.prompt.focus_handle(cx)
26619    }
26620}
26621
26622fn all_edits_insertions_or_deletions(
26623    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26624    snapshot: &MultiBufferSnapshot,
26625) -> bool {
26626    let mut all_insertions = true;
26627    let mut all_deletions = true;
26628
26629    for (range, new_text) in edits.iter() {
26630        let range_is_empty = range.to_offset(snapshot).is_empty();
26631        let text_is_empty = new_text.is_empty();
26632
26633        if range_is_empty != text_is_empty {
26634            if range_is_empty {
26635                all_deletions = false;
26636            } else {
26637                all_insertions = false;
26638            }
26639        } else {
26640            return false;
26641        }
26642
26643        if !all_insertions && !all_deletions {
26644            return false;
26645        }
26646    }
26647    all_insertions || all_deletions
26648}
26649
26650struct MissingEditPredictionKeybindingTooltip;
26651
26652impl Render for MissingEditPredictionKeybindingTooltip {
26653    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26654        ui::tooltip_container(cx, |container, cx| {
26655            container
26656                .flex_shrink_0()
26657                .max_w_80()
26658                .min_h(rems_from_px(124.))
26659                .justify_between()
26660                .child(
26661                    v_flex()
26662                        .flex_1()
26663                        .text_ui_sm(cx)
26664                        .child(Label::new("Conflict with Accept Keybinding"))
26665                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26666                )
26667                .child(
26668                    h_flex()
26669                        .pb_1()
26670                        .gap_1()
26671                        .items_end()
26672                        .w_full()
26673                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26674                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26675                        }))
26676                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26677                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26678                        })),
26679                )
26680        })
26681    }
26682}
26683
26684#[derive(Debug, Clone, Copy, PartialEq)]
26685pub struct LineHighlight {
26686    pub background: Background,
26687    pub border: Option<gpui::Hsla>,
26688    pub include_gutter: bool,
26689    pub type_id: Option<TypeId>,
26690}
26691
26692struct LineManipulationResult {
26693    pub new_text: String,
26694    pub line_count_before: usize,
26695    pub line_count_after: usize,
26696}
26697
26698fn render_diff_hunk_controls(
26699    row: u32,
26700    status: &DiffHunkStatus,
26701    hunk_range: Range<Anchor>,
26702    is_created_file: bool,
26703    line_height: Pixels,
26704    editor: &Entity<Editor>,
26705    _window: &mut Window,
26706    cx: &mut App,
26707) -> AnyElement {
26708    h_flex()
26709        .h(line_height)
26710        .mr_1()
26711        .gap_1()
26712        .px_0p5()
26713        .pb_1()
26714        .border_x_1()
26715        .border_b_1()
26716        .border_color(cx.theme().colors().border_variant)
26717        .rounded_b_lg()
26718        .bg(cx.theme().colors().editor_background)
26719        .gap_1()
26720        .block_mouse_except_scroll()
26721        .shadow_md()
26722        .child(if status.has_secondary_hunk() {
26723            Button::new(("stage", row as u64), "Stage")
26724                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26725                .tooltip({
26726                    let focus_handle = editor.focus_handle(cx);
26727                    move |_window, cx| {
26728                        Tooltip::for_action_in(
26729                            "Stage Hunk",
26730                            &::git::ToggleStaged,
26731                            &focus_handle,
26732                            cx,
26733                        )
26734                    }
26735                })
26736                .on_click({
26737                    let editor = editor.clone();
26738                    move |_event, _window, cx| {
26739                        editor.update(cx, |editor, cx| {
26740                            editor.stage_or_unstage_diff_hunks(
26741                                true,
26742                                vec![hunk_range.start..hunk_range.start],
26743                                cx,
26744                            );
26745                        });
26746                    }
26747                })
26748        } else {
26749            Button::new(("unstage", row as u64), "Unstage")
26750                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26751                .tooltip({
26752                    let focus_handle = editor.focus_handle(cx);
26753                    move |_window, cx| {
26754                        Tooltip::for_action_in(
26755                            "Unstage Hunk",
26756                            &::git::ToggleStaged,
26757                            &focus_handle,
26758                            cx,
26759                        )
26760                    }
26761                })
26762                .on_click({
26763                    let editor = editor.clone();
26764                    move |_event, _window, cx| {
26765                        editor.update(cx, |editor, cx| {
26766                            editor.stage_or_unstage_diff_hunks(
26767                                false,
26768                                vec![hunk_range.start..hunk_range.start],
26769                                cx,
26770                            );
26771                        });
26772                    }
26773                })
26774        })
26775        .child(
26776            Button::new(("restore", row as u64), "Restore")
26777                .tooltip({
26778                    let focus_handle = editor.focus_handle(cx);
26779                    move |_window, cx| {
26780                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26781                    }
26782                })
26783                .on_click({
26784                    let editor = editor.clone();
26785                    move |_event, window, cx| {
26786                        editor.update(cx, |editor, cx| {
26787                            let snapshot = editor.snapshot(window, cx);
26788                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26789                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26790                        });
26791                    }
26792                })
26793                .disabled(is_created_file),
26794        )
26795        .when(
26796            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26797            |el| {
26798                el.child(
26799                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26800                        .shape(IconButtonShape::Square)
26801                        .icon_size(IconSize::Small)
26802                        // .disabled(!has_multiple_hunks)
26803                        .tooltip({
26804                            let focus_handle = editor.focus_handle(cx);
26805                            move |_window, cx| {
26806                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26807                            }
26808                        })
26809                        .on_click({
26810                            let editor = editor.clone();
26811                            move |_event, window, cx| {
26812                                editor.update(cx, |editor, cx| {
26813                                    let snapshot = editor.snapshot(window, cx);
26814                                    let position =
26815                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26816                                    editor.go_to_hunk_before_or_after_position(
26817                                        &snapshot,
26818                                        position,
26819                                        Direction::Next,
26820                                        window,
26821                                        cx,
26822                                    );
26823                                    editor.expand_selected_diff_hunks(cx);
26824                                });
26825                            }
26826                        }),
26827                )
26828                .child(
26829                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26830                        .shape(IconButtonShape::Square)
26831                        .icon_size(IconSize::Small)
26832                        // .disabled(!has_multiple_hunks)
26833                        .tooltip({
26834                            let focus_handle = editor.focus_handle(cx);
26835                            move |_window, cx| {
26836                                Tooltip::for_action_in(
26837                                    "Previous Hunk",
26838                                    &GoToPreviousHunk,
26839                                    &focus_handle,
26840                                    cx,
26841                                )
26842                            }
26843                        })
26844                        .on_click({
26845                            let editor = editor.clone();
26846                            move |_event, window, cx| {
26847                                editor.update(cx, |editor, cx| {
26848                                    let snapshot = editor.snapshot(window, cx);
26849                                    let point =
26850                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26851                                    editor.go_to_hunk_before_or_after_position(
26852                                        &snapshot,
26853                                        point,
26854                                        Direction::Prev,
26855                                        window,
26856                                        cx,
26857                                    );
26858                                    editor.expand_selected_diff_hunks(cx);
26859                                });
26860                            }
26861                        }),
26862                )
26863            },
26864        )
26865        .into_any_element()
26866}
26867
26868pub fn multibuffer_context_lines(cx: &App) -> u32 {
26869    EditorSettings::try_get(cx)
26870        .map(|settings| settings.excerpt_context_lines)
26871        .unwrap_or(2)
26872        .min(32)
26873}