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    debounced_selection_highlight_complete: bool,
 1120    document_highlights_task: Option<Task<()>>,
 1121    linked_editing_range_task: Option<Task<Option<()>>>,
 1122    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1123    pending_rename: Option<RenameState>,
 1124    searchable: bool,
 1125    cursor_shape: CursorShape,
 1126    /// Whether the cursor is offset one character to the left when something is
 1127    /// selected (needed for vim visual mode)
 1128    cursor_offset_on_selection: bool,
 1129    current_line_highlight: Option<CurrentLineHighlight>,
 1130    pub collapse_matches: bool,
 1131    autoindent_mode: Option<AutoindentMode>,
 1132    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1133    input_enabled: bool,
 1134    use_modal_editing: bool,
 1135    read_only: bool,
 1136    leader_id: Option<CollaboratorId>,
 1137    remote_id: Option<ViewId>,
 1138    pub hover_state: HoverState,
 1139    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1140    prev_pressure_stage: Option<PressureStage>,
 1141    gutter_hovered: bool,
 1142    hovered_link_state: Option<HoveredLinkState>,
 1143    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1144    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1145    active_edit_prediction: Option<EditPredictionState>,
 1146    /// Used to prevent flickering as the user types while the menu is open
 1147    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1148    edit_prediction_settings: EditPredictionSettings,
 1149    edit_predictions_hidden_for_vim_mode: bool,
 1150    show_edit_predictions_override: Option<bool>,
 1151    show_completions_on_input_override: Option<bool>,
 1152    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1153    edit_prediction_preview: EditPredictionPreview,
 1154    edit_prediction_indent_conflict: bool,
 1155    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1156    next_inlay_id: usize,
 1157    next_color_inlay_id: usize,
 1158    _subscriptions: Vec<Subscription>,
 1159    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1160    gutter_dimensions: GutterDimensions,
 1161    style: Option<EditorStyle>,
 1162    text_style_refinement: Option<TextStyleRefinement>,
 1163    next_editor_action_id: EditorActionId,
 1164    editor_actions: Rc<
 1165        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1166    >,
 1167    use_autoclose: bool,
 1168    use_auto_surround: bool,
 1169    auto_replace_emoji_shortcode: bool,
 1170    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1171    show_git_blame_gutter: bool,
 1172    show_git_blame_inline: bool,
 1173    show_git_blame_inline_delay_task: Option<Task<()>>,
 1174    git_blame_inline_enabled: bool,
 1175    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1176    buffer_serialization: Option<BufferSerialization>,
 1177    show_selection_menu: Option<bool>,
 1178    blame: Option<Entity<GitBlame>>,
 1179    blame_subscription: Option<Subscription>,
 1180    custom_context_menu: Option<
 1181        Box<
 1182            dyn 'static
 1183                + Fn(
 1184                    &mut Self,
 1185                    DisplayPoint,
 1186                    &mut Window,
 1187                    &mut Context<Self>,
 1188                ) -> Option<Entity<ui::ContextMenu>>,
 1189        >,
 1190    >,
 1191    last_bounds: Option<Bounds<Pixels>>,
 1192    last_position_map: Option<Rc<PositionMap>>,
 1193    expect_bounds_change: Option<Bounds<Pixels>>,
 1194    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1195    tasks_update_task: Option<Task<()>>,
 1196    breakpoint_store: Option<Entity<BreakpointStore>>,
 1197    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1198    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1199    hovered_diff_hunk_row: Option<DisplayRow>,
 1200    pull_diagnostics_task: Task<()>,
 1201    pull_diagnostics_background_task: Task<()>,
 1202    in_project_search: bool,
 1203    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1204    breadcrumb_header: Option<String>,
 1205    focused_block: Option<FocusedBlock>,
 1206    next_scroll_position: NextScrollCursorCenterTopBottom,
 1207    addons: HashMap<TypeId, Box<dyn Addon>>,
 1208    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1209    load_diff_task: Option<Shared<Task<()>>>,
 1210    /// Whether we are temporarily displaying a diff other than git's
 1211    temporary_diff_override: bool,
 1212    selection_mark_mode: bool,
 1213    toggle_fold_multiple_buffers: Task<()>,
 1214    _scroll_cursor_center_top_bottom_task: Task<()>,
 1215    serialize_selections: Task<()>,
 1216    serialize_folds: Task<()>,
 1217    mouse_cursor_hidden: bool,
 1218    minimap: Option<Entity<Self>>,
 1219    hide_mouse_mode: HideMouseMode,
 1220    pub change_list: ChangeList,
 1221    inline_value_cache: InlineValueCache,
 1222    number_deleted_lines: bool,
 1223
 1224    selection_drag_state: SelectionDragState,
 1225    colors: Option<LspColorData>,
 1226    post_scroll_update: Task<()>,
 1227    refresh_colors_task: Task<()>,
 1228    inlay_hints: Option<LspInlayHintData>,
 1229    folding_newlines: Task<()>,
 1230    select_next_is_case_sensitive: Option<bool>,
 1231    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1232    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1233    accent_data: Option<AccentData>,
 1234    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1235}
 1236
 1237#[derive(Debug, PartialEq)]
 1238struct AccentData {
 1239    colors: AccentColors,
 1240    overrides: Vec<SharedString>,
 1241}
 1242
 1243fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1244    if debounce_ms > 0 {
 1245        Some(Duration::from_millis(debounce_ms))
 1246    } else {
 1247        None
 1248    }
 1249}
 1250
 1251#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1252enum NextScrollCursorCenterTopBottom {
 1253    #[default]
 1254    Center,
 1255    Top,
 1256    Bottom,
 1257}
 1258
 1259impl NextScrollCursorCenterTopBottom {
 1260    fn next(&self) -> Self {
 1261        match self {
 1262            Self::Center => Self::Top,
 1263            Self::Top => Self::Bottom,
 1264            Self::Bottom => Self::Center,
 1265        }
 1266    }
 1267}
 1268
 1269#[derive(Clone)]
 1270pub struct EditorSnapshot {
 1271    pub mode: EditorMode,
 1272    show_gutter: bool,
 1273    offset_content: bool,
 1274    show_line_numbers: Option<bool>,
 1275    number_deleted_lines: bool,
 1276    show_git_diff_gutter: Option<bool>,
 1277    show_code_actions: Option<bool>,
 1278    show_runnables: Option<bool>,
 1279    show_breakpoints: Option<bool>,
 1280    git_blame_gutter_max_author_length: Option<usize>,
 1281    pub display_snapshot: DisplaySnapshot,
 1282    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1283    is_focused: bool,
 1284    scroll_anchor: ScrollAnchor,
 1285    ongoing_scroll: OngoingScroll,
 1286    current_line_highlight: CurrentLineHighlight,
 1287    gutter_hovered: bool,
 1288}
 1289
 1290#[derive(Default, Debug, Clone, Copy)]
 1291pub struct GutterDimensions {
 1292    pub left_padding: Pixels,
 1293    pub right_padding: Pixels,
 1294    pub width: Pixels,
 1295    pub margin: Pixels,
 1296    pub git_blame_entries_width: Option<Pixels>,
 1297}
 1298
 1299impl GutterDimensions {
 1300    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1301        Self {
 1302            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1303            ..Default::default()
 1304        }
 1305    }
 1306
 1307    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1308        -cx.text_system().descent(font_id, font_size)
 1309    }
 1310    /// The full width of the space taken up by the gutter.
 1311    pub fn full_width(&self) -> Pixels {
 1312        self.margin + self.width
 1313    }
 1314
 1315    /// The width of the space reserved for the fold indicators,
 1316    /// use alongside 'justify_end' and `gutter_width` to
 1317    /// right align content with the line numbers
 1318    pub fn fold_area_width(&self) -> Pixels {
 1319        self.margin + self.right_padding
 1320    }
 1321}
 1322
 1323struct CharacterDimensions {
 1324    em_width: Pixels,
 1325    em_advance: Pixels,
 1326    line_height: Pixels,
 1327}
 1328
 1329#[derive(Debug)]
 1330pub struct RemoteSelection {
 1331    pub replica_id: ReplicaId,
 1332    pub selection: Selection<Anchor>,
 1333    pub cursor_shape: CursorShape,
 1334    pub collaborator_id: CollaboratorId,
 1335    pub line_mode: bool,
 1336    pub user_name: Option<SharedString>,
 1337    pub color: PlayerColor,
 1338}
 1339
 1340#[derive(Clone, Debug)]
 1341struct SelectionHistoryEntry {
 1342    selections: Arc<[Selection<Anchor>]>,
 1343    select_next_state: Option<SelectNextState>,
 1344    select_prev_state: Option<SelectNextState>,
 1345    add_selections_state: Option<AddSelectionsState>,
 1346}
 1347
 1348#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1349enum SelectionHistoryMode {
 1350    #[default]
 1351    Normal,
 1352    Undoing,
 1353    Redoing,
 1354    Skipping,
 1355}
 1356
 1357#[derive(Clone, PartialEq, Eq, Hash)]
 1358struct HoveredCursor {
 1359    replica_id: ReplicaId,
 1360    selection_id: usize,
 1361}
 1362
 1363#[derive(Debug)]
 1364/// SelectionEffects controls the side-effects of updating the selection.
 1365///
 1366/// The default behaviour does "what you mostly want":
 1367/// - it pushes to the nav history if the cursor moved by >10 lines
 1368/// - it re-triggers completion requests
 1369/// - it scrolls to fit
 1370///
 1371/// You might want to modify these behaviours. For example when doing a "jump"
 1372/// like go to definition, we always want to add to nav history; but when scrolling
 1373/// in vim mode we never do.
 1374///
 1375/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1376/// move.
 1377#[derive(Clone)]
 1378pub struct SelectionEffects {
 1379    nav_history: Option<bool>,
 1380    completions: bool,
 1381    scroll: Option<Autoscroll>,
 1382}
 1383
 1384impl Default for SelectionEffects {
 1385    fn default() -> Self {
 1386        Self {
 1387            nav_history: None,
 1388            completions: true,
 1389            scroll: Some(Autoscroll::fit()),
 1390        }
 1391    }
 1392}
 1393impl SelectionEffects {
 1394    pub fn scroll(scroll: Autoscroll) -> Self {
 1395        Self {
 1396            scroll: Some(scroll),
 1397            ..Default::default()
 1398        }
 1399    }
 1400
 1401    pub fn no_scroll() -> Self {
 1402        Self {
 1403            scroll: None,
 1404            ..Default::default()
 1405        }
 1406    }
 1407
 1408    pub fn completions(self, completions: bool) -> Self {
 1409        Self {
 1410            completions,
 1411            ..self
 1412        }
 1413    }
 1414
 1415    pub fn nav_history(self, nav_history: bool) -> Self {
 1416        Self {
 1417            nav_history: Some(nav_history),
 1418            ..self
 1419        }
 1420    }
 1421}
 1422
 1423struct DeferredSelectionEffectsState {
 1424    changed: bool,
 1425    effects: SelectionEffects,
 1426    old_cursor_position: Anchor,
 1427    history_entry: SelectionHistoryEntry,
 1428}
 1429
 1430#[derive(Default)]
 1431struct SelectionHistory {
 1432    #[allow(clippy::type_complexity)]
 1433    selections_by_transaction:
 1434        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1435    mode: SelectionHistoryMode,
 1436    undo_stack: VecDeque<SelectionHistoryEntry>,
 1437    redo_stack: VecDeque<SelectionHistoryEntry>,
 1438}
 1439
 1440impl SelectionHistory {
 1441    #[track_caller]
 1442    fn insert_transaction(
 1443        &mut self,
 1444        transaction_id: TransactionId,
 1445        selections: Arc<[Selection<Anchor>]>,
 1446    ) {
 1447        if selections.is_empty() {
 1448            log::error!(
 1449                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1450                std::panic::Location::caller()
 1451            );
 1452            return;
 1453        }
 1454        self.selections_by_transaction
 1455            .insert(transaction_id, (selections, None));
 1456    }
 1457
 1458    #[allow(clippy::type_complexity)]
 1459    fn transaction(
 1460        &self,
 1461        transaction_id: TransactionId,
 1462    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1463        self.selections_by_transaction.get(&transaction_id)
 1464    }
 1465
 1466    #[allow(clippy::type_complexity)]
 1467    fn transaction_mut(
 1468        &mut self,
 1469        transaction_id: TransactionId,
 1470    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1471        self.selections_by_transaction.get_mut(&transaction_id)
 1472    }
 1473
 1474    fn push(&mut self, entry: SelectionHistoryEntry) {
 1475        if !entry.selections.is_empty() {
 1476            match self.mode {
 1477                SelectionHistoryMode::Normal => {
 1478                    self.push_undo(entry);
 1479                    self.redo_stack.clear();
 1480                }
 1481                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1482                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1483                SelectionHistoryMode::Skipping => {}
 1484            }
 1485        }
 1486    }
 1487
 1488    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1489        if self
 1490            .undo_stack
 1491            .back()
 1492            .is_none_or(|e| e.selections != entry.selections)
 1493        {
 1494            self.undo_stack.push_back(entry);
 1495            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1496                self.undo_stack.pop_front();
 1497            }
 1498        }
 1499    }
 1500
 1501    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1502        if self
 1503            .redo_stack
 1504            .back()
 1505            .is_none_or(|e| e.selections != entry.selections)
 1506        {
 1507            self.redo_stack.push_back(entry);
 1508            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1509                self.redo_stack.pop_front();
 1510            }
 1511        }
 1512    }
 1513}
 1514
 1515#[derive(Clone, Copy)]
 1516pub struct RowHighlightOptions {
 1517    pub autoscroll: bool,
 1518    pub include_gutter: bool,
 1519}
 1520
 1521impl Default for RowHighlightOptions {
 1522    fn default() -> Self {
 1523        Self {
 1524            autoscroll: Default::default(),
 1525            include_gutter: true,
 1526        }
 1527    }
 1528}
 1529
 1530struct RowHighlight {
 1531    index: usize,
 1532    range: Range<Anchor>,
 1533    color: Hsla,
 1534    options: RowHighlightOptions,
 1535    type_id: TypeId,
 1536}
 1537
 1538#[derive(Clone, Debug)]
 1539struct AddSelectionsState {
 1540    groups: Vec<AddSelectionsGroup>,
 1541}
 1542
 1543#[derive(Clone, Debug)]
 1544struct AddSelectionsGroup {
 1545    above: bool,
 1546    stack: Vec<usize>,
 1547}
 1548
 1549#[derive(Clone)]
 1550struct SelectNextState {
 1551    query: AhoCorasick,
 1552    wordwise: bool,
 1553    done: bool,
 1554}
 1555
 1556impl std::fmt::Debug for SelectNextState {
 1557    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1558        f.debug_struct(std::any::type_name::<Self>())
 1559            .field("wordwise", &self.wordwise)
 1560            .field("done", &self.done)
 1561            .finish()
 1562    }
 1563}
 1564
 1565#[derive(Debug)]
 1566struct AutocloseRegion {
 1567    selection_id: usize,
 1568    range: Range<Anchor>,
 1569    pair: BracketPair,
 1570}
 1571
 1572#[derive(Debug)]
 1573struct SnippetState {
 1574    ranges: Vec<Vec<Range<Anchor>>>,
 1575    active_index: usize,
 1576    choices: Vec<Option<Vec<String>>>,
 1577}
 1578
 1579#[doc(hidden)]
 1580pub struct RenameState {
 1581    pub range: Range<Anchor>,
 1582    pub old_name: Arc<str>,
 1583    pub editor: Entity<Editor>,
 1584    block_id: CustomBlockId,
 1585}
 1586
 1587struct InvalidationStack<T>(Vec<T>);
 1588
 1589struct RegisteredEditPredictionDelegate {
 1590    provider: Arc<dyn EditPredictionDelegateHandle>,
 1591    _subscription: Subscription,
 1592}
 1593
 1594#[derive(Debug, PartialEq, Eq)]
 1595pub struct ActiveDiagnosticGroup {
 1596    pub active_range: Range<Anchor>,
 1597    pub active_message: String,
 1598    pub group_id: usize,
 1599    pub blocks: HashSet<CustomBlockId>,
 1600}
 1601
 1602#[derive(Debug, PartialEq, Eq)]
 1603
 1604pub(crate) enum ActiveDiagnostic {
 1605    None,
 1606    All,
 1607    Group(ActiveDiagnosticGroup),
 1608}
 1609
 1610#[derive(Serialize, Deserialize, Clone, Debug)]
 1611pub struct ClipboardSelection {
 1612    /// The number of bytes in this selection.
 1613    pub len: usize,
 1614    /// Whether this was a full-line selection.
 1615    pub is_entire_line: bool,
 1616    /// The indentation of the first line when this content was originally copied.
 1617    pub first_line_indent: u32,
 1618    #[serde(default)]
 1619    pub file_path: Option<PathBuf>,
 1620    #[serde(default)]
 1621    pub line_range: Option<RangeInclusive<u32>>,
 1622}
 1623
 1624impl ClipboardSelection {
 1625    pub fn for_buffer(
 1626        len: usize,
 1627        is_entire_line: bool,
 1628        range: Range<Point>,
 1629        buffer: &MultiBufferSnapshot,
 1630        project: Option<&Entity<Project>>,
 1631        cx: &App,
 1632    ) -> Self {
 1633        let first_line_indent = buffer
 1634            .indent_size_for_line(MultiBufferRow(range.start.row))
 1635            .len;
 1636
 1637        let file_path = util::maybe!({
 1638            let project = project?.read(cx);
 1639            let file = buffer.file_at(range.start)?;
 1640            let project_path = ProjectPath {
 1641                worktree_id: file.worktree_id(cx),
 1642                path: file.path().clone(),
 1643            };
 1644            project.absolute_path(&project_path, cx)
 1645        });
 1646
 1647        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1648
 1649        Self {
 1650            len,
 1651            is_entire_line,
 1652            first_line_indent,
 1653            file_path,
 1654            line_range,
 1655        }
 1656    }
 1657}
 1658
 1659// selections, scroll behavior, was newest selection reversed
 1660type SelectSyntaxNodeHistoryState = (
 1661    Box<[Selection<MultiBufferOffset>]>,
 1662    SelectSyntaxNodeScrollBehavior,
 1663    bool,
 1664);
 1665
 1666#[derive(Default)]
 1667struct SelectSyntaxNodeHistory {
 1668    stack: Vec<SelectSyntaxNodeHistoryState>,
 1669    // disable temporarily to allow changing selections without losing the stack
 1670    pub disable_clearing: bool,
 1671}
 1672
 1673impl SelectSyntaxNodeHistory {
 1674    pub fn try_clear(&mut self) {
 1675        if !self.disable_clearing {
 1676            self.stack.clear();
 1677        }
 1678    }
 1679
 1680    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1681        self.stack.push(selection);
 1682    }
 1683
 1684    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1685        self.stack.pop()
 1686    }
 1687}
 1688
 1689enum SelectSyntaxNodeScrollBehavior {
 1690    CursorTop,
 1691    FitSelection,
 1692    CursorBottom,
 1693}
 1694
 1695#[derive(Debug)]
 1696pub(crate) struct NavigationData {
 1697    cursor_anchor: Anchor,
 1698    cursor_position: Point,
 1699    scroll_anchor: ScrollAnchor,
 1700    scroll_top_row: u32,
 1701}
 1702
 1703#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1704pub enum GotoDefinitionKind {
 1705    Symbol,
 1706    Declaration,
 1707    Type,
 1708    Implementation,
 1709}
 1710
 1711pub enum FormatTarget {
 1712    Buffers(HashSet<Entity<Buffer>>),
 1713    Ranges(Vec<Range<MultiBufferPoint>>),
 1714}
 1715
 1716pub(crate) struct FocusedBlock {
 1717    id: BlockId,
 1718    focus_handle: WeakFocusHandle,
 1719}
 1720
 1721#[derive(Clone, Debug)]
 1722enum JumpData {
 1723    MultiBufferRow {
 1724        row: MultiBufferRow,
 1725        line_offset_from_top: u32,
 1726    },
 1727    MultiBufferPoint {
 1728        excerpt_id: ExcerptId,
 1729        position: Point,
 1730        anchor: text::Anchor,
 1731        line_offset_from_top: u32,
 1732    },
 1733}
 1734
 1735pub enum MultibufferSelectionMode {
 1736    First,
 1737    All,
 1738}
 1739
 1740#[derive(Clone, Copy, Debug, Default)]
 1741pub struct RewrapOptions {
 1742    pub override_language_settings: bool,
 1743    pub preserve_existing_whitespace: bool,
 1744}
 1745
 1746impl Editor {
 1747    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1748        let buffer = cx.new(|cx| Buffer::local("", cx));
 1749        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1750        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1751    }
 1752
 1753    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1754        let buffer = cx.new(|cx| Buffer::local("", cx));
 1755        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1756        Self::new(EditorMode::full(), buffer, None, window, cx)
 1757    }
 1758
 1759    pub fn auto_height(
 1760        min_lines: usize,
 1761        max_lines: usize,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        let buffer = cx.new(|cx| Buffer::local("", cx));
 1766        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1767        Self::new(
 1768            EditorMode::AutoHeight {
 1769                min_lines,
 1770                max_lines: Some(max_lines),
 1771            },
 1772            buffer,
 1773            None,
 1774            window,
 1775            cx,
 1776        )
 1777    }
 1778
 1779    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1780    /// The editor grows as tall as needed to fit its content.
 1781    pub fn auto_height_unbounded(
 1782        min_lines: usize,
 1783        window: &mut Window,
 1784        cx: &mut Context<Self>,
 1785    ) -> Self {
 1786        let buffer = cx.new(|cx| Buffer::local("", cx));
 1787        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1788        Self::new(
 1789            EditorMode::AutoHeight {
 1790                min_lines,
 1791                max_lines: None,
 1792            },
 1793            buffer,
 1794            None,
 1795            window,
 1796            cx,
 1797        )
 1798    }
 1799
 1800    pub fn for_buffer(
 1801        buffer: Entity<Buffer>,
 1802        project: Option<Entity<Project>>,
 1803        window: &mut Window,
 1804        cx: &mut Context<Self>,
 1805    ) -> Self {
 1806        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1807        Self::new(EditorMode::full(), buffer, project, window, cx)
 1808    }
 1809
 1810    pub fn for_multibuffer(
 1811        buffer: Entity<MultiBuffer>,
 1812        project: Option<Entity<Project>>,
 1813        window: &mut Window,
 1814        cx: &mut Context<Self>,
 1815    ) -> Self {
 1816        Self::new(EditorMode::full(), buffer, project, window, cx)
 1817    }
 1818
 1819    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1820        let mut clone = Self::new(
 1821            self.mode.clone(),
 1822            self.buffer.clone(),
 1823            self.project.clone(),
 1824            window,
 1825            cx,
 1826        );
 1827        self.display_map.update(cx, |display_map, cx| {
 1828            let snapshot = display_map.snapshot(cx);
 1829            clone.display_map.update(cx, |display_map, cx| {
 1830                display_map.set_state(&snapshot, cx);
 1831            });
 1832        });
 1833        clone.folds_did_change(cx);
 1834        clone.selections.clone_state(&self.selections);
 1835        clone.scroll_manager.clone_state(&self.scroll_manager);
 1836        clone.searchable = self.searchable;
 1837        clone.read_only = self.read_only;
 1838        clone
 1839    }
 1840
 1841    pub fn new(
 1842        mode: EditorMode,
 1843        buffer: Entity<MultiBuffer>,
 1844        project: Option<Entity<Project>>,
 1845        window: &mut Window,
 1846        cx: &mut Context<Self>,
 1847    ) -> Self {
 1848        Editor::new_internal(mode, buffer, project, None, window, cx)
 1849    }
 1850
 1851    pub fn sticky_headers(
 1852        &self,
 1853        style: &EditorStyle,
 1854        cx: &App,
 1855    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1856        let multi_buffer = self.buffer().read(cx);
 1857        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1858        let multi_buffer_visible_start = self
 1859            .scroll_manager
 1860            .anchor()
 1861            .anchor
 1862            .to_point(&multi_buffer_snapshot);
 1863        let max_row = multi_buffer_snapshot.max_point().row;
 1864
 1865        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1866        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1867
 1868        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1869            let outline_items = buffer
 1870                .outline_items_containing(
 1871                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1872                    true,
 1873                    Some(style.syntax.as_ref()),
 1874                )
 1875                .into_iter()
 1876                .map(|outline_item| OutlineItem {
 1877                    depth: outline_item.depth,
 1878                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1879                    source_range_for_text: Anchor::range_in_buffer(
 1880                        *excerpt_id,
 1881                        outline_item.source_range_for_text,
 1882                    ),
 1883                    text: outline_item.text,
 1884                    highlight_ranges: outline_item.highlight_ranges,
 1885                    name_ranges: outline_item.name_ranges,
 1886                    body_range: outline_item
 1887                        .body_range
 1888                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1889                    annotation_range: outline_item
 1890                        .annotation_range
 1891                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1892                });
 1893            return Some(outline_items.collect());
 1894        }
 1895
 1896        None
 1897    }
 1898
 1899    fn new_internal(
 1900        mode: EditorMode,
 1901        multi_buffer: Entity<MultiBuffer>,
 1902        project: Option<Entity<Project>>,
 1903        display_map: Option<Entity<DisplayMap>>,
 1904        window: &mut Window,
 1905        cx: &mut Context<Self>,
 1906    ) -> Self {
 1907        debug_assert!(
 1908            display_map.is_none() || mode.is_minimap(),
 1909            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1910        );
 1911
 1912        let full_mode = mode.is_full();
 1913        let is_minimap = mode.is_minimap();
 1914        let diagnostics_max_severity = if full_mode {
 1915            EditorSettings::get_global(cx)
 1916                .diagnostics_max_severity
 1917                .unwrap_or(DiagnosticSeverity::Hint)
 1918        } else {
 1919            DiagnosticSeverity::Off
 1920        };
 1921        let style = window.text_style();
 1922        let font_size = style.font_size.to_pixels(window.rem_size());
 1923        let editor = cx.entity().downgrade();
 1924        let fold_placeholder = FoldPlaceholder {
 1925            constrain_width: false,
 1926            render: Arc::new(move |fold_id, fold_range, cx| {
 1927                let editor = editor.clone();
 1928                div()
 1929                    .id(fold_id)
 1930                    .bg(cx.theme().colors().ghost_element_background)
 1931                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1932                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1933                    .rounded_xs()
 1934                    .size_full()
 1935                    .cursor_pointer()
 1936                    .child("")
 1937                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1938                    .on_click(move |_, _window, cx| {
 1939                        editor
 1940                            .update(cx, |editor, cx| {
 1941                                editor.unfold_ranges(
 1942                                    &[fold_range.start..fold_range.end],
 1943                                    true,
 1944                                    false,
 1945                                    cx,
 1946                                );
 1947                                cx.stop_propagation();
 1948                            })
 1949                            .ok();
 1950                    })
 1951                    .into_any()
 1952            }),
 1953            merge_adjacent: true,
 1954            ..FoldPlaceholder::default()
 1955        };
 1956        let display_map = display_map.unwrap_or_else(|| {
 1957            cx.new(|cx| {
 1958                DisplayMap::new(
 1959                    multi_buffer.clone(),
 1960                    style.font(),
 1961                    font_size,
 1962                    None,
 1963                    FILE_HEADER_HEIGHT,
 1964                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1965                    fold_placeholder,
 1966                    diagnostics_max_severity,
 1967                    cx,
 1968                )
 1969            })
 1970        });
 1971
 1972        let selections = SelectionsCollection::new();
 1973
 1974        let blink_manager = cx.new(|cx| {
 1975            let mut blink_manager = BlinkManager::new(
 1976                CURSOR_BLINK_INTERVAL,
 1977                |cx| EditorSettings::get_global(cx).cursor_blink,
 1978                cx,
 1979            );
 1980            if is_minimap {
 1981                blink_manager.disable(cx);
 1982            }
 1983            blink_manager
 1984        });
 1985
 1986        let soft_wrap_mode_override =
 1987            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1988
 1989        let mut project_subscriptions = Vec::new();
 1990        if full_mode && let Some(project) = project.as_ref() {
 1991            project_subscriptions.push(cx.subscribe_in(
 1992                project,
 1993                window,
 1994                |editor, _, event, window, cx| match event {
 1995                    project::Event::RefreshCodeLens => {
 1996                        // we always query lens with actions, without storing them, always refreshing them
 1997                    }
 1998                    project::Event::RefreshInlayHints {
 1999                        server_id,
 2000                        request_id,
 2001                    } => {
 2002                        editor.refresh_inlay_hints(
 2003                            InlayHintRefreshReason::RefreshRequested {
 2004                                server_id: *server_id,
 2005                                request_id: *request_id,
 2006                            },
 2007                            cx,
 2008                        );
 2009                    }
 2010                    project::Event::LanguageServerRemoved(..) => {
 2011                        if editor.tasks_update_task.is_none() {
 2012                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2013                        }
 2014                        editor.registered_buffers.clear();
 2015                        editor.register_visible_buffers(cx);
 2016                    }
 2017                    project::Event::LanguageServerAdded(..) => {
 2018                        if editor.tasks_update_task.is_none() {
 2019                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2020                        }
 2021                    }
 2022                    project::Event::SnippetEdit(id, snippet_edits) => {
 2023                        // todo(lw): Non singletons
 2024                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2025                            let snapshot = buffer.read(cx).snapshot();
 2026                            let focus_handle = editor.focus_handle(cx);
 2027                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2028                                for (range, snippet) in snippet_edits {
 2029                                    let buffer_range =
 2030                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2031                                    editor
 2032                                        .insert_snippet(
 2033                                            &[MultiBufferOffset(buffer_range.start)
 2034                                                ..MultiBufferOffset(buffer_range.end)],
 2035                                            snippet.clone(),
 2036                                            window,
 2037                                            cx,
 2038                                        )
 2039                                        .ok();
 2040                                }
 2041                            }
 2042                        }
 2043                    }
 2044                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2045                        let buffer_id = *buffer_id;
 2046                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2047                            editor.register_buffer(buffer_id, cx);
 2048                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2049                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2050                            refresh_linked_ranges(editor, window, cx);
 2051                            editor.refresh_code_actions(window, cx);
 2052                            editor.refresh_document_highlights(cx);
 2053                        }
 2054                    }
 2055
 2056                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2057                        let Some(workspace) = editor.workspace() else {
 2058                            return;
 2059                        };
 2060                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2061                        else {
 2062                            return;
 2063                        };
 2064
 2065                        if active_editor.entity_id() == cx.entity_id() {
 2066                            let entity_id = cx.entity_id();
 2067                            workspace.update(cx, |this, cx| {
 2068                                this.panes_mut()
 2069                                    .iter_mut()
 2070                                    .filter(|pane| pane.entity_id() != entity_id)
 2071                                    .for_each(|p| {
 2072                                        p.update(cx, |pane, _| {
 2073                                            pane.nav_history_mut().rename_item(
 2074                                                entity_id,
 2075                                                project_path.clone(),
 2076                                                abs_path.clone().into(),
 2077                                            );
 2078                                        })
 2079                                    });
 2080                            });
 2081
 2082                            Self::open_transaction_for_hidden_buffers(
 2083                                workspace,
 2084                                transaction.clone(),
 2085                                "Rename".to_string(),
 2086                                window,
 2087                                cx,
 2088                            );
 2089                        }
 2090                    }
 2091
 2092                    project::Event::WorkspaceEditApplied(transaction) => {
 2093                        let Some(workspace) = editor.workspace() else {
 2094                            return;
 2095                        };
 2096                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2097                        else {
 2098                            return;
 2099                        };
 2100
 2101                        if active_editor.entity_id() == cx.entity_id() {
 2102                            Self::open_transaction_for_hidden_buffers(
 2103                                workspace,
 2104                                transaction.clone(),
 2105                                "LSP Edit".to_string(),
 2106                                window,
 2107                                cx,
 2108                            );
 2109                        }
 2110                    }
 2111
 2112                    _ => {}
 2113                },
 2114            ));
 2115            if let Some(task_inventory) = project
 2116                .read(cx)
 2117                .task_store()
 2118                .read(cx)
 2119                .task_inventory()
 2120                .cloned()
 2121            {
 2122                project_subscriptions.push(cx.observe_in(
 2123                    &task_inventory,
 2124                    window,
 2125                    |editor, _, window, cx| {
 2126                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2127                    },
 2128                ));
 2129            };
 2130
 2131            project_subscriptions.push(cx.subscribe_in(
 2132                &project.read(cx).breakpoint_store(),
 2133                window,
 2134                |editor, _, event, window, cx| match event {
 2135                    BreakpointStoreEvent::ClearDebugLines => {
 2136                        editor.clear_row_highlights::<ActiveDebugLine>();
 2137                        editor.refresh_inline_values(cx);
 2138                    }
 2139                    BreakpointStoreEvent::SetDebugLine => {
 2140                        if editor.go_to_active_debug_line(window, cx) {
 2141                            cx.stop_propagation();
 2142                        }
 2143
 2144                        editor.refresh_inline_values(cx);
 2145                    }
 2146                    _ => {}
 2147                },
 2148            ));
 2149            let git_store = project.read(cx).git_store().clone();
 2150            let project = project.clone();
 2151            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2152                if let GitStoreEvent::RepositoryAdded = event {
 2153                    this.load_diff_task = Some(
 2154                        update_uncommitted_diff_for_buffer(
 2155                            cx.entity(),
 2156                            &project,
 2157                            this.buffer.read(cx).all_buffers(),
 2158                            this.buffer.clone(),
 2159                            cx,
 2160                        )
 2161                        .shared(),
 2162                    );
 2163                }
 2164            }));
 2165        }
 2166
 2167        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2168
 2169        let inlay_hint_settings =
 2170            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2171        let focus_handle = cx.focus_handle();
 2172        if !is_minimap {
 2173            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2174                .detach();
 2175            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2176                .detach();
 2177            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2178                .detach();
 2179            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2180                .detach();
 2181            cx.observe_pending_input(window, Self::observe_pending_input)
 2182                .detach();
 2183        }
 2184
 2185        let show_indent_guides =
 2186            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2187                Some(false)
 2188            } else {
 2189                None
 2190            };
 2191
 2192        let breakpoint_store = match (&mode, project.as_ref()) {
 2193            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2194            _ => None,
 2195        };
 2196
 2197        let mut code_action_providers = Vec::new();
 2198        let mut load_uncommitted_diff = None;
 2199        if let Some(project) = project.clone() {
 2200            load_uncommitted_diff = Some(
 2201                update_uncommitted_diff_for_buffer(
 2202                    cx.entity(),
 2203                    &project,
 2204                    multi_buffer.read(cx).all_buffers(),
 2205                    multi_buffer.clone(),
 2206                    cx,
 2207                )
 2208                .shared(),
 2209            );
 2210            code_action_providers.push(Rc::new(project) as Rc<_>);
 2211        }
 2212
 2213        let mut editor = Self {
 2214            focus_handle,
 2215            show_cursor_when_unfocused: false,
 2216            last_focused_descendant: None,
 2217            buffer: multi_buffer.clone(),
 2218            display_map: display_map.clone(),
 2219            placeholder_display_map: None,
 2220            selections,
 2221            scroll_manager: ScrollManager::new(cx),
 2222            columnar_selection_state: None,
 2223            add_selections_state: None,
 2224            select_next_state: None,
 2225            select_prev_state: None,
 2226            selection_history: SelectionHistory::default(),
 2227            defer_selection_effects: false,
 2228            deferred_selection_effects_state: None,
 2229            autoclose_regions: Vec::new(),
 2230            snippet_stack: InvalidationStack::default(),
 2231            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2232            ime_transaction: None,
 2233            active_diagnostics: ActiveDiagnostic::None,
 2234            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2235            inline_diagnostics_update: Task::ready(()),
 2236            inline_diagnostics: Vec::new(),
 2237            soft_wrap_mode_override,
 2238            diagnostics_max_severity,
 2239            hard_wrap: None,
 2240            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2241            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2242            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2243            project,
 2244            blink_manager: blink_manager.clone(),
 2245            show_local_selections: true,
 2246            show_scrollbars: ScrollbarAxes {
 2247                horizontal: full_mode,
 2248                vertical: full_mode,
 2249            },
 2250            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2251            offset_content: !matches!(mode, EditorMode::SingleLine),
 2252            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2253            show_gutter: full_mode,
 2254            show_line_numbers: (!full_mode).then_some(false),
 2255            use_relative_line_numbers: None,
 2256            disable_expand_excerpt_buttons: !full_mode,
 2257            delegate_expand_excerpts: false,
 2258            show_git_diff_gutter: None,
 2259            show_code_actions: None,
 2260            show_runnables: None,
 2261            show_breakpoints: None,
 2262            show_diff_review_button: false,
 2263            show_wrap_guides: None,
 2264            show_indent_guides,
 2265            buffers_with_disabled_indent_guides: HashSet::default(),
 2266            highlight_order: 0,
 2267            highlighted_rows: HashMap::default(),
 2268            background_highlights: HashMap::default(),
 2269            gutter_highlights: HashMap::default(),
 2270            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2271            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2272            nav_history: None,
 2273            context_menu: RefCell::new(None),
 2274            context_menu_options: None,
 2275            mouse_context_menu: None,
 2276            completion_tasks: Vec::new(),
 2277            inline_blame_popover: None,
 2278            inline_blame_popover_show_task: None,
 2279            signature_help_state: SignatureHelpState::default(),
 2280            auto_signature_help: None,
 2281            find_all_references_task_sources: Vec::new(),
 2282            next_completion_id: 0,
 2283            next_inlay_id: 0,
 2284            code_action_providers,
 2285            available_code_actions: None,
 2286            code_actions_task: None,
 2287            quick_selection_highlight_task: None,
 2288            debounced_selection_highlight_task: None,
 2289            debounced_selection_highlight_complete: false,
 2290            document_highlights_task: None,
 2291            linked_editing_range_task: None,
 2292            pending_rename: None,
 2293            searchable: !is_minimap,
 2294            cursor_shape: EditorSettings::get_global(cx)
 2295                .cursor_shape
 2296                .unwrap_or_default(),
 2297            cursor_offset_on_selection: false,
 2298            current_line_highlight: None,
 2299            autoindent_mode: Some(AutoindentMode::EachLine),
 2300            collapse_matches: false,
 2301            workspace: None,
 2302            input_enabled: !is_minimap,
 2303            use_modal_editing: full_mode,
 2304            read_only: is_minimap,
 2305            use_autoclose: true,
 2306            use_auto_surround: true,
 2307            auto_replace_emoji_shortcode: false,
 2308            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2309            leader_id: None,
 2310            remote_id: None,
 2311            hover_state: HoverState::default(),
 2312            pending_mouse_down: None,
 2313            prev_pressure_stage: None,
 2314            hovered_link_state: None,
 2315            edit_prediction_provider: None,
 2316            active_edit_prediction: None,
 2317            stale_edit_prediction_in_menu: None,
 2318            edit_prediction_preview: EditPredictionPreview::Inactive {
 2319                released_too_fast: false,
 2320            },
 2321            inline_diagnostics_enabled: full_mode,
 2322            diagnostics_enabled: full_mode,
 2323            word_completions_enabled: full_mode,
 2324            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2325            gutter_hovered: false,
 2326            pixel_position_of_newest_cursor: None,
 2327            last_bounds: None,
 2328            last_position_map: None,
 2329            expect_bounds_change: None,
 2330            gutter_dimensions: GutterDimensions::default(),
 2331            style: None,
 2332            show_cursor_names: false,
 2333            hovered_cursors: HashMap::default(),
 2334            next_editor_action_id: EditorActionId::default(),
 2335            editor_actions: Rc::default(),
 2336            edit_predictions_hidden_for_vim_mode: false,
 2337            show_edit_predictions_override: None,
 2338            show_completions_on_input_override: None,
 2339            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2340            edit_prediction_settings: EditPredictionSettings::Disabled,
 2341            edit_prediction_indent_conflict: false,
 2342            edit_prediction_requires_modifier_in_indent_conflict: true,
 2343            custom_context_menu: None,
 2344            show_git_blame_gutter: false,
 2345            show_git_blame_inline: false,
 2346            show_selection_menu: None,
 2347            show_git_blame_inline_delay_task: None,
 2348            git_blame_inline_enabled: full_mode
 2349                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2350            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2351            buffer_serialization: is_minimap.not().then(|| {
 2352                BufferSerialization::new(
 2353                    ProjectSettings::get_global(cx)
 2354                        .session
 2355                        .restore_unsaved_buffers,
 2356                )
 2357            }),
 2358            blame: None,
 2359            blame_subscription: None,
 2360            tasks: BTreeMap::default(),
 2361
 2362            breakpoint_store,
 2363            gutter_breakpoint_indicator: (None, None),
 2364            gutter_diff_review_indicator: (None, None),
 2365            hovered_diff_hunk_row: None,
 2366            _subscriptions: (!is_minimap)
 2367                .then(|| {
 2368                    vec![
 2369                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2370                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2371                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2372                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2373                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2374                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2375                        cx.observe_window_activation(window, |editor, window, cx| {
 2376                            let active = window.is_window_active();
 2377                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2378                                if active {
 2379                                    blink_manager.enable(cx);
 2380                                } else {
 2381                                    blink_manager.disable(cx);
 2382                                }
 2383                            });
 2384                            if active {
 2385                                editor.show_mouse_cursor(cx);
 2386                            }
 2387                        }),
 2388                    ]
 2389                })
 2390                .unwrap_or_default(),
 2391            tasks_update_task: None,
 2392            pull_diagnostics_task: Task::ready(()),
 2393            pull_diagnostics_background_task: Task::ready(()),
 2394            colors: None,
 2395            refresh_colors_task: Task::ready(()),
 2396            inlay_hints: None,
 2397            next_color_inlay_id: 0,
 2398            post_scroll_update: Task::ready(()),
 2399            linked_edit_ranges: Default::default(),
 2400            in_project_search: false,
 2401            previous_search_ranges: None,
 2402            breadcrumb_header: None,
 2403            focused_block: None,
 2404            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2405            addons: HashMap::default(),
 2406            registered_buffers: HashMap::default(),
 2407            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2408            selection_mark_mode: false,
 2409            toggle_fold_multiple_buffers: Task::ready(()),
 2410            serialize_selections: Task::ready(()),
 2411            serialize_folds: Task::ready(()),
 2412            text_style_refinement: None,
 2413            load_diff_task: load_uncommitted_diff,
 2414            temporary_diff_override: false,
 2415            mouse_cursor_hidden: false,
 2416            minimap: None,
 2417            hide_mouse_mode: EditorSettings::get_global(cx)
 2418                .hide_mouse
 2419                .unwrap_or_default(),
 2420            change_list: ChangeList::new(),
 2421            mode,
 2422            selection_drag_state: SelectionDragState::None,
 2423            folding_newlines: Task::ready(()),
 2424            lookup_key: None,
 2425            select_next_is_case_sensitive: None,
 2426            applicable_language_settings: HashMap::default(),
 2427            accent_data: None,
 2428            fetched_tree_sitter_chunks: HashMap::default(),
 2429            number_deleted_lines: false,
 2430        };
 2431
 2432        if is_minimap {
 2433            return editor;
 2434        }
 2435
 2436        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2437        editor.accent_data = editor.fetch_accent_data(cx);
 2438
 2439        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2440            editor
 2441                ._subscriptions
 2442                .push(cx.observe(breakpoints, |_, _, cx| {
 2443                    cx.notify();
 2444                }));
 2445        }
 2446        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2447        editor._subscriptions.extend(project_subscriptions);
 2448
 2449        editor._subscriptions.push(cx.subscribe_in(
 2450            &cx.entity(),
 2451            window,
 2452            |editor, _, e: &EditorEvent, window, cx| match e {
 2453                EditorEvent::ScrollPositionChanged { local, .. } => {
 2454                    if *local {
 2455                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2456                        editor.inline_blame_popover.take();
 2457                        let new_anchor = editor.scroll_manager.anchor();
 2458                        let snapshot = editor.snapshot(window, cx);
 2459                        editor.update_restoration_data(cx, move |data| {
 2460                            data.scroll_position = (
 2461                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2462                                new_anchor.offset,
 2463                            );
 2464                        });
 2465
 2466                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2467                            cx.background_executor()
 2468                                .timer(Duration::from_millis(50))
 2469                                .await;
 2470                            editor
 2471                                .update_in(cx, |editor, window, cx| {
 2472                                    editor.register_visible_buffers(cx);
 2473                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2474                                    editor.refresh_inlay_hints(
 2475                                        InlayHintRefreshReason::NewLinesShown,
 2476                                        cx,
 2477                                    );
 2478                                    editor.colorize_brackets(false, cx);
 2479                                })
 2480                                .ok();
 2481                        });
 2482                    }
 2483                }
 2484                EditorEvent::Edited { .. } => {
 2485                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2486                        .map(|vim_mode| vim_mode.0)
 2487                        .unwrap_or(false);
 2488                    if !vim_mode {
 2489                        let display_map = editor.display_snapshot(cx);
 2490                        let selections = editor.selections.all_adjusted_display(&display_map);
 2491                        let pop_state = editor
 2492                            .change_list
 2493                            .last()
 2494                            .map(|previous| {
 2495                                previous.len() == selections.len()
 2496                                    && previous.iter().enumerate().all(|(ix, p)| {
 2497                                        p.to_display_point(&display_map).row()
 2498                                            == selections[ix].head().row()
 2499                                    })
 2500                            })
 2501                            .unwrap_or(false);
 2502                        let new_positions = selections
 2503                            .into_iter()
 2504                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2505                            .collect();
 2506                        editor
 2507                            .change_list
 2508                            .push_to_change_list(pop_state, new_positions);
 2509                    }
 2510                }
 2511                _ => (),
 2512            },
 2513        ));
 2514
 2515        if let Some(dap_store) = editor
 2516            .project
 2517            .as_ref()
 2518            .map(|project| project.read(cx).dap_store())
 2519        {
 2520            let weak_editor = cx.weak_entity();
 2521
 2522            editor
 2523                ._subscriptions
 2524                .push(
 2525                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2526                        let session_entity = cx.entity();
 2527                        weak_editor
 2528                            .update(cx, |editor, cx| {
 2529                                editor._subscriptions.push(
 2530                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2531                                );
 2532                            })
 2533                            .ok();
 2534                    }),
 2535                );
 2536
 2537            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2538                editor
 2539                    ._subscriptions
 2540                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2541            }
 2542        }
 2543
 2544        // skip adding the initial selection to selection history
 2545        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2546        editor.end_selection(window, cx);
 2547        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2548
 2549        editor.scroll_manager.show_scrollbars(window, cx);
 2550        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2551
 2552        if full_mode {
 2553            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2554            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2555
 2556            if editor.git_blame_inline_enabled {
 2557                editor.start_git_blame_inline(false, window, cx);
 2558            }
 2559
 2560            editor.go_to_active_debug_line(window, cx);
 2561
 2562            editor.minimap =
 2563                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2564            editor.colors = Some(LspColorData::new(cx));
 2565            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2566
 2567            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2568                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2569            }
 2570            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2571        }
 2572
 2573        editor
 2574    }
 2575
 2576    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2577        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2578    }
 2579
 2580    pub fn deploy_mouse_context_menu(
 2581        &mut self,
 2582        position: gpui::Point<Pixels>,
 2583        context_menu: Entity<ContextMenu>,
 2584        window: &mut Window,
 2585        cx: &mut Context<Self>,
 2586    ) {
 2587        self.mouse_context_menu = Some(MouseContextMenu::new(
 2588            self,
 2589            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2590            context_menu,
 2591            window,
 2592            cx,
 2593        ));
 2594    }
 2595
 2596    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2597        self.mouse_context_menu
 2598            .as_ref()
 2599            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2600    }
 2601
 2602    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2603        if self
 2604            .selections
 2605            .pending_anchor()
 2606            .is_some_and(|pending_selection| {
 2607                let snapshot = self.buffer().read(cx).snapshot(cx);
 2608                pending_selection.range().includes(range, &snapshot)
 2609            })
 2610        {
 2611            return true;
 2612        }
 2613
 2614        self.selections
 2615            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2616            .into_iter()
 2617            .any(|selection| {
 2618                // This is needed to cover a corner case, if we just check for an existing
 2619                // selection in the fold range, having a cursor at the start of the fold
 2620                // marks it as selected. Non-empty selections don't cause this.
 2621                let length = selection.end - selection.start;
 2622                length > 0
 2623            })
 2624    }
 2625
 2626    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2627        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2628    }
 2629
 2630    fn key_context_internal(
 2631        &self,
 2632        has_active_edit_prediction: bool,
 2633        window: &mut Window,
 2634        cx: &mut App,
 2635    ) -> KeyContext {
 2636        let mut key_context = KeyContext::new_with_defaults();
 2637        key_context.add("Editor");
 2638        let mode = match self.mode {
 2639            EditorMode::SingleLine => "single_line",
 2640            EditorMode::AutoHeight { .. } => "auto_height",
 2641            EditorMode::Minimap { .. } => "minimap",
 2642            EditorMode::Full { .. } => "full",
 2643        };
 2644
 2645        if EditorSettings::jupyter_enabled(cx) {
 2646            key_context.add("jupyter");
 2647        }
 2648
 2649        key_context.set("mode", mode);
 2650        if self.pending_rename.is_some() {
 2651            key_context.add("renaming");
 2652        }
 2653
 2654        if let Some(snippet_stack) = self.snippet_stack.last() {
 2655            key_context.add("in_snippet");
 2656
 2657            if snippet_stack.active_index > 0 {
 2658                key_context.add("has_previous_tabstop");
 2659            }
 2660
 2661            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2662                key_context.add("has_next_tabstop");
 2663            }
 2664        }
 2665
 2666        match self.context_menu.borrow().as_ref() {
 2667            Some(CodeContextMenu::Completions(menu)) => {
 2668                if menu.visible() {
 2669                    key_context.add("menu");
 2670                    key_context.add("showing_completions");
 2671                }
 2672            }
 2673            Some(CodeContextMenu::CodeActions(menu)) => {
 2674                if menu.visible() {
 2675                    key_context.add("menu");
 2676                    key_context.add("showing_code_actions")
 2677                }
 2678            }
 2679            None => {}
 2680        }
 2681
 2682        if self.signature_help_state.has_multiple_signatures() {
 2683            key_context.add("showing_signature_help");
 2684        }
 2685
 2686        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2687        if !self.focus_handle(cx).contains_focused(window, cx)
 2688            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2689        {
 2690            for addon in self.addons.values() {
 2691                addon.extend_key_context(&mut key_context, cx)
 2692            }
 2693        }
 2694
 2695        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2696            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2697                Some(
 2698                    file.full_path(cx)
 2699                        .extension()?
 2700                        .to_string_lossy()
 2701                        .to_lowercase(),
 2702                )
 2703            }) {
 2704                key_context.set("extension", extension);
 2705            }
 2706        } else {
 2707            key_context.add("multibuffer");
 2708        }
 2709
 2710        if has_active_edit_prediction {
 2711            if self.edit_prediction_in_conflict() {
 2712                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2713            } else {
 2714                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2715                key_context.add("copilot_suggestion");
 2716            }
 2717        }
 2718
 2719        if self.selection_mark_mode {
 2720            key_context.add("selection_mode");
 2721        }
 2722
 2723        let disjoint = self.selections.disjoint_anchors();
 2724        let snapshot = self.snapshot(window, cx);
 2725        let snapshot = snapshot.buffer_snapshot();
 2726        if self.mode == EditorMode::SingleLine
 2727            && let [selection] = disjoint
 2728            && selection.start == selection.end
 2729            && selection.end.to_offset(snapshot) == snapshot.len()
 2730        {
 2731            key_context.add("end_of_input");
 2732        }
 2733
 2734        if self.has_any_expanded_diff_hunks(cx) {
 2735            key_context.add("diffs_expanded");
 2736        }
 2737
 2738        key_context
 2739    }
 2740
 2741    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2742        self.last_bounds.as_ref()
 2743    }
 2744
 2745    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2746        if self.mouse_cursor_hidden {
 2747            self.mouse_cursor_hidden = false;
 2748            cx.notify();
 2749        }
 2750    }
 2751
 2752    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2753        let hide_mouse_cursor = match origin {
 2754            HideMouseCursorOrigin::TypingAction => {
 2755                matches!(
 2756                    self.hide_mouse_mode,
 2757                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2758                )
 2759            }
 2760            HideMouseCursorOrigin::MovementAction => {
 2761                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2762            }
 2763        };
 2764        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2765            self.mouse_cursor_hidden = hide_mouse_cursor;
 2766            cx.notify();
 2767        }
 2768    }
 2769
 2770    pub fn edit_prediction_in_conflict(&self) -> bool {
 2771        if !self.show_edit_predictions_in_menu() {
 2772            return false;
 2773        }
 2774
 2775        let showing_completions = self
 2776            .context_menu
 2777            .borrow()
 2778            .as_ref()
 2779            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2780
 2781        showing_completions
 2782            || self.edit_prediction_requires_modifier()
 2783            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2784            // bindings to insert tab characters.
 2785            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2786    }
 2787
 2788    pub fn accept_edit_prediction_keybind(
 2789        &self,
 2790        granularity: EditPredictionGranularity,
 2791        window: &mut Window,
 2792        cx: &mut App,
 2793    ) -> AcceptEditPredictionBinding {
 2794        let key_context = self.key_context_internal(true, window, cx);
 2795        let in_conflict = self.edit_prediction_in_conflict();
 2796
 2797        let bindings =
 2798            match granularity {
 2799                EditPredictionGranularity::Word => window
 2800                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2801                EditPredictionGranularity::Line => window
 2802                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2803                EditPredictionGranularity::Full => {
 2804                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2805                }
 2806            };
 2807
 2808        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2809            !in_conflict
 2810                || binding
 2811                    .keystrokes()
 2812                    .first()
 2813                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2814        }))
 2815    }
 2816
 2817    pub fn new_file(
 2818        workspace: &mut Workspace,
 2819        _: &workspace::NewFile,
 2820        window: &mut Window,
 2821        cx: &mut Context<Workspace>,
 2822    ) {
 2823        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2824            "Failed to create buffer",
 2825            window,
 2826            cx,
 2827            |e, _, _| match e.error_code() {
 2828                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2829                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2830                e.error_tag("required").unwrap_or("the latest version")
 2831            )),
 2832                _ => None,
 2833            },
 2834        );
 2835    }
 2836
 2837    pub fn new_in_workspace(
 2838        workspace: &mut Workspace,
 2839        window: &mut Window,
 2840        cx: &mut Context<Workspace>,
 2841    ) -> Task<Result<Entity<Editor>>> {
 2842        let project = workspace.project().clone();
 2843        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2844
 2845        cx.spawn_in(window, async move |workspace, cx| {
 2846            let buffer = create.await?;
 2847            workspace.update_in(cx, |workspace, window, cx| {
 2848                let editor =
 2849                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2850                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2851                editor
 2852            })
 2853        })
 2854    }
 2855
 2856    fn new_file_vertical(
 2857        workspace: &mut Workspace,
 2858        _: &workspace::NewFileSplitVertical,
 2859        window: &mut Window,
 2860        cx: &mut Context<Workspace>,
 2861    ) {
 2862        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2863    }
 2864
 2865    fn new_file_horizontal(
 2866        workspace: &mut Workspace,
 2867        _: &workspace::NewFileSplitHorizontal,
 2868        window: &mut Window,
 2869        cx: &mut Context<Workspace>,
 2870    ) {
 2871        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2872    }
 2873
 2874    fn new_file_split(
 2875        workspace: &mut Workspace,
 2876        action: &workspace::NewFileSplit,
 2877        window: &mut Window,
 2878        cx: &mut Context<Workspace>,
 2879    ) {
 2880        Self::new_file_in_direction(workspace, action.0, window, cx)
 2881    }
 2882
 2883    fn new_file_in_direction(
 2884        workspace: &mut Workspace,
 2885        direction: SplitDirection,
 2886        window: &mut Window,
 2887        cx: &mut Context<Workspace>,
 2888    ) {
 2889        let project = workspace.project().clone();
 2890        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2891
 2892        cx.spawn_in(window, async move |workspace, cx| {
 2893            let buffer = create.await?;
 2894            workspace.update_in(cx, move |workspace, window, cx| {
 2895                workspace.split_item(
 2896                    direction,
 2897                    Box::new(
 2898                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2899                    ),
 2900                    window,
 2901                    cx,
 2902                )
 2903            })?;
 2904            anyhow::Ok(())
 2905        })
 2906        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2907            match e.error_code() {
 2908                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2909                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2910                e.error_tag("required").unwrap_or("the latest version")
 2911            )),
 2912                _ => None,
 2913            }
 2914        });
 2915    }
 2916
 2917    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2918        self.leader_id
 2919    }
 2920
 2921    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2922        &self.buffer
 2923    }
 2924
 2925    pub fn project(&self) -> Option<&Entity<Project>> {
 2926        self.project.as_ref()
 2927    }
 2928
 2929    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2930        self.workspace.as_ref()?.0.upgrade()
 2931    }
 2932
 2933    /// Returns the workspace serialization ID if this editor should be serialized.
 2934    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2935        self.workspace
 2936            .as_ref()
 2937            .filter(|_| self.should_serialize_buffer())
 2938            .and_then(|workspace| workspace.1)
 2939    }
 2940
 2941    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2942        self.buffer().read(cx).title(cx)
 2943    }
 2944
 2945    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2946        let git_blame_gutter_max_author_length = self
 2947            .render_git_blame_gutter(cx)
 2948            .then(|| {
 2949                if let Some(blame) = self.blame.as_ref() {
 2950                    let max_author_length =
 2951                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2952                    Some(max_author_length)
 2953                } else {
 2954                    None
 2955                }
 2956            })
 2957            .flatten();
 2958
 2959        EditorSnapshot {
 2960            mode: self.mode.clone(),
 2961            show_gutter: self.show_gutter,
 2962            offset_content: self.offset_content,
 2963            show_line_numbers: self.show_line_numbers,
 2964            number_deleted_lines: self.number_deleted_lines,
 2965            show_git_diff_gutter: self.show_git_diff_gutter,
 2966            show_code_actions: self.show_code_actions,
 2967            show_runnables: self.show_runnables,
 2968            show_breakpoints: self.show_breakpoints,
 2969            git_blame_gutter_max_author_length,
 2970            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2971            placeholder_display_snapshot: self
 2972                .placeholder_display_map
 2973                .as_ref()
 2974                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2975            scroll_anchor: self.scroll_manager.anchor(),
 2976            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2977            is_focused: self.focus_handle.is_focused(window),
 2978            current_line_highlight: self
 2979                .current_line_highlight
 2980                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2981            gutter_hovered: self.gutter_hovered,
 2982        }
 2983    }
 2984
 2985    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2986        self.buffer.read(cx).language_at(point, cx)
 2987    }
 2988
 2989    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2990        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2991    }
 2992
 2993    pub fn active_excerpt(
 2994        &self,
 2995        cx: &App,
 2996    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2997        self.buffer
 2998            .read(cx)
 2999            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3000    }
 3001
 3002    pub fn mode(&self) -> &EditorMode {
 3003        &self.mode
 3004    }
 3005
 3006    pub fn set_mode(&mut self, mode: EditorMode) {
 3007        self.mode = mode;
 3008    }
 3009
 3010    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3011        self.collaboration_hub.as_deref()
 3012    }
 3013
 3014    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3015        self.collaboration_hub = Some(hub);
 3016    }
 3017
 3018    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3019        self.in_project_search = in_project_search;
 3020    }
 3021
 3022    pub fn set_custom_context_menu(
 3023        &mut self,
 3024        f: impl 'static
 3025        + Fn(
 3026            &mut Self,
 3027            DisplayPoint,
 3028            &mut Window,
 3029            &mut Context<Self>,
 3030        ) -> Option<Entity<ui::ContextMenu>>,
 3031    ) {
 3032        self.custom_context_menu = Some(Box::new(f))
 3033    }
 3034
 3035    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3036        self.completion_provider = provider;
 3037    }
 3038
 3039    #[cfg(any(test, feature = "test-support"))]
 3040    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3041        self.completion_provider.clone()
 3042    }
 3043
 3044    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3045        self.semantics_provider.clone()
 3046    }
 3047
 3048    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3049        self.semantics_provider = provider;
 3050    }
 3051
 3052    pub fn set_edit_prediction_provider<T>(
 3053        &mut self,
 3054        provider: Option<Entity<T>>,
 3055        window: &mut Window,
 3056        cx: &mut Context<Self>,
 3057    ) where
 3058        T: EditPredictionDelegate,
 3059    {
 3060        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3061            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3062                if this.focus_handle.is_focused(window) {
 3063                    this.update_visible_edit_prediction(window, cx);
 3064                }
 3065            }),
 3066            provider: Arc::new(provider),
 3067        });
 3068        self.update_edit_prediction_settings(cx);
 3069        self.refresh_edit_prediction(false, false, window, cx);
 3070    }
 3071
 3072    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3073        self.placeholder_display_map
 3074            .as_ref()
 3075            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3076    }
 3077
 3078    pub fn set_placeholder_text(
 3079        &mut self,
 3080        placeholder_text: &str,
 3081        window: &mut Window,
 3082        cx: &mut Context<Self>,
 3083    ) {
 3084        let multibuffer = cx
 3085            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3086
 3087        let style = window.text_style();
 3088
 3089        self.placeholder_display_map = Some(cx.new(|cx| {
 3090            DisplayMap::new(
 3091                multibuffer,
 3092                style.font(),
 3093                style.font_size.to_pixels(window.rem_size()),
 3094                None,
 3095                FILE_HEADER_HEIGHT,
 3096                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3097                Default::default(),
 3098                DiagnosticSeverity::Off,
 3099                cx,
 3100            )
 3101        }));
 3102        cx.notify();
 3103    }
 3104
 3105    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3106        self.cursor_shape = cursor_shape;
 3107
 3108        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3109        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3110
 3111        cx.notify();
 3112    }
 3113
 3114    pub fn cursor_shape(&self) -> CursorShape {
 3115        self.cursor_shape
 3116    }
 3117
 3118    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3119        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3120    }
 3121
 3122    pub fn set_current_line_highlight(
 3123        &mut self,
 3124        current_line_highlight: Option<CurrentLineHighlight>,
 3125    ) {
 3126        self.current_line_highlight = current_line_highlight;
 3127    }
 3128
 3129    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3130        self.collapse_matches = collapse_matches;
 3131    }
 3132
 3133    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3134        if self.collapse_matches {
 3135            return range.start..range.start;
 3136        }
 3137        range.clone()
 3138    }
 3139
 3140    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3141        self.display_map.read(cx).clip_at_line_ends
 3142    }
 3143
 3144    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3145        if self.display_map.read(cx).clip_at_line_ends != clip {
 3146            self.display_map
 3147                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3148        }
 3149    }
 3150
 3151    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3152        self.input_enabled = input_enabled;
 3153    }
 3154
 3155    pub fn set_edit_predictions_hidden_for_vim_mode(
 3156        &mut self,
 3157        hidden: bool,
 3158        window: &mut Window,
 3159        cx: &mut Context<Self>,
 3160    ) {
 3161        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3162            self.edit_predictions_hidden_for_vim_mode = hidden;
 3163            if hidden {
 3164                self.update_visible_edit_prediction(window, cx);
 3165            } else {
 3166                self.refresh_edit_prediction(true, false, window, cx);
 3167            }
 3168        }
 3169    }
 3170
 3171    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3172        self.menu_edit_predictions_policy = value;
 3173    }
 3174
 3175    pub fn set_autoindent(&mut self, autoindent: bool) {
 3176        if autoindent {
 3177            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3178        } else {
 3179            self.autoindent_mode = None;
 3180        }
 3181    }
 3182
 3183    pub fn capability(&self, cx: &App) -> Capability {
 3184        if self.read_only {
 3185            Capability::ReadOnly
 3186        } else {
 3187            self.buffer.read(cx).capability()
 3188        }
 3189    }
 3190
 3191    pub fn read_only(&self, cx: &App) -> bool {
 3192        self.read_only || self.buffer.read(cx).read_only()
 3193    }
 3194
 3195    pub fn set_read_only(&mut self, read_only: bool) {
 3196        self.read_only = read_only;
 3197    }
 3198
 3199    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3200        self.use_autoclose = autoclose;
 3201    }
 3202
 3203    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3204        self.use_auto_surround = auto_surround;
 3205    }
 3206
 3207    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3208        self.auto_replace_emoji_shortcode = auto_replace;
 3209    }
 3210
 3211    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3212        self.buffer_serialization = should_serialize.then(|| {
 3213            BufferSerialization::new(
 3214                ProjectSettings::get_global(cx)
 3215                    .session
 3216                    .restore_unsaved_buffers,
 3217            )
 3218        })
 3219    }
 3220
 3221    fn should_serialize_buffer(&self) -> bool {
 3222        self.buffer_serialization.is_some()
 3223    }
 3224
 3225    pub fn toggle_edit_predictions(
 3226        &mut self,
 3227        _: &ToggleEditPrediction,
 3228        window: &mut Window,
 3229        cx: &mut Context<Self>,
 3230    ) {
 3231        if self.show_edit_predictions_override.is_some() {
 3232            self.set_show_edit_predictions(None, window, cx);
 3233        } else {
 3234            let show_edit_predictions = !self.edit_predictions_enabled();
 3235            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3236        }
 3237    }
 3238
 3239    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3240        self.show_completions_on_input_override = show_completions_on_input;
 3241    }
 3242
 3243    pub fn set_show_edit_predictions(
 3244        &mut self,
 3245        show_edit_predictions: Option<bool>,
 3246        window: &mut Window,
 3247        cx: &mut Context<Self>,
 3248    ) {
 3249        self.show_edit_predictions_override = show_edit_predictions;
 3250        self.update_edit_prediction_settings(cx);
 3251
 3252        if let Some(false) = show_edit_predictions {
 3253            self.discard_edit_prediction(false, cx);
 3254        } else {
 3255            self.refresh_edit_prediction(false, true, window, cx);
 3256        }
 3257    }
 3258
 3259    fn edit_predictions_disabled_in_scope(
 3260        &self,
 3261        buffer: &Entity<Buffer>,
 3262        buffer_position: language::Anchor,
 3263        cx: &App,
 3264    ) -> bool {
 3265        let snapshot = buffer.read(cx).snapshot();
 3266        let settings = snapshot.settings_at(buffer_position, cx);
 3267
 3268        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3269            return false;
 3270        };
 3271
 3272        scope.override_name().is_some_and(|scope_name| {
 3273            settings
 3274                .edit_predictions_disabled_in
 3275                .iter()
 3276                .any(|s| s == scope_name)
 3277        })
 3278    }
 3279
 3280    pub fn set_use_modal_editing(&mut self, to: bool) {
 3281        self.use_modal_editing = to;
 3282    }
 3283
 3284    pub fn use_modal_editing(&self) -> bool {
 3285        self.use_modal_editing
 3286    }
 3287
 3288    fn selections_did_change(
 3289        &mut self,
 3290        local: bool,
 3291        old_cursor_position: &Anchor,
 3292        effects: SelectionEffects,
 3293        window: &mut Window,
 3294        cx: &mut Context<Self>,
 3295    ) {
 3296        window.invalidate_character_coordinates();
 3297
 3298        // Copy selections to primary selection buffer
 3299        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3300        if local {
 3301            let selections = self
 3302                .selections
 3303                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3304            let buffer_handle = self.buffer.read(cx).read(cx);
 3305
 3306            let mut text = String::new();
 3307            for (index, selection) in selections.iter().enumerate() {
 3308                let text_for_selection = buffer_handle
 3309                    .text_for_range(selection.start..selection.end)
 3310                    .collect::<String>();
 3311
 3312                text.push_str(&text_for_selection);
 3313                if index != selections.len() - 1 {
 3314                    text.push('\n');
 3315                }
 3316            }
 3317
 3318            if !text.is_empty() {
 3319                cx.write_to_primary(ClipboardItem::new_string(text));
 3320            }
 3321        }
 3322
 3323        let selection_anchors = self.selections.disjoint_anchors_arc();
 3324
 3325        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3326            self.buffer.update(cx, |buffer, cx| {
 3327                buffer.set_active_selections(
 3328                    &selection_anchors,
 3329                    self.selections.line_mode(),
 3330                    self.cursor_shape,
 3331                    cx,
 3332                )
 3333            });
 3334        }
 3335        let display_map = self
 3336            .display_map
 3337            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3338        let buffer = display_map.buffer_snapshot();
 3339        if self.selections.count() == 1 {
 3340            self.add_selections_state = None;
 3341        }
 3342        self.select_next_state = None;
 3343        self.select_prev_state = None;
 3344        self.select_syntax_node_history.try_clear();
 3345        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3346        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3347        self.take_rename(false, window, cx);
 3348
 3349        let newest_selection = self.selections.newest_anchor();
 3350        let new_cursor_position = newest_selection.head();
 3351        let selection_start = newest_selection.start;
 3352
 3353        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3354            self.push_to_nav_history(
 3355                *old_cursor_position,
 3356                Some(new_cursor_position.to_point(buffer)),
 3357                false,
 3358                effects.nav_history == Some(true),
 3359                cx,
 3360            );
 3361        }
 3362
 3363        if local {
 3364            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3365                self.register_buffer(buffer_id, cx);
 3366            }
 3367
 3368            let mut context_menu = self.context_menu.borrow_mut();
 3369            let completion_menu = match context_menu.as_ref() {
 3370                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3371                Some(CodeContextMenu::CodeActions(_)) => {
 3372                    *context_menu = None;
 3373                    None
 3374                }
 3375                None => None,
 3376            };
 3377            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3378            drop(context_menu);
 3379
 3380            if effects.completions
 3381                && let Some(completion_position) = completion_position
 3382            {
 3383                let start_offset = selection_start.to_offset(buffer);
 3384                let position_matches = start_offset == completion_position.to_offset(buffer);
 3385                let continue_showing = if let Some((snap, ..)) =
 3386                    buffer.point_to_buffer_offset(completion_position)
 3387                    && !snap.capability.editable()
 3388                {
 3389                    false
 3390                } else if position_matches {
 3391                    if self.snippet_stack.is_empty() {
 3392                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3393                            == Some(CharKind::Word)
 3394                    } else {
 3395                        // Snippet choices can be shown even when the cursor is in whitespace.
 3396                        // Dismissing the menu with actions like backspace is handled by
 3397                        // invalidation regions.
 3398                        true
 3399                    }
 3400                } else {
 3401                    false
 3402                };
 3403
 3404                if continue_showing {
 3405                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3406                } else {
 3407                    self.hide_context_menu(window, cx);
 3408                }
 3409            }
 3410
 3411            hide_hover(self, cx);
 3412
 3413            if old_cursor_position.to_display_point(&display_map).row()
 3414                != new_cursor_position.to_display_point(&display_map).row()
 3415            {
 3416                self.available_code_actions.take();
 3417            }
 3418            self.refresh_code_actions(window, cx);
 3419            self.refresh_document_highlights(cx);
 3420            refresh_linked_ranges(self, window, cx);
 3421
 3422            self.refresh_selected_text_highlights(false, window, cx);
 3423            self.refresh_matching_bracket_highlights(window, cx);
 3424            self.update_visible_edit_prediction(window, cx);
 3425            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3426            self.inline_blame_popover.take();
 3427            if self.git_blame_inline_enabled {
 3428                self.start_inline_blame_timer(window, cx);
 3429            }
 3430        }
 3431
 3432        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3433        cx.emit(EditorEvent::SelectionsChanged { local });
 3434
 3435        let selections = &self.selections.disjoint_anchors_arc();
 3436        if selections.len() == 1 {
 3437            cx.emit(SearchEvent::ActiveMatchChanged)
 3438        }
 3439        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3440            let inmemory_selections = selections
 3441                .iter()
 3442                .map(|s| {
 3443                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3444                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3445                })
 3446                .collect();
 3447            self.update_restoration_data(cx, |data| {
 3448                data.selections = inmemory_selections;
 3449            });
 3450
 3451            if WorkspaceSettings::get(None, cx).restore_on_startup
 3452                != RestoreOnStartupBehavior::EmptyTab
 3453                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3454            {
 3455                let snapshot = self.buffer().read(cx).snapshot(cx);
 3456                let selections = selections.clone();
 3457                let background_executor = cx.background_executor().clone();
 3458                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3459                self.serialize_selections = cx.background_spawn(async move {
 3460                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3461                    let db_selections = selections
 3462                        .iter()
 3463                        .map(|selection| {
 3464                            (
 3465                                selection.start.to_offset(&snapshot).0,
 3466                                selection.end.to_offset(&snapshot).0,
 3467                            )
 3468                        })
 3469                        .collect();
 3470
 3471                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3472                        .await
 3473                        .with_context(|| {
 3474                            format!(
 3475                                "persisting editor selections for editor {editor_id}, \
 3476                                workspace {workspace_id:?}"
 3477                            )
 3478                        })
 3479                        .log_err();
 3480                });
 3481            }
 3482        }
 3483
 3484        cx.notify();
 3485    }
 3486
 3487    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3488        use text::ToOffset as _;
 3489        use text::ToPoint as _;
 3490
 3491        if self.mode.is_minimap()
 3492            || WorkspaceSettings::get(None, cx).restore_on_startup
 3493                == RestoreOnStartupBehavior::EmptyTab
 3494        {
 3495            return;
 3496        }
 3497
 3498        if !self.buffer().read(cx).is_singleton() {
 3499            return;
 3500        }
 3501
 3502        let display_snapshot = self
 3503            .display_map
 3504            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3505        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3506            return;
 3507        };
 3508        let inmemory_folds = display_snapshot
 3509            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3510            .map(|fold| {
 3511                fold.range.start.text_anchor.to_point(&snapshot)
 3512                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3513            })
 3514            .collect();
 3515        self.update_restoration_data(cx, |data| {
 3516            data.folds = inmemory_folds;
 3517        });
 3518
 3519        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3520            return;
 3521        };
 3522        let background_executor = cx.background_executor().clone();
 3523        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3524        const FINGERPRINT_LEN: usize = 32;
 3525        let db_folds = display_snapshot
 3526            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3527            .map(|fold| {
 3528                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3529                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3530
 3531                // Extract fingerprints - content at fold boundaries for validation on restore
 3532                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3533                // content that might change independently.
 3534                // start_fp: first min(32, fold_len) bytes of fold content
 3535                // end_fp: last min(32, fold_len) bytes of fold content
 3536                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3537                let fold_len = end - start;
 3538                let start_fp_end = snapshot
 3539                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3540                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3541                let end_fp_start = snapshot
 3542                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3543                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3544
 3545                (start, end, start_fp, end_fp)
 3546            })
 3547            .collect::<Vec<_>>();
 3548        self.serialize_folds = cx.background_spawn(async move {
 3549            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3550            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3551                .await
 3552                .with_context(|| {
 3553                    format!(
 3554                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3555                    )
 3556                })
 3557                .log_err();
 3558        });
 3559    }
 3560
 3561    pub fn sync_selections(
 3562        &mut self,
 3563        other: Entity<Editor>,
 3564        cx: &mut Context<Self>,
 3565    ) -> gpui::Subscription {
 3566        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3567        if !other_selections.is_empty() {
 3568            self.selections
 3569                .change_with(&self.display_snapshot(cx), |selections| {
 3570                    selections.select_anchors(other_selections);
 3571                });
 3572        }
 3573
 3574        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3575            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3576                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3577                if other_selections.is_empty() {
 3578                    return;
 3579                }
 3580                let snapshot = this.display_snapshot(cx);
 3581                this.selections.change_with(&snapshot, |selections| {
 3582                    selections.select_anchors(other_selections);
 3583                });
 3584            }
 3585        });
 3586
 3587        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3588            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3589                let these_selections = this.selections.disjoint_anchors().to_vec();
 3590                if these_selections.is_empty() {
 3591                    return;
 3592                }
 3593                other.update(cx, |other_editor, cx| {
 3594                    let snapshot = other_editor.display_snapshot(cx);
 3595                    other_editor
 3596                        .selections
 3597                        .change_with(&snapshot, |selections| {
 3598                            selections.select_anchors(these_selections);
 3599                        })
 3600                });
 3601            }
 3602        });
 3603
 3604        Subscription::join(other_subscription, this_subscription)
 3605    }
 3606
 3607    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3608        if self.buffer().read(cx).is_singleton() {
 3609            return;
 3610        }
 3611        let snapshot = self.buffer.read(cx).snapshot(cx);
 3612        let buffer_ids: HashSet<BufferId> = self
 3613            .selections
 3614            .disjoint_anchor_ranges()
 3615            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3616            .collect();
 3617        for buffer_id in buffer_ids {
 3618            self.unfold_buffer(buffer_id, cx);
 3619        }
 3620    }
 3621
 3622    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3623    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3624    /// effects of selection change occur at the end of the transaction.
 3625    pub fn change_selections<R>(
 3626        &mut self,
 3627        effects: SelectionEffects,
 3628        window: &mut Window,
 3629        cx: &mut Context<Self>,
 3630        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3631    ) -> R {
 3632        let snapshot = self.display_snapshot(cx);
 3633        if let Some(state) = &mut self.deferred_selection_effects_state {
 3634            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3635            state.effects.completions = effects.completions;
 3636            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3637            let (changed, result) = self.selections.change_with(&snapshot, change);
 3638            state.changed |= changed;
 3639            return result;
 3640        }
 3641        let mut state = DeferredSelectionEffectsState {
 3642            changed: false,
 3643            effects,
 3644            old_cursor_position: self.selections.newest_anchor().head(),
 3645            history_entry: SelectionHistoryEntry {
 3646                selections: self.selections.disjoint_anchors_arc(),
 3647                select_next_state: self.select_next_state.clone(),
 3648                select_prev_state: self.select_prev_state.clone(),
 3649                add_selections_state: self.add_selections_state.clone(),
 3650            },
 3651        };
 3652        let (changed, result) = self.selections.change_with(&snapshot, change);
 3653        state.changed = state.changed || changed;
 3654        if self.defer_selection_effects {
 3655            self.deferred_selection_effects_state = Some(state);
 3656        } else {
 3657            self.apply_selection_effects(state, window, cx);
 3658        }
 3659        result
 3660    }
 3661
 3662    /// Defers the effects of selection change, so that the effects of multiple calls to
 3663    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3664    /// to selection history and the state of popovers based on selection position aren't
 3665    /// erroneously updated.
 3666    pub fn with_selection_effects_deferred<R>(
 3667        &mut self,
 3668        window: &mut Window,
 3669        cx: &mut Context<Self>,
 3670        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3671    ) -> R {
 3672        let already_deferred = self.defer_selection_effects;
 3673        self.defer_selection_effects = true;
 3674        let result = update(self, window, cx);
 3675        if !already_deferred {
 3676            self.defer_selection_effects = false;
 3677            if let Some(state) = self.deferred_selection_effects_state.take() {
 3678                self.apply_selection_effects(state, window, cx);
 3679            }
 3680        }
 3681        result
 3682    }
 3683
 3684    fn apply_selection_effects(
 3685        &mut self,
 3686        state: DeferredSelectionEffectsState,
 3687        window: &mut Window,
 3688        cx: &mut Context<Self>,
 3689    ) {
 3690        if state.changed {
 3691            self.selection_history.push(state.history_entry);
 3692
 3693            if let Some(autoscroll) = state.effects.scroll {
 3694                self.request_autoscroll(autoscroll, cx);
 3695            }
 3696
 3697            let old_cursor_position = &state.old_cursor_position;
 3698
 3699            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3700
 3701            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3702                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3703            }
 3704        }
 3705    }
 3706
 3707    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3708    where
 3709        I: IntoIterator<Item = (Range<S>, T)>,
 3710        S: ToOffset,
 3711        T: Into<Arc<str>>,
 3712    {
 3713        if self.read_only(cx) {
 3714            return;
 3715        }
 3716
 3717        self.buffer
 3718            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3719    }
 3720
 3721    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3722    where
 3723        I: IntoIterator<Item = (Range<S>, T)>,
 3724        S: ToOffset,
 3725        T: Into<Arc<str>>,
 3726    {
 3727        if self.read_only(cx) {
 3728            return;
 3729        }
 3730
 3731        self.buffer.update(cx, |buffer, cx| {
 3732            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3733        });
 3734    }
 3735
 3736    pub fn edit_with_block_indent<I, S, T>(
 3737        &mut self,
 3738        edits: I,
 3739        original_indent_columns: Vec<Option<u32>>,
 3740        cx: &mut Context<Self>,
 3741    ) where
 3742        I: IntoIterator<Item = (Range<S>, T)>,
 3743        S: ToOffset,
 3744        T: Into<Arc<str>>,
 3745    {
 3746        if self.read_only(cx) {
 3747            return;
 3748        }
 3749
 3750        self.buffer.update(cx, |buffer, cx| {
 3751            buffer.edit(
 3752                edits,
 3753                Some(AutoindentMode::Block {
 3754                    original_indent_columns,
 3755                }),
 3756                cx,
 3757            )
 3758        });
 3759    }
 3760
 3761    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3762        self.hide_context_menu(window, cx);
 3763
 3764        match phase {
 3765            SelectPhase::Begin {
 3766                position,
 3767                add,
 3768                click_count,
 3769            } => self.begin_selection(position, add, click_count, window, cx),
 3770            SelectPhase::BeginColumnar {
 3771                position,
 3772                goal_column,
 3773                reset,
 3774                mode,
 3775            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3776            SelectPhase::Extend {
 3777                position,
 3778                click_count,
 3779            } => self.extend_selection(position, click_count, window, cx),
 3780            SelectPhase::Update {
 3781                position,
 3782                goal_column,
 3783                scroll_delta,
 3784            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3785            SelectPhase::End => self.end_selection(window, cx),
 3786        }
 3787    }
 3788
 3789    fn extend_selection(
 3790        &mut self,
 3791        position: DisplayPoint,
 3792        click_count: usize,
 3793        window: &mut Window,
 3794        cx: &mut Context<Self>,
 3795    ) {
 3796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3797        let tail = self
 3798            .selections
 3799            .newest::<MultiBufferOffset>(&display_map)
 3800            .tail();
 3801        let click_count = click_count.max(match self.selections.select_mode() {
 3802            SelectMode::Character => 1,
 3803            SelectMode::Word(_) => 2,
 3804            SelectMode::Line(_) => 3,
 3805            SelectMode::All => 4,
 3806        });
 3807        self.begin_selection(position, false, click_count, window, cx);
 3808
 3809        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3810
 3811        let current_selection = match self.selections.select_mode() {
 3812            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3813            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3814        };
 3815
 3816        let mut pending_selection = self
 3817            .selections
 3818            .pending_anchor()
 3819            .cloned()
 3820            .expect("extend_selection not called with pending selection");
 3821
 3822        if pending_selection
 3823            .start
 3824            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3825            == Ordering::Greater
 3826        {
 3827            pending_selection.start = current_selection.start;
 3828        }
 3829        if pending_selection
 3830            .end
 3831            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3832            == Ordering::Less
 3833        {
 3834            pending_selection.end = current_selection.end;
 3835            pending_selection.reversed = true;
 3836        }
 3837
 3838        let mut pending_mode = self.selections.pending_mode().unwrap();
 3839        match &mut pending_mode {
 3840            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3841            _ => {}
 3842        }
 3843
 3844        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3845            SelectionEffects::scroll(Autoscroll::fit())
 3846        } else {
 3847            SelectionEffects::no_scroll()
 3848        };
 3849
 3850        self.change_selections(effects, window, cx, |s| {
 3851            s.set_pending(pending_selection.clone(), pending_mode);
 3852            s.set_is_extending(true);
 3853        });
 3854    }
 3855
 3856    fn begin_selection(
 3857        &mut self,
 3858        position: DisplayPoint,
 3859        add: bool,
 3860        click_count: usize,
 3861        window: &mut Window,
 3862        cx: &mut Context<Self>,
 3863    ) {
 3864        if !self.focus_handle.is_focused(window) {
 3865            self.last_focused_descendant = None;
 3866            window.focus(&self.focus_handle, cx);
 3867        }
 3868
 3869        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3870        let buffer = display_map.buffer_snapshot();
 3871        let position = display_map.clip_point(position, Bias::Left);
 3872
 3873        let start;
 3874        let end;
 3875        let mode;
 3876        let mut auto_scroll;
 3877        match click_count {
 3878            1 => {
 3879                start = buffer.anchor_before(position.to_point(&display_map));
 3880                end = start;
 3881                mode = SelectMode::Character;
 3882                auto_scroll = true;
 3883            }
 3884            2 => {
 3885                let position = display_map
 3886                    .clip_point(position, Bias::Left)
 3887                    .to_offset(&display_map, Bias::Left);
 3888                let (range, _) = buffer.surrounding_word(position, None);
 3889                start = buffer.anchor_before(range.start);
 3890                end = buffer.anchor_before(range.end);
 3891                mode = SelectMode::Word(start..end);
 3892                auto_scroll = true;
 3893            }
 3894            3 => {
 3895                let position = display_map
 3896                    .clip_point(position, Bias::Left)
 3897                    .to_point(&display_map);
 3898                let line_start = display_map.prev_line_boundary(position).0;
 3899                let next_line_start = buffer.clip_point(
 3900                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3901                    Bias::Left,
 3902                );
 3903                start = buffer.anchor_before(line_start);
 3904                end = buffer.anchor_before(next_line_start);
 3905                mode = SelectMode::Line(start..end);
 3906                auto_scroll = true;
 3907            }
 3908            _ => {
 3909                start = buffer.anchor_before(MultiBufferOffset(0));
 3910                end = buffer.anchor_before(buffer.len());
 3911                mode = SelectMode::All;
 3912                auto_scroll = false;
 3913            }
 3914        }
 3915        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3916
 3917        let point_to_delete: Option<usize> = {
 3918            let selected_points: Vec<Selection<Point>> =
 3919                self.selections.disjoint_in_range(start..end, &display_map);
 3920
 3921            if !add || click_count > 1 {
 3922                None
 3923            } else if !selected_points.is_empty() {
 3924                Some(selected_points[0].id)
 3925            } else {
 3926                let clicked_point_already_selected =
 3927                    self.selections.disjoint_anchors().iter().find(|selection| {
 3928                        selection.start.to_point(buffer) == start.to_point(buffer)
 3929                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3930                    });
 3931
 3932                clicked_point_already_selected.map(|selection| selection.id)
 3933            }
 3934        };
 3935
 3936        let selections_count = self.selections.count();
 3937        let effects = if auto_scroll {
 3938            SelectionEffects::default()
 3939        } else {
 3940            SelectionEffects::no_scroll()
 3941        };
 3942
 3943        self.change_selections(effects, window, cx, |s| {
 3944            if let Some(point_to_delete) = point_to_delete {
 3945                s.delete(point_to_delete);
 3946
 3947                if selections_count == 1 {
 3948                    s.set_pending_anchor_range(start..end, mode);
 3949                }
 3950            } else {
 3951                if !add {
 3952                    s.clear_disjoint();
 3953                }
 3954
 3955                s.set_pending_anchor_range(start..end, mode);
 3956            }
 3957        });
 3958    }
 3959
 3960    fn begin_columnar_selection(
 3961        &mut self,
 3962        position: DisplayPoint,
 3963        goal_column: u32,
 3964        reset: bool,
 3965        mode: ColumnarMode,
 3966        window: &mut Window,
 3967        cx: &mut Context<Self>,
 3968    ) {
 3969        if !self.focus_handle.is_focused(window) {
 3970            self.last_focused_descendant = None;
 3971            window.focus(&self.focus_handle, cx);
 3972        }
 3973
 3974        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3975
 3976        if reset {
 3977            let pointer_position = display_map
 3978                .buffer_snapshot()
 3979                .anchor_before(position.to_point(&display_map));
 3980
 3981            self.change_selections(
 3982                SelectionEffects::scroll(Autoscroll::newest()),
 3983                window,
 3984                cx,
 3985                |s| {
 3986                    s.clear_disjoint();
 3987                    s.set_pending_anchor_range(
 3988                        pointer_position..pointer_position,
 3989                        SelectMode::Character,
 3990                    );
 3991                },
 3992            );
 3993        };
 3994
 3995        let tail = self.selections.newest::<Point>(&display_map).tail();
 3996        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3997        self.columnar_selection_state = match mode {
 3998            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3999                selection_tail: selection_anchor,
 4000                display_point: if reset {
 4001                    if position.column() != goal_column {
 4002                        Some(DisplayPoint::new(position.row(), goal_column))
 4003                    } else {
 4004                        None
 4005                    }
 4006                } else {
 4007                    None
 4008                },
 4009            }),
 4010            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4011                selection_tail: selection_anchor,
 4012            }),
 4013        };
 4014
 4015        if !reset {
 4016            self.select_columns(position, goal_column, &display_map, window, cx);
 4017        }
 4018    }
 4019
 4020    fn update_selection(
 4021        &mut self,
 4022        position: DisplayPoint,
 4023        goal_column: u32,
 4024        scroll_delta: gpui::Point<f32>,
 4025        window: &mut Window,
 4026        cx: &mut Context<Self>,
 4027    ) {
 4028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4029
 4030        if self.columnar_selection_state.is_some() {
 4031            self.select_columns(position, goal_column, &display_map, window, cx);
 4032        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4033            let buffer = display_map.buffer_snapshot();
 4034            let head;
 4035            let tail;
 4036            let mode = self.selections.pending_mode().unwrap();
 4037            match &mode {
 4038                SelectMode::Character => {
 4039                    head = position.to_point(&display_map);
 4040                    tail = pending.tail().to_point(buffer);
 4041                }
 4042                SelectMode::Word(original_range) => {
 4043                    let offset = display_map
 4044                        .clip_point(position, Bias::Left)
 4045                        .to_offset(&display_map, Bias::Left);
 4046                    let original_range = original_range.to_offset(buffer);
 4047
 4048                    let head_offset = if buffer.is_inside_word(offset, None)
 4049                        || original_range.contains(&offset)
 4050                    {
 4051                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4052                        if word_range.start < original_range.start {
 4053                            word_range.start
 4054                        } else {
 4055                            word_range.end
 4056                        }
 4057                    } else {
 4058                        offset
 4059                    };
 4060
 4061                    head = head_offset.to_point(buffer);
 4062                    if head_offset <= original_range.start {
 4063                        tail = original_range.end.to_point(buffer);
 4064                    } else {
 4065                        tail = original_range.start.to_point(buffer);
 4066                    }
 4067                }
 4068                SelectMode::Line(original_range) => {
 4069                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4070
 4071                    let position = display_map
 4072                        .clip_point(position, Bias::Left)
 4073                        .to_point(&display_map);
 4074                    let line_start = display_map.prev_line_boundary(position).0;
 4075                    let next_line_start = buffer.clip_point(
 4076                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4077                        Bias::Left,
 4078                    );
 4079
 4080                    if line_start < original_range.start {
 4081                        head = line_start
 4082                    } else {
 4083                        head = next_line_start
 4084                    }
 4085
 4086                    if head <= original_range.start {
 4087                        tail = original_range.end;
 4088                    } else {
 4089                        tail = original_range.start;
 4090                    }
 4091                }
 4092                SelectMode::All => {
 4093                    return;
 4094                }
 4095            };
 4096
 4097            if head < tail {
 4098                pending.start = buffer.anchor_before(head);
 4099                pending.end = buffer.anchor_before(tail);
 4100                pending.reversed = true;
 4101            } else {
 4102                pending.start = buffer.anchor_before(tail);
 4103                pending.end = buffer.anchor_before(head);
 4104                pending.reversed = false;
 4105            }
 4106
 4107            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4108                s.set_pending(pending.clone(), mode);
 4109            });
 4110        } else {
 4111            log::error!("update_selection dispatched with no pending selection");
 4112            return;
 4113        }
 4114
 4115        self.apply_scroll_delta(scroll_delta, window, cx);
 4116        cx.notify();
 4117    }
 4118
 4119    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4120        self.columnar_selection_state.take();
 4121        if let Some(pending_mode) = self.selections.pending_mode() {
 4122            let selections = self
 4123                .selections
 4124                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4125            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4126                s.select(selections);
 4127                s.clear_pending();
 4128                if s.is_extending() {
 4129                    s.set_is_extending(false);
 4130                } else {
 4131                    s.set_select_mode(pending_mode);
 4132                }
 4133            });
 4134        }
 4135    }
 4136
 4137    fn select_columns(
 4138        &mut self,
 4139        head: DisplayPoint,
 4140        goal_column: u32,
 4141        display_map: &DisplaySnapshot,
 4142        window: &mut Window,
 4143        cx: &mut Context<Self>,
 4144    ) {
 4145        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4146            return;
 4147        };
 4148
 4149        let tail = match columnar_state {
 4150            ColumnarSelectionState::FromMouse {
 4151                selection_tail,
 4152                display_point,
 4153            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4154            ColumnarSelectionState::FromSelection { selection_tail } => {
 4155                selection_tail.to_display_point(display_map)
 4156            }
 4157        };
 4158
 4159        let start_row = cmp::min(tail.row(), head.row());
 4160        let end_row = cmp::max(tail.row(), head.row());
 4161        let start_column = cmp::min(tail.column(), goal_column);
 4162        let end_column = cmp::max(tail.column(), goal_column);
 4163        let reversed = start_column < tail.column();
 4164
 4165        let selection_ranges = (start_row.0..=end_row.0)
 4166            .map(DisplayRow)
 4167            .filter_map(|row| {
 4168                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4169                    || start_column <= display_map.line_len(row))
 4170                    && !display_map.is_block_line(row)
 4171                {
 4172                    let start = display_map
 4173                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4174                        .to_point(display_map);
 4175                    let end = display_map
 4176                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4177                        .to_point(display_map);
 4178                    if reversed {
 4179                        Some(end..start)
 4180                    } else {
 4181                        Some(start..end)
 4182                    }
 4183                } else {
 4184                    None
 4185                }
 4186            })
 4187            .collect::<Vec<_>>();
 4188        if selection_ranges.is_empty() {
 4189            return;
 4190        }
 4191
 4192        let ranges = match columnar_state {
 4193            ColumnarSelectionState::FromMouse { .. } => {
 4194                let mut non_empty_ranges = selection_ranges
 4195                    .iter()
 4196                    .filter(|selection_range| selection_range.start != selection_range.end)
 4197                    .peekable();
 4198                if non_empty_ranges.peek().is_some() {
 4199                    non_empty_ranges.cloned().collect()
 4200                } else {
 4201                    selection_ranges
 4202                }
 4203            }
 4204            _ => selection_ranges,
 4205        };
 4206
 4207        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4208            s.select_ranges(ranges);
 4209        });
 4210        cx.notify();
 4211    }
 4212
 4213    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4214        self.selections
 4215            .all_adjusted(snapshot)
 4216            .iter()
 4217            .any(|selection| !selection.is_empty())
 4218    }
 4219
 4220    pub fn has_pending_nonempty_selection(&self) -> bool {
 4221        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4222            Some(Selection { start, end, .. }) => start != end,
 4223            None => false,
 4224        };
 4225
 4226        pending_nonempty_selection
 4227            || (self.columnar_selection_state.is_some()
 4228                && self.selections.disjoint_anchors().len() > 1)
 4229    }
 4230
 4231    pub fn has_pending_selection(&self) -> bool {
 4232        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4233    }
 4234
 4235    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4236        self.selection_mark_mode = false;
 4237        self.selection_drag_state = SelectionDragState::None;
 4238
 4239        if self.dismiss_menus_and_popups(true, window, cx) {
 4240            cx.notify();
 4241            return;
 4242        }
 4243        if self.clear_expanded_diff_hunks(cx) {
 4244            cx.notify();
 4245            return;
 4246        }
 4247        if self.show_git_blame_gutter {
 4248            self.show_git_blame_gutter = false;
 4249            cx.notify();
 4250            return;
 4251        }
 4252
 4253        if self.mode.is_full()
 4254            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4255        {
 4256            cx.notify();
 4257            return;
 4258        }
 4259
 4260        cx.propagate();
 4261    }
 4262
 4263    pub fn dismiss_menus_and_popups(
 4264        &mut self,
 4265        is_user_requested: bool,
 4266        window: &mut Window,
 4267        cx: &mut Context<Self>,
 4268    ) -> bool {
 4269        let mut dismissed = false;
 4270
 4271        dismissed |= self.take_rename(false, window, cx).is_some();
 4272        dismissed |= self.hide_blame_popover(true, cx);
 4273        dismissed |= hide_hover(self, cx);
 4274        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4275        dismissed |= self.hide_context_menu(window, cx).is_some();
 4276        dismissed |= self.mouse_context_menu.take().is_some();
 4277        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4278        dismissed |= self.snippet_stack.pop().is_some();
 4279
 4280        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4281            self.dismiss_diagnostics(cx);
 4282            dismissed = true;
 4283        }
 4284
 4285        dismissed
 4286    }
 4287
 4288    fn linked_editing_ranges_for(
 4289        &self,
 4290        selection: Range<text::Anchor>,
 4291        cx: &App,
 4292    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4293        if self.linked_edit_ranges.is_empty() {
 4294            return None;
 4295        }
 4296        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4297            selection.end.buffer_id.and_then(|end_buffer_id| {
 4298                if selection.start.buffer_id != Some(end_buffer_id) {
 4299                    return None;
 4300                }
 4301                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4302                let snapshot = buffer.read(cx).snapshot();
 4303                self.linked_edit_ranges
 4304                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4305                    .map(|ranges| (ranges, snapshot, buffer))
 4306            })?;
 4307        use text::ToOffset as TO;
 4308        // find offset from the start of current range to current cursor position
 4309        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4310
 4311        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4312        let start_difference = start_offset - start_byte_offset;
 4313        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4314        let end_difference = end_offset - start_byte_offset;
 4315        // Current range has associated linked ranges.
 4316        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4317        for range in linked_ranges.iter() {
 4318            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4319            let end_offset = start_offset + end_difference;
 4320            let start_offset = start_offset + start_difference;
 4321            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4322                continue;
 4323            }
 4324            if self.selections.disjoint_anchor_ranges().any(|s| {
 4325                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4326                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4327                {
 4328                    return false;
 4329                }
 4330                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4331                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4332            }) {
 4333                continue;
 4334            }
 4335            let start = buffer_snapshot.anchor_after(start_offset);
 4336            let end = buffer_snapshot.anchor_after(end_offset);
 4337            linked_edits
 4338                .entry(buffer.clone())
 4339                .or_default()
 4340                .push(start..end);
 4341        }
 4342        Some(linked_edits)
 4343    }
 4344
 4345    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4346        let text: Arc<str> = text.into();
 4347
 4348        if self.read_only(cx) {
 4349            return;
 4350        }
 4351
 4352        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4353
 4354        self.unfold_buffers_with_selections(cx);
 4355
 4356        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4357        let mut bracket_inserted = false;
 4358        let mut edits = Vec::new();
 4359        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4360        let mut new_selections = Vec::with_capacity(selections.len());
 4361        let mut new_autoclose_regions = Vec::new();
 4362        let snapshot = self.buffer.read(cx).read(cx);
 4363        let mut clear_linked_edit_ranges = false;
 4364        let mut all_selections_read_only = true;
 4365        let mut has_adjacent_edits = false;
 4366        let mut in_adjacent_group = false;
 4367
 4368        let mut regions = self
 4369            .selections_with_autoclose_regions(selections, &snapshot)
 4370            .peekable();
 4371
 4372        while let Some((selection, autoclose_region)) = regions.next() {
 4373            if snapshot
 4374                .point_to_buffer_point(selection.head())
 4375                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4376            {
 4377                continue;
 4378            }
 4379            if snapshot
 4380                .point_to_buffer_point(selection.tail())
 4381                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4382            {
 4383                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4384                continue;
 4385            }
 4386            all_selections_read_only = false;
 4387
 4388            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4389                // Determine if the inserted text matches the opening or closing
 4390                // bracket of any of this language's bracket pairs.
 4391                let mut bracket_pair = None;
 4392                let mut is_bracket_pair_start = false;
 4393                let mut is_bracket_pair_end = false;
 4394                if !text.is_empty() {
 4395                    let mut bracket_pair_matching_end = None;
 4396                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4397                    //  and they are removing the character that triggered IME popup.
 4398                    for (pair, enabled) in scope.brackets() {
 4399                        if !pair.close && !pair.surround {
 4400                            continue;
 4401                        }
 4402
 4403                        if enabled && pair.start.ends_with(text.as_ref()) {
 4404                            let prefix_len = pair.start.len() - text.len();
 4405                            let preceding_text_matches_prefix = prefix_len == 0
 4406                                || (selection.start.column >= (prefix_len as u32)
 4407                                    && snapshot.contains_str_at(
 4408                                        Point::new(
 4409                                            selection.start.row,
 4410                                            selection.start.column - (prefix_len as u32),
 4411                                        ),
 4412                                        &pair.start[..prefix_len],
 4413                                    ));
 4414                            if preceding_text_matches_prefix {
 4415                                bracket_pair = Some(pair.clone());
 4416                                is_bracket_pair_start = true;
 4417                                break;
 4418                            }
 4419                        }
 4420                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4421                        {
 4422                            // take first bracket pair matching end, but don't break in case a later bracket
 4423                            // pair matches start
 4424                            bracket_pair_matching_end = Some(pair.clone());
 4425                        }
 4426                    }
 4427                    if let Some(end) = bracket_pair_matching_end
 4428                        && bracket_pair.is_none()
 4429                    {
 4430                        bracket_pair = Some(end);
 4431                        is_bracket_pair_end = true;
 4432                    }
 4433                }
 4434
 4435                if let Some(bracket_pair) = bracket_pair {
 4436                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4437                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4438                    let auto_surround =
 4439                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4440                    if selection.is_empty() {
 4441                        if is_bracket_pair_start {
 4442                            // If the inserted text is a suffix of an opening bracket and the
 4443                            // selection is preceded by the rest of the opening bracket, then
 4444                            // insert the closing bracket.
 4445                            let following_text_allows_autoclose = snapshot
 4446                                .chars_at(selection.start)
 4447                                .next()
 4448                                .is_none_or(|c| scope.should_autoclose_before(c));
 4449
 4450                            let preceding_text_allows_autoclose = selection.start.column == 0
 4451                                || snapshot
 4452                                    .reversed_chars_at(selection.start)
 4453                                    .next()
 4454                                    .is_none_or(|c| {
 4455                                        bracket_pair.start != bracket_pair.end
 4456                                            || !snapshot
 4457                                                .char_classifier_at(selection.start)
 4458                                                .is_word(c)
 4459                                    });
 4460
 4461                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4462                                && bracket_pair.start.len() == 1
 4463                            {
 4464                                let target = bracket_pair.start.chars().next().unwrap();
 4465                                let mut byte_offset = 0u32;
 4466                                let current_line_count = snapshot
 4467                                    .reversed_chars_at(selection.start)
 4468                                    .take_while(|&c| c != '\n')
 4469                                    .filter(|c| {
 4470                                        byte_offset += c.len_utf8() as u32;
 4471                                        if *c != target {
 4472                                            return false;
 4473                                        }
 4474
 4475                                        let point = Point::new(
 4476                                            selection.start.row,
 4477                                            selection.start.column.saturating_sub(byte_offset),
 4478                                        );
 4479
 4480                                        let is_enabled = snapshot
 4481                                            .language_scope_at(point)
 4482                                            .and_then(|scope| {
 4483                                                scope
 4484                                                    .brackets()
 4485                                                    .find(|(pair, _)| {
 4486                                                        pair.start == bracket_pair.start
 4487                                                    })
 4488                                                    .map(|(_, enabled)| enabled)
 4489                                            })
 4490                                            .unwrap_or(true);
 4491
 4492                                        let is_delimiter = snapshot
 4493                                            .language_scope_at(Point::new(
 4494                                                point.row,
 4495                                                point.column + 1,
 4496                                            ))
 4497                                            .and_then(|scope| {
 4498                                                scope
 4499                                                    .brackets()
 4500                                                    .find(|(pair, _)| {
 4501                                                        pair.start == bracket_pair.start
 4502                                                    })
 4503                                                    .map(|(_, enabled)| !enabled)
 4504                                            })
 4505                                            .unwrap_or(false);
 4506
 4507                                        is_enabled && !is_delimiter
 4508                                    })
 4509                                    .count();
 4510                                current_line_count % 2 == 1
 4511                            } else {
 4512                                false
 4513                            };
 4514
 4515                            if autoclose
 4516                                && bracket_pair.close
 4517                                && following_text_allows_autoclose
 4518                                && preceding_text_allows_autoclose
 4519                                && !is_closing_quote
 4520                            {
 4521                                let anchor = snapshot.anchor_before(selection.end);
 4522                                new_selections.push((selection.map(|_| anchor), text.len()));
 4523                                new_autoclose_regions.push((
 4524                                    anchor,
 4525                                    text.len(),
 4526                                    selection.id,
 4527                                    bracket_pair.clone(),
 4528                                ));
 4529                                edits.push((
 4530                                    selection.range(),
 4531                                    format!("{}{}", text, bracket_pair.end).into(),
 4532                                ));
 4533                                bracket_inserted = true;
 4534                                continue;
 4535                            }
 4536                        }
 4537
 4538                        if let Some(region) = autoclose_region {
 4539                            // If the selection is followed by an auto-inserted closing bracket,
 4540                            // then don't insert that closing bracket again; just move the selection
 4541                            // past the closing bracket.
 4542                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4543                                && text.as_ref() == region.pair.end.as_str()
 4544                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4545                            if should_skip {
 4546                                let anchor = snapshot.anchor_after(selection.end);
 4547                                new_selections
 4548                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4549                                continue;
 4550                            }
 4551                        }
 4552
 4553                        let always_treat_brackets_as_autoclosed = snapshot
 4554                            .language_settings_at(selection.start, cx)
 4555                            .always_treat_brackets_as_autoclosed;
 4556                        if always_treat_brackets_as_autoclosed
 4557                            && is_bracket_pair_end
 4558                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4559                        {
 4560                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4561                            // and the inserted text is a closing bracket and the selection is followed
 4562                            // by the closing bracket then move the selection past the closing bracket.
 4563                            let anchor = snapshot.anchor_after(selection.end);
 4564                            new_selections.push((selection.map(|_| anchor), text.len()));
 4565                            continue;
 4566                        }
 4567                    }
 4568                    // If an opening bracket is 1 character long and is typed while
 4569                    // text is selected, then surround that text with the bracket pair.
 4570                    else if auto_surround
 4571                        && bracket_pair.surround
 4572                        && is_bracket_pair_start
 4573                        && bracket_pair.start.chars().count() == 1
 4574                    {
 4575                        edits.push((selection.start..selection.start, text.clone()));
 4576                        edits.push((
 4577                            selection.end..selection.end,
 4578                            bracket_pair.end.as_str().into(),
 4579                        ));
 4580                        bracket_inserted = true;
 4581                        new_selections.push((
 4582                            Selection {
 4583                                id: selection.id,
 4584                                start: snapshot.anchor_after(selection.start),
 4585                                end: snapshot.anchor_before(selection.end),
 4586                                reversed: selection.reversed,
 4587                                goal: selection.goal,
 4588                            },
 4589                            0,
 4590                        ));
 4591                        continue;
 4592                    }
 4593                }
 4594            }
 4595
 4596            if self.auto_replace_emoji_shortcode
 4597                && selection.is_empty()
 4598                && text.as_ref().ends_with(':')
 4599                && let Some(possible_emoji_short_code) =
 4600                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4601                && !possible_emoji_short_code.is_empty()
 4602                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4603            {
 4604                let emoji_shortcode_start = Point::new(
 4605                    selection.start.row,
 4606                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4607                );
 4608
 4609                // Remove shortcode from buffer
 4610                edits.push((
 4611                    emoji_shortcode_start..selection.start,
 4612                    "".to_string().into(),
 4613                ));
 4614                new_selections.push((
 4615                    Selection {
 4616                        id: selection.id,
 4617                        start: snapshot.anchor_after(emoji_shortcode_start),
 4618                        end: snapshot.anchor_before(selection.start),
 4619                        reversed: selection.reversed,
 4620                        goal: selection.goal,
 4621                    },
 4622                    0,
 4623                ));
 4624
 4625                // Insert emoji
 4626                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4627                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4628                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4629
 4630                continue;
 4631            }
 4632
 4633            let next_is_adjacent = regions
 4634                .peek()
 4635                .is_some_and(|(next, _)| selection.end == next.start);
 4636
 4637            // If not handling any auto-close operation, then just replace the selected
 4638            // text with the given input and move the selection to the end of the
 4639            // newly inserted text.
 4640            let anchor = if in_adjacent_group || next_is_adjacent {
 4641                // After edits the right bias would shift those anchor to the next visible fragment
 4642                // but we want to resolve to the previous one
 4643                snapshot.anchor_before(selection.end)
 4644            } else {
 4645                snapshot.anchor_after(selection.end)
 4646            };
 4647
 4648            if !self.linked_edit_ranges.is_empty() {
 4649                let start_anchor = snapshot.anchor_before(selection.start);
 4650
 4651                let is_word_char = text.chars().next().is_none_or(|char| {
 4652                    let classifier = snapshot
 4653                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4654                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4655                    classifier.is_word(char)
 4656                });
 4657
 4658                if is_word_char {
 4659                    if let Some(ranges) = self
 4660                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4661                    {
 4662                        for (buffer, edits) in ranges {
 4663                            linked_edits
 4664                                .entry(buffer.clone())
 4665                                .or_default()
 4666                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4667                        }
 4668                    }
 4669                } else {
 4670                    clear_linked_edit_ranges = true;
 4671                }
 4672            }
 4673
 4674            new_selections.push((selection.map(|_| anchor), 0));
 4675            edits.push((selection.start..selection.end, text.clone()));
 4676
 4677            has_adjacent_edits |= next_is_adjacent;
 4678            in_adjacent_group = next_is_adjacent;
 4679        }
 4680
 4681        if all_selections_read_only {
 4682            return;
 4683        }
 4684
 4685        drop(regions);
 4686        drop(snapshot);
 4687
 4688        self.transact(window, cx, |this, window, cx| {
 4689            if clear_linked_edit_ranges {
 4690                this.linked_edit_ranges.clear();
 4691            }
 4692            let initial_buffer_versions =
 4693                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4694
 4695            this.buffer.update(cx, |buffer, cx| {
 4696                if has_adjacent_edits {
 4697                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4698                } else {
 4699                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4700                }
 4701            });
 4702            for (buffer, edits) in linked_edits {
 4703                buffer.update(cx, |buffer, cx| {
 4704                    let snapshot = buffer.snapshot();
 4705                    let edits = edits
 4706                        .into_iter()
 4707                        .map(|(range, text)| {
 4708                            use text::ToPoint as TP;
 4709                            let end_point = TP::to_point(&range.end, &snapshot);
 4710                            let start_point = TP::to_point(&range.start, &snapshot);
 4711                            (start_point..end_point, text)
 4712                        })
 4713                        .sorted_by_key(|(range, _)| range.start);
 4714                    buffer.edit(edits, None, cx);
 4715                })
 4716            }
 4717            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4718            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4719            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4720            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4721                new_anchor_selections,
 4722                &map,
 4723            )
 4724            .zip(new_selection_deltas)
 4725            .map(|(selection, delta)| Selection {
 4726                id: selection.id,
 4727                start: selection.start + delta,
 4728                end: selection.end + delta,
 4729                reversed: selection.reversed,
 4730                goal: SelectionGoal::None,
 4731            })
 4732            .collect::<Vec<_>>();
 4733
 4734            let mut i = 0;
 4735            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4736                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4737                let start = map.buffer_snapshot().anchor_before(position);
 4738                let end = map.buffer_snapshot().anchor_after(position);
 4739                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4740                    match existing_state
 4741                        .range
 4742                        .start
 4743                        .cmp(&start, map.buffer_snapshot())
 4744                    {
 4745                        Ordering::Less => i += 1,
 4746                        Ordering::Greater => break,
 4747                        Ordering::Equal => {
 4748                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4749                                Ordering::Less => i += 1,
 4750                                Ordering::Equal => break,
 4751                                Ordering::Greater => break,
 4752                            }
 4753                        }
 4754                    }
 4755                }
 4756                this.autoclose_regions.insert(
 4757                    i,
 4758                    AutocloseRegion {
 4759                        selection_id,
 4760                        range: start..end,
 4761                        pair,
 4762                    },
 4763                );
 4764            }
 4765
 4766            let had_active_edit_prediction = this.has_active_edit_prediction();
 4767            this.change_selections(
 4768                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4769                window,
 4770                cx,
 4771                |s| s.select(new_selections),
 4772            );
 4773
 4774            if !bracket_inserted
 4775                && let Some(on_type_format_task) =
 4776                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4777            {
 4778                on_type_format_task.detach_and_log_err(cx);
 4779            }
 4780
 4781            let editor_settings = EditorSettings::get_global(cx);
 4782            if bracket_inserted
 4783                && (editor_settings.auto_signature_help
 4784                    || editor_settings.show_signature_help_after_edits)
 4785            {
 4786                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4787            }
 4788
 4789            let trigger_in_words =
 4790                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4791            if this.hard_wrap.is_some() {
 4792                let latest: Range<Point> = this.selections.newest(&map).range();
 4793                if latest.is_empty()
 4794                    && this
 4795                        .buffer()
 4796                        .read(cx)
 4797                        .snapshot(cx)
 4798                        .line_len(MultiBufferRow(latest.start.row))
 4799                        == latest.start.column
 4800                {
 4801                    this.rewrap_impl(
 4802                        RewrapOptions {
 4803                            override_language_settings: true,
 4804                            preserve_existing_whitespace: true,
 4805                        },
 4806                        cx,
 4807                    )
 4808                }
 4809            }
 4810            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4811            refresh_linked_ranges(this, window, cx);
 4812            this.refresh_edit_prediction(true, false, window, cx);
 4813            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4814        });
 4815    }
 4816
 4817    fn find_possible_emoji_shortcode_at_position(
 4818        snapshot: &MultiBufferSnapshot,
 4819        position: Point,
 4820    ) -> Option<String> {
 4821        let mut chars = Vec::new();
 4822        let mut found_colon = false;
 4823        for char in snapshot.reversed_chars_at(position).take(100) {
 4824            // Found a possible emoji shortcode in the middle of the buffer
 4825            if found_colon {
 4826                if char.is_whitespace() {
 4827                    chars.reverse();
 4828                    return Some(chars.iter().collect());
 4829                }
 4830                // If the previous character is not a whitespace, we are in the middle of a word
 4831                // and we only want to complete the shortcode if the word is made up of other emojis
 4832                let mut containing_word = String::new();
 4833                for ch in snapshot
 4834                    .reversed_chars_at(position)
 4835                    .skip(chars.len() + 1)
 4836                    .take(100)
 4837                {
 4838                    if ch.is_whitespace() {
 4839                        break;
 4840                    }
 4841                    containing_word.push(ch);
 4842                }
 4843                let containing_word = containing_word.chars().rev().collect::<String>();
 4844                if util::word_consists_of_emojis(containing_word.as_str()) {
 4845                    chars.reverse();
 4846                    return Some(chars.iter().collect());
 4847                }
 4848            }
 4849
 4850            if char.is_whitespace() || !char.is_ascii() {
 4851                return None;
 4852            }
 4853            if char == ':' {
 4854                found_colon = true;
 4855            } else {
 4856                chars.push(char);
 4857            }
 4858        }
 4859        // Found a possible emoji shortcode at the beginning of the buffer
 4860        chars.reverse();
 4861        Some(chars.iter().collect())
 4862    }
 4863
 4864    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4866        self.transact(window, cx, |this, window, cx| {
 4867            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4868                let selections = this
 4869                    .selections
 4870                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4871                let multi_buffer = this.buffer.read(cx);
 4872                let buffer = multi_buffer.snapshot(cx);
 4873                selections
 4874                    .iter()
 4875                    .map(|selection| {
 4876                        let start_point = selection.start.to_point(&buffer);
 4877                        let mut existing_indent =
 4878                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4879                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4880                        let start = selection.start;
 4881                        let end = selection.end;
 4882                        let selection_is_empty = start == end;
 4883                        let language_scope = buffer.language_scope_at(start);
 4884                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4885                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4886                                &buffer,
 4887                                start..end,
 4888                                language,
 4889                            )
 4890                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4891                                    &buffer,
 4892                                    start..end,
 4893                                );
 4894
 4895                            let mut newline_config = NewlineConfig::Newline {
 4896                                additional_indent: IndentSize::spaces(0),
 4897                                extra_line_additional_indent: if needs_extra_newline {
 4898                                    Some(IndentSize::spaces(0))
 4899                                } else {
 4900                                    None
 4901                                },
 4902                                prevent_auto_indent: false,
 4903                            };
 4904
 4905                            let comment_delimiter = maybe!({
 4906                                if !selection_is_empty {
 4907                                    return None;
 4908                                }
 4909
 4910                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4911                                    return None;
 4912                                }
 4913
 4914                                return comment_delimiter_for_newline(
 4915                                    &start_point,
 4916                                    &buffer,
 4917                                    language,
 4918                                );
 4919                            });
 4920
 4921                            let doc_delimiter = maybe!({
 4922                                if !selection_is_empty {
 4923                                    return None;
 4924                                }
 4925
 4926                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4927                                    return None;
 4928                                }
 4929
 4930                                return documentation_delimiter_for_newline(
 4931                                    &start_point,
 4932                                    &buffer,
 4933                                    language,
 4934                                    &mut newline_config,
 4935                                );
 4936                            });
 4937
 4938                            let list_delimiter = maybe!({
 4939                                if !selection_is_empty {
 4940                                    return None;
 4941                                }
 4942
 4943                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 4944                                    return None;
 4945                                }
 4946
 4947                                return list_delimiter_for_newline(
 4948                                    &start_point,
 4949                                    &buffer,
 4950                                    language,
 4951                                    &mut newline_config,
 4952                                );
 4953                            });
 4954
 4955                            (
 4956                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 4957                                newline_config,
 4958                            )
 4959                        } else {
 4960                            (
 4961                                None,
 4962                                NewlineConfig::Newline {
 4963                                    additional_indent: IndentSize::spaces(0),
 4964                                    extra_line_additional_indent: None,
 4965                                    prevent_auto_indent: false,
 4966                                },
 4967                            )
 4968                        };
 4969
 4970                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 4971                            NewlineConfig::ClearCurrentLine => {
 4972                                let row_start =
 4973                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4974                                (row_start, String::new(), false)
 4975                            }
 4976                            NewlineConfig::UnindentCurrentLine { continuation } => {
 4977                                let row_start =
 4978                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4979                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 4980                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 4981                                let reduced_indent =
 4982                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 4983                                let mut new_text = String::new();
 4984                                new_text.extend(reduced_indent.chars());
 4985                                new_text.push_str(continuation);
 4986                                (row_start, new_text, true)
 4987                            }
 4988                            NewlineConfig::Newline {
 4989                                additional_indent,
 4990                                extra_line_additional_indent,
 4991                                prevent_auto_indent,
 4992                            } => {
 4993                                let capacity_for_delimiter =
 4994                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 4995                                let extra_line_len = extra_line_additional_indent
 4996                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 4997                                    .unwrap_or(0);
 4998                                let mut new_text = String::with_capacity(
 4999                                    1 + capacity_for_delimiter
 5000                                        + existing_indent.len as usize
 5001                                        + additional_indent.len as usize
 5002                                        + extra_line_len,
 5003                                );
 5004                                new_text.push('\n');
 5005                                new_text.extend(existing_indent.chars());
 5006                                new_text.extend(additional_indent.chars());
 5007                                if let Some(delimiter) = &delimiter {
 5008                                    new_text.push_str(delimiter);
 5009                                }
 5010                                if let Some(extra_indent) = extra_line_additional_indent {
 5011                                    new_text.push('\n');
 5012                                    new_text.extend(existing_indent.chars());
 5013                                    new_text.extend(extra_indent.chars());
 5014                                }
 5015                                (start, new_text, *prevent_auto_indent)
 5016                            }
 5017                        };
 5018
 5019                        let anchor = buffer.anchor_after(end);
 5020                        let new_selection = selection.map(|_| anchor);
 5021                        (
 5022                            ((edit_start..end, new_text), prevent_auto_indent),
 5023                            (newline_config.has_extra_line(), new_selection),
 5024                        )
 5025                    })
 5026                    .unzip()
 5027            };
 5028
 5029            let mut auto_indent_edits = Vec::new();
 5030            let mut edits = Vec::new();
 5031            for (edit, prevent_auto_indent) in edits_with_flags {
 5032                if prevent_auto_indent {
 5033                    edits.push(edit);
 5034                } else {
 5035                    auto_indent_edits.push(edit);
 5036                }
 5037            }
 5038            if !edits.is_empty() {
 5039                this.edit(edits, cx);
 5040            }
 5041            if !auto_indent_edits.is_empty() {
 5042                this.edit_with_autoindent(auto_indent_edits, cx);
 5043            }
 5044
 5045            let buffer = this.buffer.read(cx).snapshot(cx);
 5046            let new_selections = selection_info
 5047                .into_iter()
 5048                .map(|(extra_newline_inserted, new_selection)| {
 5049                    let mut cursor = new_selection.end.to_point(&buffer);
 5050                    if extra_newline_inserted {
 5051                        cursor.row -= 1;
 5052                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5053                    }
 5054                    new_selection.map(|_| cursor)
 5055                })
 5056                .collect();
 5057
 5058            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5059            this.refresh_edit_prediction(true, false, window, cx);
 5060            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5061                task.detach_and_log_err(cx);
 5062            }
 5063        });
 5064    }
 5065
 5066    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5068
 5069        let buffer = self.buffer.read(cx);
 5070        let snapshot = buffer.snapshot(cx);
 5071
 5072        let mut edits = Vec::new();
 5073        let mut rows = Vec::new();
 5074
 5075        for (rows_inserted, selection) in self
 5076            .selections
 5077            .all_adjusted(&self.display_snapshot(cx))
 5078            .into_iter()
 5079            .enumerate()
 5080        {
 5081            let cursor = selection.head();
 5082            let row = cursor.row;
 5083
 5084            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5085
 5086            let newline = "\n".to_string();
 5087            edits.push((start_of_line..start_of_line, newline));
 5088
 5089            rows.push(row + rows_inserted as u32);
 5090        }
 5091
 5092        self.transact(window, cx, |editor, window, cx| {
 5093            editor.edit(edits, cx);
 5094
 5095            editor.change_selections(Default::default(), window, cx, |s| {
 5096                let mut index = 0;
 5097                s.move_cursors_with(|map, _, _| {
 5098                    let row = rows[index];
 5099                    index += 1;
 5100
 5101                    let point = Point::new(row, 0);
 5102                    let boundary = map.next_line_boundary(point).1;
 5103                    let clipped = map.clip_point(boundary, Bias::Left);
 5104
 5105                    (clipped, SelectionGoal::None)
 5106                });
 5107            });
 5108
 5109            let mut indent_edits = Vec::new();
 5110            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5111            for row in rows {
 5112                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5113                for (row, indent) in indents {
 5114                    if indent.len == 0 {
 5115                        continue;
 5116                    }
 5117
 5118                    let text = match indent.kind {
 5119                        IndentKind::Space => " ".repeat(indent.len as usize),
 5120                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5121                    };
 5122                    let point = Point::new(row.0, 0);
 5123                    indent_edits.push((point..point, text));
 5124                }
 5125            }
 5126            editor.edit(indent_edits, cx);
 5127            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5128                format.detach_and_log_err(cx);
 5129            }
 5130        });
 5131    }
 5132
 5133    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5135
 5136        let buffer = self.buffer.read(cx);
 5137        let snapshot = buffer.snapshot(cx);
 5138
 5139        let mut edits = Vec::new();
 5140        let mut rows = Vec::new();
 5141        let mut rows_inserted = 0;
 5142
 5143        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5144            let cursor = selection.head();
 5145            let row = cursor.row;
 5146
 5147            let point = Point::new(row + 1, 0);
 5148            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5149
 5150            let newline = "\n".to_string();
 5151            edits.push((start_of_line..start_of_line, newline));
 5152
 5153            rows_inserted += 1;
 5154            rows.push(row + rows_inserted);
 5155        }
 5156
 5157        self.transact(window, cx, |editor, window, cx| {
 5158            editor.edit(edits, cx);
 5159
 5160            editor.change_selections(Default::default(), window, cx, |s| {
 5161                let mut index = 0;
 5162                s.move_cursors_with(|map, _, _| {
 5163                    let row = rows[index];
 5164                    index += 1;
 5165
 5166                    let point = Point::new(row, 0);
 5167                    let boundary = map.next_line_boundary(point).1;
 5168                    let clipped = map.clip_point(boundary, Bias::Left);
 5169
 5170                    (clipped, SelectionGoal::None)
 5171                });
 5172            });
 5173
 5174            let mut indent_edits = Vec::new();
 5175            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5176            for row in rows {
 5177                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5178                for (row, indent) in indents {
 5179                    if indent.len == 0 {
 5180                        continue;
 5181                    }
 5182
 5183                    let text = match indent.kind {
 5184                        IndentKind::Space => " ".repeat(indent.len as usize),
 5185                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5186                    };
 5187                    let point = Point::new(row.0, 0);
 5188                    indent_edits.push((point..point, text));
 5189                }
 5190            }
 5191            editor.edit(indent_edits, cx);
 5192            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5193                format.detach_and_log_err(cx);
 5194            }
 5195        });
 5196    }
 5197
 5198    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5199        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5200            original_indent_columns: Vec::new(),
 5201        });
 5202        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5203    }
 5204
 5205    fn insert_with_autoindent_mode(
 5206        &mut self,
 5207        text: &str,
 5208        autoindent_mode: Option<AutoindentMode>,
 5209        window: &mut Window,
 5210        cx: &mut Context<Self>,
 5211    ) {
 5212        if self.read_only(cx) {
 5213            return;
 5214        }
 5215
 5216        let text: Arc<str> = text.into();
 5217        self.transact(window, cx, |this, window, cx| {
 5218            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5219            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5220                let anchors = {
 5221                    let snapshot = buffer.read(cx);
 5222                    old_selections
 5223                        .iter()
 5224                        .map(|s| {
 5225                            let anchor = snapshot.anchor_after(s.head());
 5226                            s.map(|_| anchor)
 5227                        })
 5228                        .collect::<Vec<_>>()
 5229                };
 5230                buffer.edit(
 5231                    old_selections
 5232                        .iter()
 5233                        .map(|s| (s.start..s.end, text.clone())),
 5234                    autoindent_mode,
 5235                    cx,
 5236                );
 5237                anchors
 5238            });
 5239
 5240            this.change_selections(Default::default(), window, cx, |s| {
 5241                s.select_anchors(selection_anchors);
 5242            });
 5243
 5244            cx.notify();
 5245        });
 5246    }
 5247
 5248    fn trigger_completion_on_input(
 5249        &mut self,
 5250        text: &str,
 5251        trigger_in_words: bool,
 5252        window: &mut Window,
 5253        cx: &mut Context<Self>,
 5254    ) {
 5255        let completions_source = self
 5256            .context_menu
 5257            .borrow()
 5258            .as_ref()
 5259            .and_then(|menu| match menu {
 5260                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5261                CodeContextMenu::CodeActions(_) => None,
 5262            });
 5263
 5264        match completions_source {
 5265            Some(CompletionsMenuSource::Words { .. }) => {
 5266                self.open_or_update_completions_menu(
 5267                    Some(CompletionsMenuSource::Words {
 5268                        ignore_threshold: false,
 5269                    }),
 5270                    None,
 5271                    trigger_in_words,
 5272                    window,
 5273                    cx,
 5274                );
 5275            }
 5276            _ => self.open_or_update_completions_menu(
 5277                None,
 5278                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5279                true,
 5280                window,
 5281                cx,
 5282            ),
 5283        }
 5284    }
 5285
 5286    /// If any empty selections is touching the start of its innermost containing autoclose
 5287    /// region, expand it to select the brackets.
 5288    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5289        let selections = self
 5290            .selections
 5291            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5292        let buffer = self.buffer.read(cx).read(cx);
 5293        let new_selections = self
 5294            .selections_with_autoclose_regions(selections, &buffer)
 5295            .map(|(mut selection, region)| {
 5296                if !selection.is_empty() {
 5297                    return selection;
 5298                }
 5299
 5300                if let Some(region) = region {
 5301                    let mut range = region.range.to_offset(&buffer);
 5302                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5303                        range.start -= region.pair.start.len();
 5304                        if buffer.contains_str_at(range.start, &region.pair.start)
 5305                            && buffer.contains_str_at(range.end, &region.pair.end)
 5306                        {
 5307                            range.end += region.pair.end.len();
 5308                            selection.start = range.start;
 5309                            selection.end = range.end;
 5310
 5311                            return selection;
 5312                        }
 5313                    }
 5314                }
 5315
 5316                let always_treat_brackets_as_autoclosed = buffer
 5317                    .language_settings_at(selection.start, cx)
 5318                    .always_treat_brackets_as_autoclosed;
 5319
 5320                if !always_treat_brackets_as_autoclosed {
 5321                    return selection;
 5322                }
 5323
 5324                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5325                    for (pair, enabled) in scope.brackets() {
 5326                        if !enabled || !pair.close {
 5327                            continue;
 5328                        }
 5329
 5330                        if buffer.contains_str_at(selection.start, &pair.end) {
 5331                            let pair_start_len = pair.start.len();
 5332                            if buffer.contains_str_at(
 5333                                selection.start.saturating_sub_usize(pair_start_len),
 5334                                &pair.start,
 5335                            ) {
 5336                                selection.start -= pair_start_len;
 5337                                selection.end += pair.end.len();
 5338
 5339                                return selection;
 5340                            }
 5341                        }
 5342                    }
 5343                }
 5344
 5345                selection
 5346            })
 5347            .collect();
 5348
 5349        drop(buffer);
 5350        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5351            selections.select(new_selections)
 5352        });
 5353    }
 5354
 5355    /// Iterate the given selections, and for each one, find the smallest surrounding
 5356    /// autoclose region. This uses the ordering of the selections and the autoclose
 5357    /// regions to avoid repeated comparisons.
 5358    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5359        &'a self,
 5360        selections: impl IntoIterator<Item = Selection<D>>,
 5361        buffer: &'a MultiBufferSnapshot,
 5362    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5363        let mut i = 0;
 5364        let mut regions = self.autoclose_regions.as_slice();
 5365        selections.into_iter().map(move |selection| {
 5366            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5367
 5368            let mut enclosing = None;
 5369            while let Some(pair_state) = regions.get(i) {
 5370                if pair_state.range.end.to_offset(buffer) < range.start {
 5371                    regions = &regions[i + 1..];
 5372                    i = 0;
 5373                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5374                    break;
 5375                } else {
 5376                    if pair_state.selection_id == selection.id {
 5377                        enclosing = Some(pair_state);
 5378                    }
 5379                    i += 1;
 5380                }
 5381            }
 5382
 5383            (selection, enclosing)
 5384        })
 5385    }
 5386
 5387    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5388    fn invalidate_autoclose_regions(
 5389        &mut self,
 5390        mut selections: &[Selection<Anchor>],
 5391        buffer: &MultiBufferSnapshot,
 5392    ) {
 5393        self.autoclose_regions.retain(|state| {
 5394            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5395                return false;
 5396            }
 5397
 5398            let mut i = 0;
 5399            while let Some(selection) = selections.get(i) {
 5400                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5401                    selections = &selections[1..];
 5402                    continue;
 5403                }
 5404                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5405                    break;
 5406                }
 5407                if selection.id == state.selection_id {
 5408                    return true;
 5409                } else {
 5410                    i += 1;
 5411                }
 5412            }
 5413            false
 5414        });
 5415    }
 5416
 5417    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5418        let offset = position.to_offset(buffer);
 5419        let (word_range, kind) =
 5420            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5421        if offset > word_range.start && kind == Some(CharKind::Word) {
 5422            Some(
 5423                buffer
 5424                    .text_for_range(word_range.start..offset)
 5425                    .collect::<String>(),
 5426            )
 5427        } else {
 5428            None
 5429        }
 5430    }
 5431
 5432    pub fn visible_excerpts(
 5433        &self,
 5434        lsp_related_only: bool,
 5435        cx: &mut Context<Editor>,
 5436    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5437        let project = self.project().cloned();
 5438        let multi_buffer = self.buffer().read(cx);
 5439        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5440        let multi_buffer_visible_start = self
 5441            .scroll_manager
 5442            .anchor()
 5443            .anchor
 5444            .to_point(&multi_buffer_snapshot);
 5445        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5446            multi_buffer_visible_start
 5447                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5448            Bias::Left,
 5449        );
 5450        multi_buffer_snapshot
 5451            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5452            .into_iter()
 5453            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5454            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5455                if !lsp_related_only {
 5456                    return Some((
 5457                        excerpt_id,
 5458                        (
 5459                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5460                            buffer.version().clone(),
 5461                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5462                        ),
 5463                    ));
 5464                }
 5465
 5466                let project = project.as_ref()?.read(cx);
 5467                let buffer_file = project::File::from_dyn(buffer.file())?;
 5468                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5469                let worktree_entry = buffer_worktree
 5470                    .read(cx)
 5471                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5472                if worktree_entry.is_ignored {
 5473                    None
 5474                } else {
 5475                    Some((
 5476                        excerpt_id,
 5477                        (
 5478                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5479                            buffer.version().clone(),
 5480                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5481                        ),
 5482                    ))
 5483                }
 5484            })
 5485            .collect()
 5486    }
 5487
 5488    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5489        TextLayoutDetails {
 5490            text_system: window.text_system().clone(),
 5491            editor_style: self.style.clone().unwrap(),
 5492            rem_size: window.rem_size(),
 5493            scroll_anchor: self.scroll_manager.anchor(),
 5494            visible_rows: self.visible_line_count(),
 5495            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5496        }
 5497    }
 5498
 5499    fn trigger_on_type_formatting(
 5500        &self,
 5501        input: String,
 5502        window: &mut Window,
 5503        cx: &mut Context<Self>,
 5504    ) -> Option<Task<Result<()>>> {
 5505        if input.chars().count() != 1 {
 5506            return None;
 5507        }
 5508
 5509        let project = self.project()?;
 5510        let position = self.selections.newest_anchor().head();
 5511        let (buffer, buffer_position) = self
 5512            .buffer
 5513            .read(cx)
 5514            .text_anchor_for_position(position, cx)?;
 5515
 5516        let settings = language_settings::language_settings(
 5517            buffer
 5518                .read(cx)
 5519                .language_at(buffer_position)
 5520                .map(|l| l.name()),
 5521            buffer.read(cx).file(),
 5522            cx,
 5523        );
 5524        if !settings.use_on_type_format {
 5525            return None;
 5526        }
 5527
 5528        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5529        // hence we do LSP request & edit on host side only — add formats to host's history.
 5530        let push_to_lsp_host_history = true;
 5531        // If this is not the host, append its history with new edits.
 5532        let push_to_client_history = project.read(cx).is_via_collab();
 5533
 5534        let on_type_formatting = project.update(cx, |project, cx| {
 5535            project.on_type_format(
 5536                buffer.clone(),
 5537                buffer_position,
 5538                input,
 5539                push_to_lsp_host_history,
 5540                cx,
 5541            )
 5542        });
 5543        Some(cx.spawn_in(window, async move |editor, cx| {
 5544            if let Some(transaction) = on_type_formatting.await? {
 5545                if push_to_client_history {
 5546                    buffer.update(cx, |buffer, _| {
 5547                        buffer.push_transaction(transaction, Instant::now());
 5548                        buffer.finalize_last_transaction();
 5549                    });
 5550                }
 5551                editor.update(cx, |editor, cx| {
 5552                    editor.refresh_document_highlights(cx);
 5553                })?;
 5554            }
 5555            Ok(())
 5556        }))
 5557    }
 5558
 5559    pub fn show_word_completions(
 5560        &mut self,
 5561        _: &ShowWordCompletions,
 5562        window: &mut Window,
 5563        cx: &mut Context<Self>,
 5564    ) {
 5565        self.open_or_update_completions_menu(
 5566            Some(CompletionsMenuSource::Words {
 5567                ignore_threshold: true,
 5568            }),
 5569            None,
 5570            false,
 5571            window,
 5572            cx,
 5573        );
 5574    }
 5575
 5576    pub fn show_completions(
 5577        &mut self,
 5578        _: &ShowCompletions,
 5579        window: &mut Window,
 5580        cx: &mut Context<Self>,
 5581    ) {
 5582        self.open_or_update_completions_menu(None, None, false, window, cx);
 5583    }
 5584
 5585    fn open_or_update_completions_menu(
 5586        &mut self,
 5587        requested_source: Option<CompletionsMenuSource>,
 5588        trigger: Option<String>,
 5589        trigger_in_words: bool,
 5590        window: &mut Window,
 5591        cx: &mut Context<Self>,
 5592    ) {
 5593        if self.pending_rename.is_some() {
 5594            return;
 5595        }
 5596
 5597        let completions_source = self
 5598            .context_menu
 5599            .borrow()
 5600            .as_ref()
 5601            .and_then(|menu| match menu {
 5602                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5603                CodeContextMenu::CodeActions(_) => None,
 5604            });
 5605
 5606        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5607
 5608        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5609        // inserted and selected. To handle that case, the start of the selection is used so that
 5610        // the menu starts with all choices.
 5611        let position = self
 5612            .selections
 5613            .newest_anchor()
 5614            .start
 5615            .bias_right(&multibuffer_snapshot);
 5616        if position.diff_base_anchor.is_some() {
 5617            return;
 5618        }
 5619        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5620        let Some(buffer) = buffer_position
 5621            .text_anchor
 5622            .buffer_id
 5623            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5624        else {
 5625            return;
 5626        };
 5627        let buffer_snapshot = buffer.read(cx).snapshot();
 5628
 5629        let menu_is_open = matches!(
 5630            self.context_menu.borrow().as_ref(),
 5631            Some(CodeContextMenu::Completions(_))
 5632        );
 5633
 5634        let language = buffer_snapshot
 5635            .language_at(buffer_position.text_anchor)
 5636            .map(|language| language.name());
 5637
 5638        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5639        let completion_settings = language_settings.completions.clone();
 5640
 5641        let show_completions_on_input = self
 5642            .show_completions_on_input_override
 5643            .unwrap_or(language_settings.show_completions_on_input);
 5644        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5645            return;
 5646        }
 5647
 5648        let query: Option<Arc<String>> =
 5649            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5650                .map(|query| query.into());
 5651
 5652        drop(multibuffer_snapshot);
 5653
 5654        // Hide the current completions menu when query is empty. Without this, cached
 5655        // completions from before the trigger char may be reused (#32774).
 5656        if query.is_none() && menu_is_open {
 5657            self.hide_context_menu(window, cx);
 5658        }
 5659
 5660        let mut ignore_word_threshold = false;
 5661        let provider = match requested_source {
 5662            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5663            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5664                ignore_word_threshold = ignore_threshold;
 5665                None
 5666            }
 5667            Some(CompletionsMenuSource::SnippetChoices)
 5668            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5669                log::error!("bug: SnippetChoices requested_source is not handled");
 5670                None
 5671            }
 5672        };
 5673
 5674        let sort_completions = provider
 5675            .as_ref()
 5676            .is_some_and(|provider| provider.sort_completions());
 5677
 5678        let filter_completions = provider
 5679            .as_ref()
 5680            .is_none_or(|provider| provider.filter_completions());
 5681
 5682        let was_snippets_only = matches!(
 5683            completions_source,
 5684            Some(CompletionsMenuSource::SnippetsOnly)
 5685        );
 5686
 5687        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5688            if filter_completions {
 5689                menu.filter(
 5690                    query.clone().unwrap_or_default(),
 5691                    buffer_position.text_anchor,
 5692                    &buffer,
 5693                    provider.clone(),
 5694                    window,
 5695                    cx,
 5696                );
 5697            }
 5698            // When `is_incomplete` is false, no need to re-query completions when the current query
 5699            // is a suffix of the initial query.
 5700            let was_complete = !menu.is_incomplete;
 5701            if was_complete && !was_snippets_only {
 5702                // If the new query is a suffix of the old query (typing more characters) and
 5703                // the previous result was complete, the existing completions can be filtered.
 5704                //
 5705                // Note that snippet completions are always complete.
 5706                let query_matches = match (&menu.initial_query, &query) {
 5707                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5708                    (None, _) => true,
 5709                    _ => false,
 5710                };
 5711                if query_matches {
 5712                    let position_matches = if menu.initial_position == position {
 5713                        true
 5714                    } else {
 5715                        let snapshot = self.buffer.read(cx).read(cx);
 5716                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5717                    };
 5718                    if position_matches {
 5719                        return;
 5720                    }
 5721                }
 5722            }
 5723        };
 5724
 5725        let Anchor {
 5726            excerpt_id: buffer_excerpt_id,
 5727            text_anchor: buffer_position,
 5728            ..
 5729        } = buffer_position;
 5730
 5731        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5732            buffer_snapshot.surrounding_word(buffer_position, None)
 5733        {
 5734            let word_to_exclude = buffer_snapshot
 5735                .text_for_range(word_range.clone())
 5736                .collect::<String>();
 5737            (
 5738                buffer_snapshot.anchor_before(word_range.start)
 5739                    ..buffer_snapshot.anchor_after(buffer_position),
 5740                Some(word_to_exclude),
 5741            )
 5742        } else {
 5743            (buffer_position..buffer_position, None)
 5744        };
 5745
 5746        let show_completion_documentation = buffer_snapshot
 5747            .settings_at(buffer_position, cx)
 5748            .show_completion_documentation;
 5749
 5750        // The document can be large, so stay in reasonable bounds when searching for words,
 5751        // otherwise completion pop-up might be slow to appear.
 5752        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5753        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5754        let min_word_search = buffer_snapshot.clip_point(
 5755            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5756            Bias::Left,
 5757        );
 5758        let max_word_search = buffer_snapshot.clip_point(
 5759            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5760            Bias::Right,
 5761        );
 5762        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5763            ..buffer_snapshot.point_to_offset(max_word_search);
 5764
 5765        let skip_digits = query
 5766            .as_ref()
 5767            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5768
 5769        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5770            trigger.as_ref().is_none_or(|trigger| {
 5771                provider.is_completion_trigger(
 5772                    &buffer,
 5773                    position.text_anchor,
 5774                    trigger,
 5775                    trigger_in_words,
 5776                    cx,
 5777                )
 5778            })
 5779        });
 5780
 5781        let provider_responses = if let Some(provider) = &provider
 5782            && load_provider_completions
 5783        {
 5784            let trigger_character =
 5785                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5786            let completion_context = CompletionContext {
 5787                trigger_kind: match &trigger_character {
 5788                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5789                    None => CompletionTriggerKind::INVOKED,
 5790                },
 5791                trigger_character,
 5792            };
 5793
 5794            provider.completions(
 5795                buffer_excerpt_id,
 5796                &buffer,
 5797                buffer_position,
 5798                completion_context,
 5799                window,
 5800                cx,
 5801            )
 5802        } else {
 5803            Task::ready(Ok(Vec::new()))
 5804        };
 5805
 5806        let load_word_completions = if !self.word_completions_enabled {
 5807            false
 5808        } else if requested_source
 5809            == Some(CompletionsMenuSource::Words {
 5810                ignore_threshold: true,
 5811            })
 5812        {
 5813            true
 5814        } else {
 5815            load_provider_completions
 5816                && completion_settings.words != WordsCompletionMode::Disabled
 5817                && (ignore_word_threshold || {
 5818                    let words_min_length = completion_settings.words_min_length;
 5819                    // check whether word has at least `words_min_length` characters
 5820                    let query_chars = query.iter().flat_map(|q| q.chars());
 5821                    query_chars.take(words_min_length).count() == words_min_length
 5822                })
 5823        };
 5824
 5825        let mut words = if load_word_completions {
 5826            cx.background_spawn({
 5827                let buffer_snapshot = buffer_snapshot.clone();
 5828                async move {
 5829                    buffer_snapshot.words_in_range(WordsQuery {
 5830                        fuzzy_contents: None,
 5831                        range: word_search_range,
 5832                        skip_digits,
 5833                    })
 5834                }
 5835            })
 5836        } else {
 5837            Task::ready(BTreeMap::default())
 5838        };
 5839
 5840        let snippets = if let Some(provider) = &provider
 5841            && provider.show_snippets()
 5842            && let Some(project) = self.project()
 5843        {
 5844            let char_classifier = buffer_snapshot
 5845                .char_classifier_at(buffer_position)
 5846                .scope_context(Some(CharScopeContext::Completion));
 5847            project.update(cx, |project, cx| {
 5848                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5849            })
 5850        } else {
 5851            Task::ready(Ok(CompletionResponse {
 5852                completions: Vec::new(),
 5853                display_options: Default::default(),
 5854                is_incomplete: false,
 5855            }))
 5856        };
 5857
 5858        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5859
 5860        let id = post_inc(&mut self.next_completion_id);
 5861        let task = cx.spawn_in(window, async move |editor, cx| {
 5862            let Ok(()) = editor.update(cx, |this, _| {
 5863                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5864            }) else {
 5865                return;
 5866            };
 5867
 5868            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5869            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5870            let mut completions = Vec::new();
 5871            let mut is_incomplete = false;
 5872            let mut display_options: Option<CompletionDisplayOptions> = None;
 5873            if let Some(provider_responses) = provider_responses.await.log_err()
 5874                && !provider_responses.is_empty()
 5875            {
 5876                for response in provider_responses {
 5877                    completions.extend(response.completions);
 5878                    is_incomplete = is_incomplete || response.is_incomplete;
 5879                    match display_options.as_mut() {
 5880                        None => {
 5881                            display_options = Some(response.display_options);
 5882                        }
 5883                        Some(options) => options.merge(&response.display_options),
 5884                    }
 5885                }
 5886                if completion_settings.words == WordsCompletionMode::Fallback {
 5887                    words = Task::ready(BTreeMap::default());
 5888                }
 5889            }
 5890            let display_options = display_options.unwrap_or_default();
 5891
 5892            let mut words = words.await;
 5893            if let Some(word_to_exclude) = &word_to_exclude {
 5894                words.remove(word_to_exclude);
 5895            }
 5896            for lsp_completion in &completions {
 5897                words.remove(&lsp_completion.new_text);
 5898            }
 5899            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5900                replace_range: word_replace_range.clone(),
 5901                new_text: word.clone(),
 5902                label: CodeLabel::plain(word, None),
 5903                match_start: None,
 5904                snippet_deduplication_key: None,
 5905                icon_path: None,
 5906                documentation: None,
 5907                source: CompletionSource::BufferWord {
 5908                    word_range,
 5909                    resolved: false,
 5910                },
 5911                insert_text_mode: Some(InsertTextMode::AS_IS),
 5912                confirm: None,
 5913            }));
 5914
 5915            completions.extend(
 5916                snippets
 5917                    .await
 5918                    .into_iter()
 5919                    .flat_map(|response| response.completions),
 5920            );
 5921
 5922            let menu = if completions.is_empty() {
 5923                None
 5924            } else {
 5925                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5926                    let languages = editor
 5927                        .workspace
 5928                        .as_ref()
 5929                        .and_then(|(workspace, _)| workspace.upgrade())
 5930                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5931                    let menu = CompletionsMenu::new(
 5932                        id,
 5933                        requested_source.unwrap_or(if load_provider_completions {
 5934                            CompletionsMenuSource::Normal
 5935                        } else {
 5936                            CompletionsMenuSource::SnippetsOnly
 5937                        }),
 5938                        sort_completions,
 5939                        show_completion_documentation,
 5940                        position,
 5941                        query.clone(),
 5942                        is_incomplete,
 5943                        buffer.clone(),
 5944                        completions.into(),
 5945                        editor
 5946                            .context_menu()
 5947                            .borrow_mut()
 5948                            .as_ref()
 5949                            .map(|menu| menu.primary_scroll_handle()),
 5950                        display_options,
 5951                        snippet_sort_order,
 5952                        languages,
 5953                        language,
 5954                        cx,
 5955                    );
 5956
 5957                    let query = if filter_completions { query } else { None };
 5958                    let matches_task = menu.do_async_filtering(
 5959                        query.unwrap_or_default(),
 5960                        buffer_position,
 5961                        &buffer,
 5962                        cx,
 5963                    );
 5964                    (menu, matches_task)
 5965                }) else {
 5966                    return;
 5967                };
 5968
 5969                let matches = matches_task.await;
 5970
 5971                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5972                    // Newer menu already set, so exit.
 5973                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5974                        editor.context_menu.borrow().as_ref()
 5975                        && prev_menu.id > id
 5976                    {
 5977                        return;
 5978                    };
 5979
 5980                    // Only valid to take prev_menu because either the new menu is immediately set
 5981                    // below, or the menu is hidden.
 5982                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5983                        editor.context_menu.borrow_mut().take()
 5984                    {
 5985                        let position_matches =
 5986                            if prev_menu.initial_position == menu.initial_position {
 5987                                true
 5988                            } else {
 5989                                let snapshot = editor.buffer.read(cx).read(cx);
 5990                                prev_menu.initial_position.to_offset(&snapshot)
 5991                                    == menu.initial_position.to_offset(&snapshot)
 5992                            };
 5993                        if position_matches {
 5994                            // Preserve markdown cache before `set_filter_results` because it will
 5995                            // try to populate the documentation cache.
 5996                            menu.preserve_markdown_cache(prev_menu);
 5997                        }
 5998                    };
 5999
 6000                    menu.set_filter_results(matches, provider, window, cx);
 6001                }) else {
 6002                    return;
 6003                };
 6004
 6005                menu.visible().then_some(menu)
 6006            };
 6007
 6008            editor
 6009                .update_in(cx, |editor, window, cx| {
 6010                    if editor.focus_handle.is_focused(window)
 6011                        && let Some(menu) = menu
 6012                    {
 6013                        *editor.context_menu.borrow_mut() =
 6014                            Some(CodeContextMenu::Completions(menu));
 6015
 6016                        crate::hover_popover::hide_hover(editor, cx);
 6017                        if editor.show_edit_predictions_in_menu() {
 6018                            editor.update_visible_edit_prediction(window, cx);
 6019                        } else {
 6020                            editor.discard_edit_prediction(false, cx);
 6021                        }
 6022
 6023                        cx.notify();
 6024                        return;
 6025                    }
 6026
 6027                    if editor.completion_tasks.len() <= 1 {
 6028                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6029                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6030                        // If it was already hidden and we don't show edit predictions in the menu,
 6031                        // we should also show the edit prediction when available.
 6032                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6033                            editor.update_visible_edit_prediction(window, cx);
 6034                        }
 6035                    }
 6036                })
 6037                .ok();
 6038        });
 6039
 6040        self.completion_tasks.push((id, task));
 6041    }
 6042
 6043    #[cfg(feature = "test-support")]
 6044    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6045        let menu = self.context_menu.borrow();
 6046        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6047            let completions = menu.completions.borrow();
 6048            Some(completions.to_vec())
 6049        } else {
 6050            None
 6051        }
 6052    }
 6053
 6054    pub fn with_completions_menu_matching_id<R>(
 6055        &self,
 6056        id: CompletionId,
 6057        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6058    ) -> R {
 6059        let mut context_menu = self.context_menu.borrow_mut();
 6060        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6061            return f(None);
 6062        };
 6063        if completions_menu.id != id {
 6064            return f(None);
 6065        }
 6066        f(Some(completions_menu))
 6067    }
 6068
 6069    pub fn confirm_completion(
 6070        &mut self,
 6071        action: &ConfirmCompletion,
 6072        window: &mut Window,
 6073        cx: &mut Context<Self>,
 6074    ) -> Option<Task<Result<()>>> {
 6075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6076        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6077    }
 6078
 6079    pub fn confirm_completion_insert(
 6080        &mut self,
 6081        _: &ConfirmCompletionInsert,
 6082        window: &mut Window,
 6083        cx: &mut Context<Self>,
 6084    ) -> Option<Task<Result<()>>> {
 6085        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6086        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6087    }
 6088
 6089    pub fn confirm_completion_replace(
 6090        &mut self,
 6091        _: &ConfirmCompletionReplace,
 6092        window: &mut Window,
 6093        cx: &mut Context<Self>,
 6094    ) -> Option<Task<Result<()>>> {
 6095        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6096        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6097    }
 6098
 6099    pub fn compose_completion(
 6100        &mut self,
 6101        action: &ComposeCompletion,
 6102        window: &mut Window,
 6103        cx: &mut Context<Self>,
 6104    ) -> Option<Task<Result<()>>> {
 6105        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6106        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6107    }
 6108
 6109    fn do_completion(
 6110        &mut self,
 6111        item_ix: Option<usize>,
 6112        intent: CompletionIntent,
 6113        window: &mut Window,
 6114        cx: &mut Context<Editor>,
 6115    ) -> Option<Task<Result<()>>> {
 6116        use language::ToOffset as _;
 6117
 6118        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6119        else {
 6120            return None;
 6121        };
 6122
 6123        let candidate_id = {
 6124            let entries = completions_menu.entries.borrow();
 6125            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6126            if self.show_edit_predictions_in_menu() {
 6127                self.discard_edit_prediction(true, cx);
 6128            }
 6129            mat.candidate_id
 6130        };
 6131
 6132        let completion = completions_menu
 6133            .completions
 6134            .borrow()
 6135            .get(candidate_id)?
 6136            .clone();
 6137        cx.stop_propagation();
 6138
 6139        let buffer_handle = completions_menu.buffer.clone();
 6140
 6141        let CompletionEdit {
 6142            new_text,
 6143            snippet,
 6144            replace_range,
 6145        } = process_completion_for_edit(
 6146            &completion,
 6147            intent,
 6148            &buffer_handle,
 6149            &completions_menu.initial_position.text_anchor,
 6150            cx,
 6151        );
 6152
 6153        let buffer = buffer_handle.read(cx);
 6154        let snapshot = self.buffer.read(cx).snapshot(cx);
 6155        let newest_anchor = self.selections.newest_anchor();
 6156        let replace_range_multibuffer = {
 6157            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6158            excerpt.map_range_from_buffer(replace_range.clone())
 6159        };
 6160        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6161            return None;
 6162        }
 6163
 6164        let old_text = buffer
 6165            .text_for_range(replace_range.clone())
 6166            .collect::<String>();
 6167        let lookbehind = newest_anchor
 6168            .start
 6169            .text_anchor
 6170            .to_offset(buffer)
 6171            .saturating_sub(replace_range.start.0);
 6172        let lookahead = replace_range
 6173            .end
 6174            .0
 6175            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6176        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6177        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6178
 6179        let selections = self
 6180            .selections
 6181            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6182        let mut ranges = Vec::new();
 6183        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6184
 6185        for selection in &selections {
 6186            let range = if selection.id == newest_anchor.id {
 6187                replace_range_multibuffer.clone()
 6188            } else {
 6189                let mut range = selection.range();
 6190
 6191                // if prefix is present, don't duplicate it
 6192                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6193                    range.start = range.start.saturating_sub_usize(lookbehind);
 6194
 6195                    // if suffix is also present, mimic the newest cursor and replace it
 6196                    if selection.id != newest_anchor.id
 6197                        && snapshot.contains_str_at(range.end, suffix)
 6198                    {
 6199                        range.end += lookahead;
 6200                    }
 6201                }
 6202                range
 6203            };
 6204
 6205            ranges.push(range.clone());
 6206
 6207            if !self.linked_edit_ranges.is_empty() {
 6208                let start_anchor = snapshot.anchor_before(range.start);
 6209                let end_anchor = snapshot.anchor_after(range.end);
 6210                if let Some(ranges) = self
 6211                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6212                {
 6213                    for (buffer, edits) in ranges {
 6214                        linked_edits
 6215                            .entry(buffer.clone())
 6216                            .or_default()
 6217                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6218                    }
 6219                }
 6220            }
 6221        }
 6222
 6223        let common_prefix_len = old_text
 6224            .chars()
 6225            .zip(new_text.chars())
 6226            .take_while(|(a, b)| a == b)
 6227            .map(|(a, _)| a.len_utf8())
 6228            .sum::<usize>();
 6229
 6230        cx.emit(EditorEvent::InputHandled {
 6231            utf16_range_to_replace: None,
 6232            text: new_text[common_prefix_len..].into(),
 6233        });
 6234
 6235        self.transact(window, cx, |editor, window, cx| {
 6236            if let Some(mut snippet) = snippet {
 6237                snippet.text = new_text.to_string();
 6238                editor
 6239                    .insert_snippet(&ranges, snippet, window, cx)
 6240                    .log_err();
 6241            } else {
 6242                editor.buffer.update(cx, |multi_buffer, cx| {
 6243                    let auto_indent = match completion.insert_text_mode {
 6244                        Some(InsertTextMode::AS_IS) => None,
 6245                        _ => editor.autoindent_mode.clone(),
 6246                    };
 6247                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6248                    multi_buffer.edit(edits, auto_indent, cx);
 6249                });
 6250            }
 6251            for (buffer, edits) in linked_edits {
 6252                buffer.update(cx, |buffer, cx| {
 6253                    let snapshot = buffer.snapshot();
 6254                    let edits = edits
 6255                        .into_iter()
 6256                        .map(|(range, text)| {
 6257                            use text::ToPoint as TP;
 6258                            let end_point = TP::to_point(&range.end, &snapshot);
 6259                            let start_point = TP::to_point(&range.start, &snapshot);
 6260                            (start_point..end_point, text)
 6261                        })
 6262                        .sorted_by_key(|(range, _)| range.start);
 6263                    buffer.edit(edits, None, cx);
 6264                })
 6265            }
 6266
 6267            editor.refresh_edit_prediction(true, false, window, cx);
 6268        });
 6269        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6270
 6271        let show_new_completions_on_confirm = completion
 6272            .confirm
 6273            .as_ref()
 6274            .is_some_and(|confirm| confirm(intent, window, cx));
 6275        if show_new_completions_on_confirm {
 6276            self.open_or_update_completions_menu(None, None, false, window, cx);
 6277        }
 6278
 6279        let provider = self.completion_provider.as_ref()?;
 6280
 6281        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6282        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6283            let CompletionSource::Lsp {
 6284                lsp_completion,
 6285                server_id,
 6286                ..
 6287            } = &completion.source
 6288            else {
 6289                return None;
 6290            };
 6291            let lsp_command = lsp_completion.command.as_ref()?;
 6292            let available_commands = lsp_store
 6293                .read(cx)
 6294                .lsp_server_capabilities
 6295                .get(server_id)
 6296                .and_then(|server_capabilities| {
 6297                    server_capabilities
 6298                        .execute_command_provider
 6299                        .as_ref()
 6300                        .map(|options| options.commands.as_slice())
 6301                })?;
 6302            if available_commands.contains(&lsp_command.command) {
 6303                Some(CodeAction {
 6304                    server_id: *server_id,
 6305                    range: language::Anchor::MIN..language::Anchor::MIN,
 6306                    lsp_action: LspAction::Command(lsp_command.clone()),
 6307                    resolved: false,
 6308                })
 6309            } else {
 6310                None
 6311            }
 6312        });
 6313
 6314        drop(completion);
 6315        let apply_edits = provider.apply_additional_edits_for_completion(
 6316            buffer_handle.clone(),
 6317            completions_menu.completions.clone(),
 6318            candidate_id,
 6319            true,
 6320            cx,
 6321        );
 6322
 6323        let editor_settings = EditorSettings::get_global(cx);
 6324        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6325            // After the code completion is finished, users often want to know what signatures are needed.
 6326            // so we should automatically call signature_help
 6327            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6328        }
 6329
 6330        Some(cx.spawn_in(window, async move |editor, cx| {
 6331            apply_edits.await?;
 6332
 6333            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6334                let title = command.lsp_action.title().to_owned();
 6335                let project_transaction = lsp_store
 6336                    .update(cx, |lsp_store, cx| {
 6337                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6338                    })
 6339                    .await
 6340                    .context("applying post-completion command")?;
 6341                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6342                    Self::open_project_transaction(
 6343                        &editor,
 6344                        workspace.downgrade(),
 6345                        project_transaction,
 6346                        title,
 6347                        cx,
 6348                    )
 6349                    .await?;
 6350                }
 6351            }
 6352
 6353            Ok(())
 6354        }))
 6355    }
 6356
 6357    pub fn toggle_code_actions(
 6358        &mut self,
 6359        action: &ToggleCodeActions,
 6360        window: &mut Window,
 6361        cx: &mut Context<Self>,
 6362    ) {
 6363        let quick_launch = action.quick_launch;
 6364        let mut context_menu = self.context_menu.borrow_mut();
 6365        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6366            if code_actions.deployed_from == action.deployed_from {
 6367                // Toggle if we're selecting the same one
 6368                *context_menu = None;
 6369                cx.notify();
 6370                return;
 6371            } else {
 6372                // Otherwise, clear it and start a new one
 6373                *context_menu = None;
 6374                cx.notify();
 6375            }
 6376        }
 6377        drop(context_menu);
 6378        let snapshot = self.snapshot(window, cx);
 6379        let deployed_from = action.deployed_from.clone();
 6380        let action = action.clone();
 6381        self.completion_tasks.clear();
 6382        self.discard_edit_prediction(false, cx);
 6383
 6384        let multibuffer_point = match &action.deployed_from {
 6385            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6386                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6387            }
 6388            _ => self
 6389                .selections
 6390                .newest::<Point>(&snapshot.display_snapshot)
 6391                .head(),
 6392        };
 6393        let Some((buffer, buffer_row)) = snapshot
 6394            .buffer_snapshot()
 6395            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6396            .and_then(|(buffer_snapshot, range)| {
 6397                self.buffer()
 6398                    .read(cx)
 6399                    .buffer(buffer_snapshot.remote_id())
 6400                    .map(|buffer| (buffer, range.start.row))
 6401            })
 6402        else {
 6403            return;
 6404        };
 6405        let buffer_id = buffer.read(cx).remote_id();
 6406        let tasks = self
 6407            .tasks
 6408            .get(&(buffer_id, buffer_row))
 6409            .map(|t| Arc::new(t.to_owned()));
 6410
 6411        if !self.focus_handle.is_focused(window) {
 6412            return;
 6413        }
 6414        let project = self.project.clone();
 6415
 6416        let code_actions_task = match deployed_from {
 6417            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6418            _ => self.code_actions(buffer_row, window, cx),
 6419        };
 6420
 6421        let runnable_task = match deployed_from {
 6422            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6423            _ => {
 6424                let mut task_context_task = Task::ready(None);
 6425                if let Some(tasks) = &tasks
 6426                    && let Some(project) = project
 6427                {
 6428                    task_context_task =
 6429                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6430                }
 6431
 6432                cx.spawn_in(window, {
 6433                    let buffer = buffer.clone();
 6434                    async move |editor, cx| {
 6435                        let task_context = task_context_task.await;
 6436
 6437                        let resolved_tasks =
 6438                            tasks
 6439                                .zip(task_context.clone())
 6440                                .map(|(tasks, task_context)| ResolvedTasks {
 6441                                    templates: tasks.resolve(&task_context).collect(),
 6442                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6443                                        multibuffer_point.row,
 6444                                        tasks.column,
 6445                                    )),
 6446                                });
 6447                        let debug_scenarios = editor
 6448                            .update(cx, |editor, cx| {
 6449                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6450                            })?
 6451                            .await;
 6452                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6453                    }
 6454                })
 6455            }
 6456        };
 6457
 6458        cx.spawn_in(window, async move |editor, cx| {
 6459            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6460            let code_actions = code_actions_task.await;
 6461            let spawn_straight_away = quick_launch
 6462                && resolved_tasks
 6463                    .as_ref()
 6464                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6465                && code_actions
 6466                    .as_ref()
 6467                    .is_none_or(|actions| actions.is_empty())
 6468                && debug_scenarios.is_empty();
 6469
 6470            editor.update_in(cx, |editor, window, cx| {
 6471                crate::hover_popover::hide_hover(editor, cx);
 6472                let actions = CodeActionContents::new(
 6473                    resolved_tasks,
 6474                    code_actions,
 6475                    debug_scenarios,
 6476                    task_context.unwrap_or_default(),
 6477                );
 6478
 6479                // Don't show the menu if there are no actions available
 6480                if actions.is_empty() {
 6481                    cx.notify();
 6482                    return Task::ready(Ok(()));
 6483                }
 6484
 6485                *editor.context_menu.borrow_mut() =
 6486                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6487                        buffer,
 6488                        actions,
 6489                        selected_item: Default::default(),
 6490                        scroll_handle: UniformListScrollHandle::default(),
 6491                        deployed_from,
 6492                    }));
 6493                cx.notify();
 6494                if spawn_straight_away
 6495                    && let Some(task) = editor.confirm_code_action(
 6496                        &ConfirmCodeAction { item_ix: Some(0) },
 6497                        window,
 6498                        cx,
 6499                    )
 6500                {
 6501                    return task;
 6502                }
 6503
 6504                Task::ready(Ok(()))
 6505            })
 6506        })
 6507        .detach_and_log_err(cx);
 6508    }
 6509
 6510    fn debug_scenarios(
 6511        &mut self,
 6512        resolved_tasks: &Option<ResolvedTasks>,
 6513        buffer: &Entity<Buffer>,
 6514        cx: &mut App,
 6515    ) -> Task<Vec<task::DebugScenario>> {
 6516        maybe!({
 6517            let project = self.project()?;
 6518            let dap_store = project.read(cx).dap_store();
 6519            let mut scenarios = vec![];
 6520            let resolved_tasks = resolved_tasks.as_ref()?;
 6521            let buffer = buffer.read(cx);
 6522            let language = buffer.language()?;
 6523            let file = buffer.file();
 6524            let debug_adapter = language_settings(language.name().into(), file, cx)
 6525                .debuggers
 6526                .first()
 6527                .map(SharedString::from)
 6528                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6529
 6530            dap_store.update(cx, |dap_store, cx| {
 6531                for (_, task) in &resolved_tasks.templates {
 6532                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6533                        task.original_task().clone(),
 6534                        debug_adapter.clone().into(),
 6535                        task.display_label().to_owned().into(),
 6536                        cx,
 6537                    );
 6538                    scenarios.push(maybe_scenario);
 6539                }
 6540            });
 6541            Some(cx.background_spawn(async move {
 6542                futures::future::join_all(scenarios)
 6543                    .await
 6544                    .into_iter()
 6545                    .flatten()
 6546                    .collect::<Vec<_>>()
 6547            }))
 6548        })
 6549        .unwrap_or_else(|| Task::ready(vec![]))
 6550    }
 6551
 6552    fn code_actions(
 6553        &mut self,
 6554        buffer_row: u32,
 6555        window: &mut Window,
 6556        cx: &mut Context<Self>,
 6557    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6558        let mut task = self.code_actions_task.take();
 6559        cx.spawn_in(window, async move |editor, cx| {
 6560            while let Some(prev_task) = task {
 6561                prev_task.await.log_err();
 6562                task = editor
 6563                    .update(cx, |this, _| this.code_actions_task.take())
 6564                    .ok()?;
 6565            }
 6566
 6567            editor
 6568                .update(cx, |editor, cx| {
 6569                    editor
 6570                        .available_code_actions
 6571                        .clone()
 6572                        .and_then(|(location, code_actions)| {
 6573                            let snapshot = location.buffer.read(cx).snapshot();
 6574                            let point_range = location.range.to_point(&snapshot);
 6575                            let point_range = point_range.start.row..=point_range.end.row;
 6576                            if point_range.contains(&buffer_row) {
 6577                                Some(code_actions)
 6578                            } else {
 6579                                None
 6580                            }
 6581                        })
 6582                })
 6583                .ok()
 6584                .flatten()
 6585        })
 6586    }
 6587
 6588    pub fn confirm_code_action(
 6589        &mut self,
 6590        action: &ConfirmCodeAction,
 6591        window: &mut Window,
 6592        cx: &mut Context<Self>,
 6593    ) -> Option<Task<Result<()>>> {
 6594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6595
 6596        let actions_menu =
 6597            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6598                menu
 6599            } else {
 6600                return None;
 6601            };
 6602
 6603        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6604        let action = actions_menu.actions.get(action_ix)?;
 6605        let title = action.label();
 6606        let buffer = actions_menu.buffer;
 6607        let workspace = self.workspace()?;
 6608
 6609        match action {
 6610            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6611                workspace.update(cx, |workspace, cx| {
 6612                    workspace.schedule_resolved_task(
 6613                        task_source_kind,
 6614                        resolved_task,
 6615                        false,
 6616                        window,
 6617                        cx,
 6618                    );
 6619
 6620                    Some(Task::ready(Ok(())))
 6621                })
 6622            }
 6623            CodeActionsItem::CodeAction {
 6624                excerpt_id,
 6625                action,
 6626                provider,
 6627            } => {
 6628                let apply_code_action =
 6629                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6630                let workspace = workspace.downgrade();
 6631                Some(cx.spawn_in(window, async move |editor, cx| {
 6632                    let project_transaction = apply_code_action.await?;
 6633                    Self::open_project_transaction(
 6634                        &editor,
 6635                        workspace,
 6636                        project_transaction,
 6637                        title,
 6638                        cx,
 6639                    )
 6640                    .await
 6641                }))
 6642            }
 6643            CodeActionsItem::DebugScenario(scenario) => {
 6644                let context = actions_menu.actions.context;
 6645
 6646                workspace.update(cx, |workspace, cx| {
 6647                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6648                    workspace.start_debug_session(
 6649                        scenario,
 6650                        context,
 6651                        Some(buffer),
 6652                        None,
 6653                        window,
 6654                        cx,
 6655                    );
 6656                });
 6657                Some(Task::ready(Ok(())))
 6658            }
 6659        }
 6660    }
 6661
 6662    fn open_transaction_for_hidden_buffers(
 6663        workspace: Entity<Workspace>,
 6664        transaction: ProjectTransaction,
 6665        title: String,
 6666        window: &mut Window,
 6667        cx: &mut Context<Self>,
 6668    ) {
 6669        if transaction.0.is_empty() {
 6670            return;
 6671        }
 6672
 6673        let edited_buffers_already_open = {
 6674            let other_editors: Vec<Entity<Editor>> = workspace
 6675                .read(cx)
 6676                .panes()
 6677                .iter()
 6678                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6679                .filter(|editor| editor.entity_id() != cx.entity_id())
 6680                .collect();
 6681
 6682            transaction.0.keys().all(|buffer| {
 6683                other_editors.iter().any(|editor| {
 6684                    let multi_buffer = editor.read(cx).buffer();
 6685                    multi_buffer.read(cx).is_singleton()
 6686                        && multi_buffer
 6687                            .read(cx)
 6688                            .as_singleton()
 6689                            .map_or(false, |singleton| {
 6690                                singleton.entity_id() == buffer.entity_id()
 6691                            })
 6692                })
 6693            })
 6694        };
 6695        if !edited_buffers_already_open {
 6696            let workspace = workspace.downgrade();
 6697            cx.defer_in(window, move |_, window, cx| {
 6698                cx.spawn_in(window, async move |editor, cx| {
 6699                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6700                        .await
 6701                        .ok()
 6702                })
 6703                .detach();
 6704            });
 6705        }
 6706    }
 6707
 6708    pub async fn open_project_transaction(
 6709        editor: &WeakEntity<Editor>,
 6710        workspace: WeakEntity<Workspace>,
 6711        transaction: ProjectTransaction,
 6712        title: String,
 6713        cx: &mut AsyncWindowContext,
 6714    ) -> Result<()> {
 6715        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6716        cx.update(|_, cx| {
 6717            entries.sort_unstable_by_key(|(buffer, _)| {
 6718                buffer.read(cx).file().map(|f| f.path().clone())
 6719            });
 6720        })?;
 6721        if entries.is_empty() {
 6722            return Ok(());
 6723        }
 6724
 6725        // If the project transaction's edits are all contained within this editor, then
 6726        // avoid opening a new editor to display them.
 6727
 6728        if let [(buffer, transaction)] = &*entries {
 6729            let excerpt = editor.update(cx, |editor, cx| {
 6730                editor
 6731                    .buffer()
 6732                    .read(cx)
 6733                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6734            })?;
 6735            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6736                && excerpted_buffer == *buffer
 6737            {
 6738                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6739                    let excerpt_range = excerpt_range.to_offset(buffer);
 6740                    buffer
 6741                        .edited_ranges_for_transaction::<usize>(transaction)
 6742                        .all(|range| {
 6743                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6744                        })
 6745                });
 6746
 6747                if all_edits_within_excerpt {
 6748                    return Ok(());
 6749                }
 6750            }
 6751        }
 6752
 6753        let mut ranges_to_highlight = Vec::new();
 6754        let excerpt_buffer = cx.new(|cx| {
 6755            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6756            for (buffer_handle, transaction) in &entries {
 6757                let edited_ranges = buffer_handle
 6758                    .read(cx)
 6759                    .edited_ranges_for_transaction::<Point>(transaction)
 6760                    .collect::<Vec<_>>();
 6761                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6762                    PathKey::for_buffer(buffer_handle, cx),
 6763                    buffer_handle.clone(),
 6764                    edited_ranges,
 6765                    multibuffer_context_lines(cx),
 6766                    cx,
 6767                );
 6768
 6769                ranges_to_highlight.extend(ranges);
 6770            }
 6771            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6772            multibuffer
 6773        });
 6774
 6775        workspace.update_in(cx, |workspace, window, cx| {
 6776            let project = workspace.project().clone();
 6777            let editor =
 6778                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6779            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6780            editor.update(cx, |editor, cx| {
 6781                editor.highlight_background::<Self>(
 6782                    &ranges_to_highlight,
 6783                    |_, theme| theme.colors().editor_highlighted_line_background,
 6784                    cx,
 6785                );
 6786            });
 6787        })?;
 6788
 6789        Ok(())
 6790    }
 6791
 6792    pub fn clear_code_action_providers(&mut self) {
 6793        self.code_action_providers.clear();
 6794        self.available_code_actions.take();
 6795    }
 6796
 6797    pub fn add_code_action_provider(
 6798        &mut self,
 6799        provider: Rc<dyn CodeActionProvider>,
 6800        window: &mut Window,
 6801        cx: &mut Context<Self>,
 6802    ) {
 6803        if self
 6804            .code_action_providers
 6805            .iter()
 6806            .any(|existing_provider| existing_provider.id() == provider.id())
 6807        {
 6808            return;
 6809        }
 6810
 6811        self.code_action_providers.push(provider);
 6812        self.refresh_code_actions(window, cx);
 6813    }
 6814
 6815    pub fn remove_code_action_provider(
 6816        &mut self,
 6817        id: Arc<str>,
 6818        window: &mut Window,
 6819        cx: &mut Context<Self>,
 6820    ) {
 6821        self.code_action_providers
 6822            .retain(|provider| provider.id() != id);
 6823        self.refresh_code_actions(window, cx);
 6824    }
 6825
 6826    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6827        !self.code_action_providers.is_empty()
 6828            && EditorSettings::get_global(cx).toolbar.code_actions
 6829    }
 6830
 6831    pub fn has_available_code_actions(&self) -> bool {
 6832        self.available_code_actions
 6833            .as_ref()
 6834            .is_some_and(|(_, actions)| !actions.is_empty())
 6835    }
 6836
 6837    fn render_inline_code_actions(
 6838        &self,
 6839        icon_size: ui::IconSize,
 6840        display_row: DisplayRow,
 6841        is_active: bool,
 6842        cx: &mut Context<Self>,
 6843    ) -> AnyElement {
 6844        let show_tooltip = !self.context_menu_visible();
 6845        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6846            .icon_size(icon_size)
 6847            .shape(ui::IconButtonShape::Square)
 6848            .icon_color(ui::Color::Hidden)
 6849            .toggle_state(is_active)
 6850            .when(show_tooltip, |this| {
 6851                this.tooltip({
 6852                    let focus_handle = self.focus_handle.clone();
 6853                    move |_window, cx| {
 6854                        Tooltip::for_action_in(
 6855                            "Toggle Code Actions",
 6856                            &ToggleCodeActions {
 6857                                deployed_from: None,
 6858                                quick_launch: false,
 6859                            },
 6860                            &focus_handle,
 6861                            cx,
 6862                        )
 6863                    }
 6864                })
 6865            })
 6866            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6867                window.focus(&editor.focus_handle(cx), cx);
 6868                editor.toggle_code_actions(
 6869                    &crate::actions::ToggleCodeActions {
 6870                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6871                            display_row,
 6872                        )),
 6873                        quick_launch: false,
 6874                    },
 6875                    window,
 6876                    cx,
 6877                );
 6878            }))
 6879            .into_any_element()
 6880    }
 6881
 6882    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6883        &self.context_menu
 6884    }
 6885
 6886    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6887        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6888            cx.background_executor()
 6889                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6890                .await;
 6891
 6892            let (start_buffer, start, _, end, newest_selection) = this
 6893                .update(cx, |this, cx| {
 6894                    let newest_selection = this.selections.newest_anchor().clone();
 6895                    if newest_selection.head().diff_base_anchor.is_some() {
 6896                        return None;
 6897                    }
 6898                    let display_snapshot = this.display_snapshot(cx);
 6899                    let newest_selection_adjusted =
 6900                        this.selections.newest_adjusted(&display_snapshot);
 6901                    let buffer = this.buffer.read(cx);
 6902
 6903                    let (start_buffer, start) =
 6904                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6905                    let (end_buffer, end) =
 6906                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6907
 6908                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6909                })?
 6910                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6911                .context(
 6912                    "Expected selection to lie in a single buffer when refreshing code actions",
 6913                )?;
 6914            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6915                let providers = this.code_action_providers.clone();
 6916                let tasks = this
 6917                    .code_action_providers
 6918                    .iter()
 6919                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6920                    .collect::<Vec<_>>();
 6921                (providers, tasks)
 6922            })?;
 6923
 6924            let mut actions = Vec::new();
 6925            for (provider, provider_actions) in
 6926                providers.into_iter().zip(future::join_all(tasks).await)
 6927            {
 6928                if let Some(provider_actions) = provider_actions.log_err() {
 6929                    actions.extend(provider_actions.into_iter().map(|action| {
 6930                        AvailableCodeAction {
 6931                            excerpt_id: newest_selection.start.excerpt_id,
 6932                            action,
 6933                            provider: provider.clone(),
 6934                        }
 6935                    }));
 6936                }
 6937            }
 6938
 6939            this.update(cx, |this, cx| {
 6940                this.available_code_actions = if actions.is_empty() {
 6941                    None
 6942                } else {
 6943                    Some((
 6944                        Location {
 6945                            buffer: start_buffer,
 6946                            range: start..end,
 6947                        },
 6948                        actions.into(),
 6949                    ))
 6950                };
 6951                cx.notify();
 6952            })
 6953        }));
 6954    }
 6955
 6956    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6957        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6958            self.show_git_blame_inline = false;
 6959
 6960            self.show_git_blame_inline_delay_task =
 6961                Some(cx.spawn_in(window, async move |this, cx| {
 6962                    cx.background_executor().timer(delay).await;
 6963
 6964                    this.update(cx, |this, cx| {
 6965                        this.show_git_blame_inline = true;
 6966                        cx.notify();
 6967                    })
 6968                    .log_err();
 6969                }));
 6970        }
 6971    }
 6972
 6973    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6974        let snapshot = self.snapshot(window, cx);
 6975        let cursor = self
 6976            .selections
 6977            .newest::<Point>(&snapshot.display_snapshot)
 6978            .head();
 6979        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6980        else {
 6981            return;
 6982        };
 6983
 6984        if self.blame.is_none() {
 6985            self.start_git_blame(true, window, cx);
 6986        }
 6987        let Some(blame) = self.blame.as_ref() else {
 6988            return;
 6989        };
 6990
 6991        let row_info = RowInfo {
 6992            buffer_id: Some(buffer.remote_id()),
 6993            buffer_row: Some(point.row),
 6994            ..Default::default()
 6995        };
 6996        let Some((buffer, blame_entry)) = blame
 6997            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6998            .flatten()
 6999        else {
 7000            return;
 7001        };
 7002
 7003        let anchor = self.selections.newest_anchor().head();
 7004        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7005        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7006            self.show_blame_popover(
 7007                buffer,
 7008                &blame_entry,
 7009                position + last_bounds.origin,
 7010                true,
 7011                cx,
 7012            );
 7013        };
 7014    }
 7015
 7016    fn show_blame_popover(
 7017        &mut self,
 7018        buffer: BufferId,
 7019        blame_entry: &BlameEntry,
 7020        position: gpui::Point<Pixels>,
 7021        ignore_timeout: bool,
 7022        cx: &mut Context<Self>,
 7023    ) {
 7024        if let Some(state) = &mut self.inline_blame_popover {
 7025            state.hide_task.take();
 7026        } else {
 7027            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7028            let blame_entry = blame_entry.clone();
 7029            let show_task = cx.spawn(async move |editor, cx| {
 7030                if !ignore_timeout {
 7031                    cx.background_executor()
 7032                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7033                        .await;
 7034                }
 7035                editor
 7036                    .update(cx, |editor, cx| {
 7037                        editor.inline_blame_popover_show_task.take();
 7038                        let Some(blame) = editor.blame.as_ref() else {
 7039                            return;
 7040                        };
 7041                        let blame = blame.read(cx);
 7042                        let details = blame.details_for_entry(buffer, &blame_entry);
 7043                        let markdown = cx.new(|cx| {
 7044                            Markdown::new(
 7045                                details
 7046                                    .as_ref()
 7047                                    .map(|message| message.message.clone())
 7048                                    .unwrap_or_default(),
 7049                                None,
 7050                                None,
 7051                                cx,
 7052                            )
 7053                        });
 7054                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7055                            position,
 7056                            hide_task: None,
 7057                            popover_bounds: None,
 7058                            popover_state: InlineBlamePopoverState {
 7059                                scroll_handle: ScrollHandle::new(),
 7060                                commit_message: details,
 7061                                markdown,
 7062                            },
 7063                            keyboard_grace: ignore_timeout,
 7064                        });
 7065                        cx.notify();
 7066                    })
 7067                    .ok();
 7068            });
 7069            self.inline_blame_popover_show_task = Some(show_task);
 7070        }
 7071    }
 7072
 7073    pub fn has_mouse_context_menu(&self) -> bool {
 7074        self.mouse_context_menu.is_some()
 7075    }
 7076
 7077    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7078        self.inline_blame_popover_show_task.take();
 7079        if let Some(state) = &mut self.inline_blame_popover {
 7080            let hide_task = cx.spawn(async move |editor, cx| {
 7081                if !ignore_timeout {
 7082                    cx.background_executor()
 7083                        .timer(std::time::Duration::from_millis(100))
 7084                        .await;
 7085                }
 7086                editor
 7087                    .update(cx, |editor, cx| {
 7088                        editor.inline_blame_popover.take();
 7089                        cx.notify();
 7090                    })
 7091                    .ok();
 7092            });
 7093            state.hide_task = Some(hide_task);
 7094            true
 7095        } else {
 7096            false
 7097        }
 7098    }
 7099
 7100    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7101        if self.pending_rename.is_some() {
 7102            return None;
 7103        }
 7104
 7105        let provider = self.semantics_provider.clone()?;
 7106        let buffer = self.buffer.read(cx);
 7107        let newest_selection = self.selections.newest_anchor().clone();
 7108        let cursor_position = newest_selection.head();
 7109        let (cursor_buffer, cursor_buffer_position) =
 7110            buffer.text_anchor_for_position(cursor_position, cx)?;
 7111        let (tail_buffer, tail_buffer_position) =
 7112            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7113        if cursor_buffer != tail_buffer {
 7114            return None;
 7115        }
 7116
 7117        let snapshot = cursor_buffer.read(cx).snapshot();
 7118        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7119        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7120        if start_word_range != end_word_range {
 7121            self.document_highlights_task.take();
 7122            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7123            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7124            return None;
 7125        }
 7126
 7127        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7128        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7129            cx.background_executor()
 7130                .timer(Duration::from_millis(debounce))
 7131                .await;
 7132
 7133            let highlights = if let Some(highlights) = cx.update(|cx| {
 7134                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7135            }) {
 7136                highlights.await.log_err()
 7137            } else {
 7138                None
 7139            };
 7140
 7141            if let Some(highlights) = highlights {
 7142                this.update(cx, |this, cx| {
 7143                    if this.pending_rename.is_some() {
 7144                        return;
 7145                    }
 7146
 7147                    let buffer = this.buffer.read(cx);
 7148                    if buffer
 7149                        .text_anchor_for_position(cursor_position, cx)
 7150                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7151                    {
 7152                        return;
 7153                    }
 7154
 7155                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7156                    let mut write_ranges = Vec::new();
 7157                    let mut read_ranges = Vec::new();
 7158                    for highlight in highlights {
 7159                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7160                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7161                        {
 7162                            let start = highlight
 7163                                .range
 7164                                .start
 7165                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7166                            let end = highlight
 7167                                .range
 7168                                .end
 7169                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7170                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7171                                continue;
 7172                            }
 7173
 7174                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7175                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7176                                write_ranges.push(range);
 7177                            } else {
 7178                                read_ranges.push(range);
 7179                            }
 7180                        }
 7181                    }
 7182
 7183                    this.highlight_background::<DocumentHighlightRead>(
 7184                        &read_ranges,
 7185                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7186                        cx,
 7187                    );
 7188                    this.highlight_background::<DocumentHighlightWrite>(
 7189                        &write_ranges,
 7190                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7191                        cx,
 7192                    );
 7193                    cx.notify();
 7194                })
 7195                .log_err();
 7196            }
 7197        }));
 7198        None
 7199    }
 7200
 7201    fn prepare_highlight_query_from_selection(
 7202        &mut self,
 7203        window: &Window,
 7204        cx: &mut Context<Editor>,
 7205    ) -> Option<(String, Range<Anchor>)> {
 7206        if matches!(self.mode, EditorMode::SingleLine) {
 7207            return None;
 7208        }
 7209        if !EditorSettings::get_global(cx).selection_highlight {
 7210            return None;
 7211        }
 7212        if self.selections.count() != 1 || self.selections.line_mode() {
 7213            return None;
 7214        }
 7215        let snapshot = self.snapshot(window, cx);
 7216        let selection = self.selections.newest::<Point>(&snapshot);
 7217        // If the selection spans multiple rows OR it is empty
 7218        if selection.start.row != selection.end.row
 7219            || selection.start.column == selection.end.column
 7220        {
 7221            return None;
 7222        }
 7223        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7224        let query = snapshot
 7225            .buffer_snapshot()
 7226            .text_for_range(selection_anchor_range.clone())
 7227            .collect::<String>();
 7228        if query.trim().is_empty() {
 7229            return None;
 7230        }
 7231        Some((query, selection_anchor_range))
 7232    }
 7233
 7234    #[ztracing::instrument(skip_all)]
 7235    fn update_selection_occurrence_highlights(
 7236        &mut self,
 7237        query_text: String,
 7238        query_range: Range<Anchor>,
 7239        multi_buffer_range_to_query: Range<Point>,
 7240        use_debounce: bool,
 7241        window: &mut Window,
 7242        cx: &mut Context<Editor>,
 7243    ) -> Task<()> {
 7244        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7245        cx.spawn_in(window, async move |editor, cx| {
 7246            if use_debounce {
 7247                cx.background_executor()
 7248                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7249                    .await;
 7250            }
 7251            let match_task = cx.background_spawn(async move {
 7252                let buffer_ranges = multi_buffer_snapshot
 7253                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7254                    .into_iter()
 7255                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7256                let mut match_ranges = Vec::new();
 7257                let Ok(regex) = project::search::SearchQuery::text(
 7258                    query_text.clone(),
 7259                    false,
 7260                    false,
 7261                    false,
 7262                    Default::default(),
 7263                    Default::default(),
 7264                    false,
 7265                    None,
 7266                ) else {
 7267                    return Vec::default();
 7268                };
 7269                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7270                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7271                    match_ranges.extend(
 7272                        regex
 7273                            .search(
 7274                                buffer_snapshot,
 7275                                Some(search_range.start.0..search_range.end.0),
 7276                            )
 7277                            .await
 7278                            .into_iter()
 7279                            .filter_map(|match_range| {
 7280                                let match_start = buffer_snapshot
 7281                                    .anchor_after(search_range.start + match_range.start);
 7282                                let match_end = buffer_snapshot
 7283                                    .anchor_before(search_range.start + match_range.end);
 7284                                let match_anchor_range =
 7285                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7286                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7287                            }),
 7288                    );
 7289                }
 7290                match_ranges
 7291            });
 7292            let match_ranges = match_task.await;
 7293            editor
 7294                .update_in(cx, |editor, _, cx| {
 7295                    if use_debounce {
 7296                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7297                        editor.debounced_selection_highlight_complete = true;
 7298                    } else if editor.debounced_selection_highlight_complete {
 7299                        return;
 7300                    }
 7301                    if !match_ranges.is_empty() {
 7302                        editor.highlight_background::<SelectedTextHighlight>(
 7303                            &match_ranges,
 7304                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7305                            cx,
 7306                        )
 7307                    }
 7308                })
 7309                .log_err();
 7310        })
 7311    }
 7312
 7313    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7314        struct NewlineFold;
 7315        let type_id = std::any::TypeId::of::<NewlineFold>();
 7316        if !self.mode.is_single_line() {
 7317            return;
 7318        }
 7319        let snapshot = self.snapshot(window, cx);
 7320        if snapshot.buffer_snapshot().max_point().row == 0 {
 7321            return;
 7322        }
 7323        let task = cx.background_spawn(async move {
 7324            let new_newlines = snapshot
 7325                .buffer_chars_at(MultiBufferOffset(0))
 7326                .filter_map(|(c, i)| {
 7327                    if c == '\n' {
 7328                        Some(
 7329                            snapshot.buffer_snapshot().anchor_after(i)
 7330                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7331                        )
 7332                    } else {
 7333                        None
 7334                    }
 7335                })
 7336                .collect::<Vec<_>>();
 7337            let existing_newlines = snapshot
 7338                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7339                .filter_map(|fold| {
 7340                    if fold.placeholder.type_tag == Some(type_id) {
 7341                        Some(fold.range.start..fold.range.end)
 7342                    } else {
 7343                        None
 7344                    }
 7345                })
 7346                .collect::<Vec<_>>();
 7347
 7348            (new_newlines, existing_newlines)
 7349        });
 7350        self.folding_newlines = cx.spawn(async move |this, cx| {
 7351            let (new_newlines, existing_newlines) = task.await;
 7352            if new_newlines == existing_newlines {
 7353                return;
 7354            }
 7355            let placeholder = FoldPlaceholder {
 7356                render: Arc::new(move |_, _, cx| {
 7357                    div()
 7358                        .bg(cx.theme().status().hint_background)
 7359                        .border_b_1()
 7360                        .size_full()
 7361                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7362                        .border_color(cx.theme().status().hint)
 7363                        .child("\\n")
 7364                        .into_any()
 7365                }),
 7366                constrain_width: false,
 7367                merge_adjacent: false,
 7368                type_tag: Some(type_id),
 7369            };
 7370            let creases = new_newlines
 7371                .into_iter()
 7372                .map(|range| Crease::simple(range, placeholder.clone()))
 7373                .collect();
 7374            this.update(cx, |this, cx| {
 7375                this.display_map.update(cx, |display_map, cx| {
 7376                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7377                    display_map.fold(creases, cx);
 7378                });
 7379            })
 7380            .ok();
 7381        });
 7382    }
 7383
 7384    #[ztracing::instrument(skip_all)]
 7385    fn refresh_selected_text_highlights(
 7386        &mut self,
 7387        on_buffer_edit: bool,
 7388        window: &mut Window,
 7389        cx: &mut Context<Editor>,
 7390    ) {
 7391        let Some((query_text, query_range)) =
 7392            self.prepare_highlight_query_from_selection(window, cx)
 7393        else {
 7394            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7395            self.quick_selection_highlight_task.take();
 7396            self.debounced_selection_highlight_task.take();
 7397            self.debounced_selection_highlight_complete = false;
 7398            return;
 7399        };
 7400        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7401        let query_changed = self
 7402            .quick_selection_highlight_task
 7403            .as_ref()
 7404            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7405        if query_changed {
 7406            self.debounced_selection_highlight_complete = false;
 7407        }
 7408        if on_buffer_edit || query_changed {
 7409            let multi_buffer_visible_start = self
 7410                .scroll_manager
 7411                .anchor()
 7412                .anchor
 7413                .to_point(&multi_buffer_snapshot);
 7414            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7415                multi_buffer_visible_start
 7416                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7417                Bias::Left,
 7418            );
 7419            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7420            self.quick_selection_highlight_task = Some((
 7421                query_range.clone(),
 7422                self.update_selection_occurrence_highlights(
 7423                    query_text.clone(),
 7424                    query_range.clone(),
 7425                    multi_buffer_visible_range,
 7426                    false,
 7427                    window,
 7428                    cx,
 7429                ),
 7430            ));
 7431        }
 7432        if on_buffer_edit
 7433            || self
 7434                .debounced_selection_highlight_task
 7435                .as_ref()
 7436                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7437        {
 7438            let multi_buffer_start = multi_buffer_snapshot
 7439                .anchor_before(MultiBufferOffset(0))
 7440                .to_point(&multi_buffer_snapshot);
 7441            let multi_buffer_end = multi_buffer_snapshot
 7442                .anchor_after(multi_buffer_snapshot.len())
 7443                .to_point(&multi_buffer_snapshot);
 7444            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7445            self.debounced_selection_highlight_task = Some((
 7446                query_range.clone(),
 7447                self.update_selection_occurrence_highlights(
 7448                    query_text,
 7449                    query_range,
 7450                    multi_buffer_full_range,
 7451                    true,
 7452                    window,
 7453                    cx,
 7454                ),
 7455            ));
 7456        }
 7457    }
 7458
 7459    pub fn refresh_edit_prediction(
 7460        &mut self,
 7461        debounce: bool,
 7462        user_requested: bool,
 7463        window: &mut Window,
 7464        cx: &mut Context<Self>,
 7465    ) -> Option<()> {
 7466        if DisableAiSettings::get_global(cx).disable_ai {
 7467            return None;
 7468        }
 7469
 7470        let provider = self.edit_prediction_provider()?;
 7471        let cursor = self.selections.newest_anchor().head();
 7472        let (buffer, cursor_buffer_position) =
 7473            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7474
 7475        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7476            self.discard_edit_prediction(false, cx);
 7477            return None;
 7478        }
 7479
 7480        self.update_visible_edit_prediction(window, cx);
 7481
 7482        if !user_requested
 7483            && (!self.should_show_edit_predictions()
 7484                || !self.is_focused(window)
 7485                || buffer.read(cx).is_empty())
 7486        {
 7487            self.discard_edit_prediction(false, cx);
 7488            return None;
 7489        }
 7490
 7491        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7492        Some(())
 7493    }
 7494
 7495    fn show_edit_predictions_in_menu(&self) -> bool {
 7496        match self.edit_prediction_settings {
 7497            EditPredictionSettings::Disabled => false,
 7498            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7499        }
 7500    }
 7501
 7502    pub fn edit_predictions_enabled(&self) -> bool {
 7503        match self.edit_prediction_settings {
 7504            EditPredictionSettings::Disabled => false,
 7505            EditPredictionSettings::Enabled { .. } => true,
 7506        }
 7507    }
 7508
 7509    fn edit_prediction_requires_modifier(&self) -> bool {
 7510        match self.edit_prediction_settings {
 7511            EditPredictionSettings::Disabled => false,
 7512            EditPredictionSettings::Enabled {
 7513                preview_requires_modifier,
 7514                ..
 7515            } => preview_requires_modifier,
 7516        }
 7517    }
 7518
 7519    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7520        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7521            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7522            self.discard_edit_prediction(false, cx);
 7523        } else {
 7524            let selection = self.selections.newest_anchor();
 7525            let cursor = selection.head();
 7526
 7527            if let Some((buffer, cursor_buffer_position)) =
 7528                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7529            {
 7530                self.edit_prediction_settings =
 7531                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7532            }
 7533        }
 7534    }
 7535
 7536    fn edit_prediction_settings_at_position(
 7537        &self,
 7538        buffer: &Entity<Buffer>,
 7539        buffer_position: language::Anchor,
 7540        cx: &App,
 7541    ) -> EditPredictionSettings {
 7542        if !self.mode.is_full()
 7543            || !self.show_edit_predictions_override.unwrap_or(true)
 7544            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7545        {
 7546            return EditPredictionSettings::Disabled;
 7547        }
 7548
 7549        let buffer = buffer.read(cx);
 7550
 7551        let file = buffer.file();
 7552
 7553        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7554            return EditPredictionSettings::Disabled;
 7555        };
 7556
 7557        let by_provider = matches!(
 7558            self.menu_edit_predictions_policy,
 7559            MenuEditPredictionsPolicy::ByProvider
 7560        );
 7561
 7562        let show_in_menu = by_provider
 7563            && self
 7564                .edit_prediction_provider
 7565                .as_ref()
 7566                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7567
 7568        let preview_requires_modifier =
 7569            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7570
 7571        EditPredictionSettings::Enabled {
 7572            show_in_menu,
 7573            preview_requires_modifier,
 7574        }
 7575    }
 7576
 7577    fn should_show_edit_predictions(&self) -> bool {
 7578        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7579    }
 7580
 7581    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7582        matches!(
 7583            self.edit_prediction_preview,
 7584            EditPredictionPreview::Active { .. }
 7585        )
 7586    }
 7587
 7588    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7589        let cursor = self.selections.newest_anchor().head();
 7590        if let Some((buffer, cursor_position)) =
 7591            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7592        {
 7593            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7594        } else {
 7595            false
 7596        }
 7597    }
 7598
 7599    pub fn supports_minimap(&self, cx: &App) -> bool {
 7600        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7601    }
 7602
 7603    fn edit_predictions_enabled_in_buffer(
 7604        &self,
 7605        buffer: &Entity<Buffer>,
 7606        buffer_position: language::Anchor,
 7607        cx: &App,
 7608    ) -> bool {
 7609        maybe!({
 7610            if self.read_only(cx) {
 7611                return Some(false);
 7612            }
 7613            let provider = self.edit_prediction_provider()?;
 7614            if !provider.is_enabled(buffer, buffer_position, cx) {
 7615                return Some(false);
 7616            }
 7617            let buffer = buffer.read(cx);
 7618            let Some(file) = buffer.file() else {
 7619                return Some(true);
 7620            };
 7621            let settings = all_language_settings(Some(file), cx);
 7622            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7623        })
 7624        .unwrap_or(false)
 7625    }
 7626
 7627    pub fn show_edit_prediction(
 7628        &mut self,
 7629        _: &ShowEditPrediction,
 7630        window: &mut Window,
 7631        cx: &mut Context<Self>,
 7632    ) {
 7633        if !self.has_active_edit_prediction() {
 7634            self.refresh_edit_prediction(false, true, window, cx);
 7635            return;
 7636        }
 7637
 7638        self.update_visible_edit_prediction(window, cx);
 7639    }
 7640
 7641    pub fn display_cursor_names(
 7642        &mut self,
 7643        _: &DisplayCursorNames,
 7644        window: &mut Window,
 7645        cx: &mut Context<Self>,
 7646    ) {
 7647        self.show_cursor_names(window, cx);
 7648    }
 7649
 7650    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7651        self.show_cursor_names = true;
 7652        cx.notify();
 7653        cx.spawn_in(window, async move |this, cx| {
 7654            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7655            this.update(cx, |this, cx| {
 7656                this.show_cursor_names = false;
 7657                cx.notify()
 7658            })
 7659            .ok()
 7660        })
 7661        .detach();
 7662    }
 7663
 7664    pub fn accept_partial_edit_prediction(
 7665        &mut self,
 7666        granularity: EditPredictionGranularity,
 7667        window: &mut Window,
 7668        cx: &mut Context<Self>,
 7669    ) {
 7670        if self.show_edit_predictions_in_menu() {
 7671            self.hide_context_menu(window, cx);
 7672        }
 7673
 7674        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7675            return;
 7676        };
 7677
 7678        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7679            return;
 7680        }
 7681
 7682        match &active_edit_prediction.completion {
 7683            EditPrediction::MoveWithin { target, .. } => {
 7684                let target = *target;
 7685
 7686                if matches!(granularity, EditPredictionGranularity::Full) {
 7687                    if let Some(position_map) = &self.last_position_map {
 7688                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7689                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7690
 7691                        if is_visible || !self.edit_prediction_requires_modifier() {
 7692                            self.unfold_ranges(&[target..target], true, false, cx);
 7693                            self.change_selections(
 7694                                SelectionEffects::scroll(Autoscroll::newest()),
 7695                                window,
 7696                                cx,
 7697                                |selections| {
 7698                                    selections.select_anchor_ranges([target..target]);
 7699                                },
 7700                            );
 7701                            self.clear_row_highlights::<EditPredictionPreview>();
 7702                            self.edit_prediction_preview
 7703                                .set_previous_scroll_position(None);
 7704                        } else {
 7705                            // Highlight and request scroll
 7706                            self.edit_prediction_preview
 7707                                .set_previous_scroll_position(Some(
 7708                                    position_map.snapshot.scroll_anchor,
 7709                                ));
 7710                            self.highlight_rows::<EditPredictionPreview>(
 7711                                target..target,
 7712                                cx.theme().colors().editor_highlighted_line_background,
 7713                                RowHighlightOptions {
 7714                                    autoscroll: true,
 7715                                    ..Default::default()
 7716                                },
 7717                                cx,
 7718                            );
 7719                            self.request_autoscroll(Autoscroll::fit(), cx);
 7720                        }
 7721                    }
 7722                } else {
 7723                    self.change_selections(
 7724                        SelectionEffects::scroll(Autoscroll::newest()),
 7725                        window,
 7726                        cx,
 7727                        |selections| {
 7728                            selections.select_anchor_ranges([target..target]);
 7729                        },
 7730                    );
 7731                }
 7732            }
 7733            EditPrediction::MoveOutside { snapshot, target } => {
 7734                if let Some(workspace) = self.workspace() {
 7735                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7736                        .detach_and_log_err(cx);
 7737                }
 7738            }
 7739            EditPrediction::Edit { edits, .. } => {
 7740                self.report_edit_prediction_event(
 7741                    active_edit_prediction.completion_id.clone(),
 7742                    true,
 7743                    cx,
 7744                );
 7745
 7746                match granularity {
 7747                    EditPredictionGranularity::Full => {
 7748                        if let Some(provider) = self.edit_prediction_provider() {
 7749                            provider.accept(cx);
 7750                        }
 7751
 7752                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7753                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7754                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7755
 7756                        self.buffer.update(cx, |buffer, cx| {
 7757                            buffer.edit(edits.iter().cloned(), None, cx)
 7758                        });
 7759
 7760                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7761                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7762                        });
 7763
 7764                        let selections = self.selections.disjoint_anchors_arc();
 7765                        if let Some(transaction_id_now) =
 7766                            self.buffer.read(cx).last_transaction_id(cx)
 7767                        {
 7768                            if transaction_id_prev != Some(transaction_id_now) {
 7769                                self.selection_history
 7770                                    .insert_transaction(transaction_id_now, selections);
 7771                            }
 7772                        }
 7773
 7774                        self.update_visible_edit_prediction(window, cx);
 7775                        if self.active_edit_prediction.is_none() {
 7776                            self.refresh_edit_prediction(true, true, window, cx);
 7777                        }
 7778                        cx.notify();
 7779                    }
 7780                    _ => {
 7781                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7782                        let cursor_offset = self
 7783                            .selections
 7784                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7785                            .head();
 7786
 7787                        let insertion = edits.iter().find_map(|(range, text)| {
 7788                            let range = range.to_offset(&snapshot);
 7789                            if range.is_empty() && range.start == cursor_offset {
 7790                                Some(text)
 7791                            } else {
 7792                                None
 7793                            }
 7794                        });
 7795
 7796                        if let Some(text) = insertion {
 7797                            let text_to_insert = match granularity {
 7798                                EditPredictionGranularity::Word => {
 7799                                    let mut partial = text
 7800                                        .chars()
 7801                                        .by_ref()
 7802                                        .take_while(|c| c.is_alphabetic())
 7803                                        .collect::<String>();
 7804                                    if partial.is_empty() {
 7805                                        partial = text
 7806                                            .chars()
 7807                                            .by_ref()
 7808                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7809                                            .collect::<String>();
 7810                                    }
 7811                                    partial
 7812                                }
 7813                                EditPredictionGranularity::Line => {
 7814                                    if let Some(line) = text.split_inclusive('\n').next() {
 7815                                        line.to_string()
 7816                                    } else {
 7817                                        text.to_string()
 7818                                    }
 7819                                }
 7820                                EditPredictionGranularity::Full => unreachable!(),
 7821                            };
 7822
 7823                            cx.emit(EditorEvent::InputHandled {
 7824                                utf16_range_to_replace: None,
 7825                                text: text_to_insert.clone().into(),
 7826                            });
 7827
 7828                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7829                            self.refresh_edit_prediction(true, true, window, cx);
 7830                            cx.notify();
 7831                        } else {
 7832                            self.accept_partial_edit_prediction(
 7833                                EditPredictionGranularity::Full,
 7834                                window,
 7835                                cx,
 7836                            );
 7837                        }
 7838                    }
 7839                }
 7840            }
 7841        }
 7842
 7843        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7844    }
 7845
 7846    pub fn accept_next_word_edit_prediction(
 7847        &mut self,
 7848        _: &AcceptNextWordEditPrediction,
 7849        window: &mut Window,
 7850        cx: &mut Context<Self>,
 7851    ) {
 7852        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7853    }
 7854
 7855    pub fn accept_next_line_edit_prediction(
 7856        &mut self,
 7857        _: &AcceptNextLineEditPrediction,
 7858        window: &mut Window,
 7859        cx: &mut Context<Self>,
 7860    ) {
 7861        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7862    }
 7863
 7864    pub fn accept_edit_prediction(
 7865        &mut self,
 7866        _: &AcceptEditPrediction,
 7867        window: &mut Window,
 7868        cx: &mut Context<Self>,
 7869    ) {
 7870        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7871    }
 7872
 7873    fn discard_edit_prediction(
 7874        &mut self,
 7875        should_report_edit_prediction_event: bool,
 7876        cx: &mut Context<Self>,
 7877    ) -> bool {
 7878        if should_report_edit_prediction_event {
 7879            let completion_id = self
 7880                .active_edit_prediction
 7881                .as_ref()
 7882                .and_then(|active_completion| active_completion.completion_id.clone());
 7883
 7884            self.report_edit_prediction_event(completion_id, false, cx);
 7885        }
 7886
 7887        if let Some(provider) = self.edit_prediction_provider() {
 7888            provider.discard(cx);
 7889        }
 7890
 7891        self.take_active_edit_prediction(cx)
 7892    }
 7893
 7894    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7895        let Some(provider) = self.edit_prediction_provider() else {
 7896            return;
 7897        };
 7898
 7899        let Some((_, buffer, _)) = self
 7900            .buffer
 7901            .read(cx)
 7902            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7903        else {
 7904            return;
 7905        };
 7906
 7907        let extension = buffer
 7908            .read(cx)
 7909            .file()
 7910            .and_then(|file| Some(file.path().extension()?.to_string()));
 7911
 7912        let event_type = match accepted {
 7913            true => "Edit Prediction Accepted",
 7914            false => "Edit Prediction Discarded",
 7915        };
 7916        telemetry::event!(
 7917            event_type,
 7918            provider = provider.name(),
 7919            prediction_id = id,
 7920            suggestion_accepted = accepted,
 7921            file_extension = extension,
 7922        );
 7923    }
 7924
 7925    fn open_editor_at_anchor(
 7926        snapshot: &language::BufferSnapshot,
 7927        target: language::Anchor,
 7928        workspace: &Entity<Workspace>,
 7929        window: &mut Window,
 7930        cx: &mut App,
 7931    ) -> Task<Result<()>> {
 7932        workspace.update(cx, |workspace, cx| {
 7933            let path = snapshot.file().map(|file| file.full_path(cx));
 7934            let Some(path) =
 7935                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7936            else {
 7937                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7938            };
 7939            let target = text::ToPoint::to_point(&target, snapshot);
 7940            let item = workspace.open_path(path, None, true, window, cx);
 7941            window.spawn(cx, async move |cx| {
 7942                let Some(editor) = item.await?.downcast::<Editor>() else {
 7943                    return Ok(());
 7944                };
 7945                editor
 7946                    .update_in(cx, |editor, window, cx| {
 7947                        editor.go_to_singleton_buffer_point(target, window, cx);
 7948                    })
 7949                    .ok();
 7950                anyhow::Ok(())
 7951            })
 7952        })
 7953    }
 7954
 7955    pub fn has_active_edit_prediction(&self) -> bool {
 7956        self.active_edit_prediction.is_some()
 7957    }
 7958
 7959    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7960        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7961            return false;
 7962        };
 7963
 7964        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7965        self.clear_highlights::<EditPredictionHighlight>(cx);
 7966        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7967        true
 7968    }
 7969
 7970    /// Returns true when we're displaying the edit prediction popover below the cursor
 7971    /// like we are not previewing and the LSP autocomplete menu is visible
 7972    /// or we are in `when_holding_modifier` mode.
 7973    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7974        if self.edit_prediction_preview_is_active()
 7975            || !self.show_edit_predictions_in_menu()
 7976            || !self.edit_predictions_enabled()
 7977        {
 7978            return false;
 7979        }
 7980
 7981        if self.has_visible_completions_menu() {
 7982            return true;
 7983        }
 7984
 7985        has_completion && self.edit_prediction_requires_modifier()
 7986    }
 7987
 7988    fn handle_modifiers_changed(
 7989        &mut self,
 7990        modifiers: Modifiers,
 7991        position_map: &PositionMap,
 7992        window: &mut Window,
 7993        cx: &mut Context<Self>,
 7994    ) {
 7995        // Ensure that the edit prediction preview is updated, even when not
 7996        // enabled, if there's an active edit prediction preview.
 7997        if self.show_edit_predictions_in_menu()
 7998            || matches!(
 7999                self.edit_prediction_preview,
 8000                EditPredictionPreview::Active { .. }
 8001            )
 8002        {
 8003            self.update_edit_prediction_preview(&modifiers, window, cx);
 8004        }
 8005
 8006        self.update_selection_mode(&modifiers, position_map, window, cx);
 8007
 8008        let mouse_position = window.mouse_position();
 8009        if !position_map.text_hitbox.is_hovered(window) {
 8010            return;
 8011        }
 8012
 8013        self.update_hovered_link(
 8014            position_map.point_for_position(mouse_position),
 8015            &position_map.snapshot,
 8016            modifiers,
 8017            window,
 8018            cx,
 8019        )
 8020    }
 8021
 8022    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8023        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8024            MultiCursorModifier::Alt => modifiers.secondary(),
 8025            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8026        }
 8027    }
 8028
 8029    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8030        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8031            MultiCursorModifier::Alt => modifiers.alt,
 8032            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8033        }
 8034    }
 8035
 8036    fn columnar_selection_mode(
 8037        modifiers: &Modifiers,
 8038        cx: &mut Context<Self>,
 8039    ) -> Option<ColumnarMode> {
 8040        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8041            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8042                Some(ColumnarMode::FromMouse)
 8043            } else if Self::is_alt_pressed(modifiers, cx) {
 8044                Some(ColumnarMode::FromSelection)
 8045            } else {
 8046                None
 8047            }
 8048        } else {
 8049            None
 8050        }
 8051    }
 8052
 8053    fn update_selection_mode(
 8054        &mut self,
 8055        modifiers: &Modifiers,
 8056        position_map: &PositionMap,
 8057        window: &mut Window,
 8058        cx: &mut Context<Self>,
 8059    ) {
 8060        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8061            return;
 8062        };
 8063        if self.selections.pending_anchor().is_none() {
 8064            return;
 8065        }
 8066
 8067        let mouse_position = window.mouse_position();
 8068        let point_for_position = position_map.point_for_position(mouse_position);
 8069        let position = point_for_position.previous_valid;
 8070
 8071        self.select(
 8072            SelectPhase::BeginColumnar {
 8073                position,
 8074                reset: false,
 8075                mode,
 8076                goal_column: point_for_position.exact_unclipped.column(),
 8077            },
 8078            window,
 8079            cx,
 8080        );
 8081    }
 8082
 8083    fn update_edit_prediction_preview(
 8084        &mut self,
 8085        modifiers: &Modifiers,
 8086        window: &mut Window,
 8087        cx: &mut Context<Self>,
 8088    ) {
 8089        let mut modifiers_held = false;
 8090
 8091        // Check bindings for all granularities.
 8092        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8093        let granularities = [
 8094            EditPredictionGranularity::Full,
 8095            EditPredictionGranularity::Line,
 8096            EditPredictionGranularity::Word,
 8097        ];
 8098
 8099        for granularity in granularities {
 8100            if let Some(keystroke) = self
 8101                .accept_edit_prediction_keybind(granularity, window, cx)
 8102                .keystroke()
 8103            {
 8104                modifiers_held = modifiers_held
 8105                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8106            }
 8107        }
 8108
 8109        if modifiers_held {
 8110            if matches!(
 8111                self.edit_prediction_preview,
 8112                EditPredictionPreview::Inactive { .. }
 8113            ) {
 8114                self.edit_prediction_preview = EditPredictionPreview::Active {
 8115                    previous_scroll_position: None,
 8116                    since: Instant::now(),
 8117                };
 8118
 8119                self.update_visible_edit_prediction(window, cx);
 8120                cx.notify();
 8121            }
 8122        } else if let EditPredictionPreview::Active {
 8123            previous_scroll_position,
 8124            since,
 8125        } = self.edit_prediction_preview
 8126        {
 8127            if let (Some(previous_scroll_position), Some(position_map)) =
 8128                (previous_scroll_position, self.last_position_map.as_ref())
 8129            {
 8130                self.set_scroll_position(
 8131                    previous_scroll_position
 8132                        .scroll_position(&position_map.snapshot.display_snapshot),
 8133                    window,
 8134                    cx,
 8135                );
 8136            }
 8137
 8138            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8139                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8140            };
 8141            self.clear_row_highlights::<EditPredictionPreview>();
 8142            self.update_visible_edit_prediction(window, cx);
 8143            cx.notify();
 8144        }
 8145    }
 8146
 8147    fn update_visible_edit_prediction(
 8148        &mut self,
 8149        _window: &mut Window,
 8150        cx: &mut Context<Self>,
 8151    ) -> Option<()> {
 8152        if DisableAiSettings::get_global(cx).disable_ai {
 8153            return None;
 8154        }
 8155
 8156        if self.ime_transaction.is_some() {
 8157            self.discard_edit_prediction(false, cx);
 8158            return None;
 8159        }
 8160
 8161        let selection = self.selections.newest_anchor();
 8162        let cursor = selection.head();
 8163        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8164        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8165        let excerpt_id = cursor.excerpt_id;
 8166
 8167        let show_in_menu = self.show_edit_predictions_in_menu();
 8168        let completions_menu_has_precedence = !show_in_menu
 8169            && (self.context_menu.borrow().is_some()
 8170                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8171
 8172        if completions_menu_has_precedence
 8173            || !offset_selection.is_empty()
 8174            || self
 8175                .active_edit_prediction
 8176                .as_ref()
 8177                .is_some_and(|completion| {
 8178                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8179                        return false;
 8180                    };
 8181                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8182                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8183                    !invalidation_range.contains(&offset_selection.head())
 8184                })
 8185        {
 8186            self.discard_edit_prediction(false, cx);
 8187            return None;
 8188        }
 8189
 8190        self.take_active_edit_prediction(cx);
 8191        let Some(provider) = self.edit_prediction_provider() else {
 8192            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8193            return None;
 8194        };
 8195
 8196        let (buffer, cursor_buffer_position) =
 8197            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8198
 8199        self.edit_prediction_settings =
 8200            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8201
 8202        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8203
 8204        if self.edit_prediction_indent_conflict {
 8205            let cursor_point = cursor.to_point(&multibuffer);
 8206            let mut suggested_indent = None;
 8207            multibuffer.suggested_indents_callback(
 8208                cursor_point.row..cursor_point.row + 1,
 8209                |_, indent| {
 8210                    suggested_indent = Some(indent);
 8211                    ControlFlow::Break(())
 8212                },
 8213                cx,
 8214            );
 8215
 8216            if let Some(indent) = suggested_indent
 8217                && indent.len == cursor_point.column
 8218            {
 8219                self.edit_prediction_indent_conflict = false;
 8220            }
 8221        }
 8222
 8223        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8224
 8225        let (completion_id, edits, edit_preview) = match edit_prediction {
 8226            edit_prediction_types::EditPrediction::Local {
 8227                id,
 8228                edits,
 8229                edit_preview,
 8230            } => (id, edits, edit_preview),
 8231            edit_prediction_types::EditPrediction::Jump {
 8232                id,
 8233                snapshot,
 8234                target,
 8235            } => {
 8236                if let Some(provider) = &self.edit_prediction_provider {
 8237                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8238                }
 8239                self.stale_edit_prediction_in_menu = None;
 8240                self.active_edit_prediction = Some(EditPredictionState {
 8241                    inlay_ids: vec![],
 8242                    completion: EditPrediction::MoveOutside { snapshot, target },
 8243                    completion_id: id,
 8244                    invalidation_range: None,
 8245                });
 8246                cx.notify();
 8247                return Some(());
 8248            }
 8249        };
 8250
 8251        let edits = edits
 8252            .into_iter()
 8253            .flat_map(|(range, new_text)| {
 8254                Some((
 8255                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8256                    new_text,
 8257                ))
 8258            })
 8259            .collect::<Vec<_>>();
 8260        if edits.is_empty() {
 8261            return None;
 8262        }
 8263
 8264        let first_edit_start = edits.first().unwrap().0.start;
 8265        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8266        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8267
 8268        let last_edit_end = edits.last().unwrap().0.end;
 8269        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8270        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8271
 8272        let cursor_row = cursor.to_point(&multibuffer).row;
 8273
 8274        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8275
 8276        let mut inlay_ids = Vec::new();
 8277        let invalidation_row_range;
 8278        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8279            Some(cursor_row..edit_end_row)
 8280        } else if cursor_row > edit_end_row {
 8281            Some(edit_start_row..cursor_row)
 8282        } else {
 8283            None
 8284        };
 8285        let supports_jump = self
 8286            .edit_prediction_provider
 8287            .as_ref()
 8288            .map(|provider| provider.provider.supports_jump_to_edit())
 8289            .unwrap_or(true);
 8290
 8291        let is_move = supports_jump
 8292            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8293        let completion = if is_move {
 8294            if let Some(provider) = &self.edit_prediction_provider {
 8295                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8296            }
 8297            invalidation_row_range =
 8298                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8299            let target = first_edit_start;
 8300            EditPrediction::MoveWithin { target, snapshot }
 8301        } else {
 8302            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8303                && !self.edit_predictions_hidden_for_vim_mode;
 8304
 8305            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8306                if provider.show_tab_accept_marker() {
 8307                    EditDisplayMode::TabAccept
 8308                } else {
 8309                    EditDisplayMode::Inline
 8310                }
 8311            } else {
 8312                EditDisplayMode::DiffPopover
 8313            };
 8314
 8315            if show_completions_in_buffer {
 8316                if let Some(provider) = &self.edit_prediction_provider {
 8317                    let suggestion_display_type = match display_mode {
 8318                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8319                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8320                            SuggestionDisplayType::GhostText
 8321                        }
 8322                    };
 8323                    provider.provider.did_show(suggestion_display_type, cx);
 8324                }
 8325                if edits
 8326                    .iter()
 8327                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8328                {
 8329                    let mut inlays = Vec::new();
 8330                    for (range, new_text) in &edits {
 8331                        let inlay = Inlay::edit_prediction(
 8332                            post_inc(&mut self.next_inlay_id),
 8333                            range.start,
 8334                            new_text.as_ref(),
 8335                        );
 8336                        inlay_ids.push(inlay.id);
 8337                        inlays.push(inlay);
 8338                    }
 8339
 8340                    self.splice_inlays(&[], inlays, cx);
 8341                } else {
 8342                    let background_color = cx.theme().status().deleted_background;
 8343                    self.highlight_text::<EditPredictionHighlight>(
 8344                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8345                        HighlightStyle {
 8346                            background_color: Some(background_color),
 8347                            ..Default::default()
 8348                        },
 8349                        cx,
 8350                    );
 8351                }
 8352            }
 8353
 8354            invalidation_row_range = edit_start_row..edit_end_row;
 8355
 8356            EditPrediction::Edit {
 8357                edits,
 8358                edit_preview,
 8359                display_mode,
 8360                snapshot,
 8361            }
 8362        };
 8363
 8364        let invalidation_range = multibuffer
 8365            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8366            ..multibuffer.anchor_after(Point::new(
 8367                invalidation_row_range.end,
 8368                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8369            ));
 8370
 8371        self.stale_edit_prediction_in_menu = None;
 8372        self.active_edit_prediction = Some(EditPredictionState {
 8373            inlay_ids,
 8374            completion,
 8375            completion_id,
 8376            invalidation_range: Some(invalidation_range),
 8377        });
 8378
 8379        cx.notify();
 8380
 8381        Some(())
 8382    }
 8383
 8384    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8385        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8386    }
 8387
 8388    fn clear_tasks(&mut self) {
 8389        self.tasks.clear()
 8390    }
 8391
 8392    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8393        if self.tasks.insert(key, value).is_some() {
 8394            // This case should hopefully be rare, but just in case...
 8395            log::error!(
 8396                "multiple different run targets found on a single line, only the last target will be rendered"
 8397            )
 8398        }
 8399    }
 8400
 8401    /// Get all display points of breakpoints that will be rendered within editor
 8402    ///
 8403    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8404    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8405    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8406    fn active_breakpoints(
 8407        &self,
 8408        range: Range<DisplayRow>,
 8409        window: &mut Window,
 8410        cx: &mut Context<Self>,
 8411    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8412        let mut breakpoint_display_points = HashMap::default();
 8413
 8414        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8415            return breakpoint_display_points;
 8416        };
 8417
 8418        let snapshot = self.snapshot(window, cx);
 8419
 8420        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8421        let Some(project) = self.project() else {
 8422            return breakpoint_display_points;
 8423        };
 8424
 8425        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8426            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8427
 8428        for (buffer_snapshot, range, excerpt_id) in
 8429            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8430        {
 8431            let Some(buffer) = project
 8432                .read(cx)
 8433                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8434            else {
 8435                continue;
 8436            };
 8437            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8438                &buffer,
 8439                Some(
 8440                    buffer_snapshot.anchor_before(range.start)
 8441                        ..buffer_snapshot.anchor_after(range.end),
 8442                ),
 8443                buffer_snapshot,
 8444                cx,
 8445            );
 8446            for (breakpoint, state) in breakpoints {
 8447                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8448                let position = multi_buffer_anchor
 8449                    .to_point(&multi_buffer_snapshot)
 8450                    .to_display_point(&snapshot);
 8451
 8452                breakpoint_display_points.insert(
 8453                    position.row(),
 8454                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8455                );
 8456            }
 8457        }
 8458
 8459        breakpoint_display_points
 8460    }
 8461
 8462    fn breakpoint_context_menu(
 8463        &self,
 8464        anchor: Anchor,
 8465        window: &mut Window,
 8466        cx: &mut Context<Self>,
 8467    ) -> Entity<ui::ContextMenu> {
 8468        let weak_editor = cx.weak_entity();
 8469        let focus_handle = self.focus_handle(cx);
 8470
 8471        let row = self
 8472            .buffer
 8473            .read(cx)
 8474            .snapshot(cx)
 8475            .summary_for_anchor::<Point>(&anchor)
 8476            .row;
 8477
 8478        let breakpoint = self
 8479            .breakpoint_at_row(row, window, cx)
 8480            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8481
 8482        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8483            "Edit Log Breakpoint"
 8484        } else {
 8485            "Set Log Breakpoint"
 8486        };
 8487
 8488        let condition_breakpoint_msg = if breakpoint
 8489            .as_ref()
 8490            .is_some_and(|bp| bp.1.condition.is_some())
 8491        {
 8492            "Edit Condition Breakpoint"
 8493        } else {
 8494            "Set Condition Breakpoint"
 8495        };
 8496
 8497        let hit_condition_breakpoint_msg = if breakpoint
 8498            .as_ref()
 8499            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8500        {
 8501            "Edit Hit Condition Breakpoint"
 8502        } else {
 8503            "Set Hit Condition Breakpoint"
 8504        };
 8505
 8506        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8507            "Unset Breakpoint"
 8508        } else {
 8509            "Set Breakpoint"
 8510        };
 8511
 8512        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8513
 8514        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8515            BreakpointState::Enabled => Some("Disable"),
 8516            BreakpointState::Disabled => Some("Enable"),
 8517        });
 8518
 8519        let (anchor, breakpoint) =
 8520            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8521
 8522        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8523            menu.on_blur_subscription(Subscription::new(|| {}))
 8524                .context(focus_handle)
 8525                .when(run_to_cursor, |this| {
 8526                    let weak_editor = weak_editor.clone();
 8527                    this.entry("Run to cursor", None, move |window, cx| {
 8528                        weak_editor
 8529                            .update(cx, |editor, cx| {
 8530                                editor.change_selections(
 8531                                    SelectionEffects::no_scroll(),
 8532                                    window,
 8533                                    cx,
 8534                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8535                                );
 8536                            })
 8537                            .ok();
 8538
 8539                        window.dispatch_action(Box::new(RunToCursor), cx);
 8540                    })
 8541                    .separator()
 8542                })
 8543                .when_some(toggle_state_msg, |this, msg| {
 8544                    this.entry(msg, None, {
 8545                        let weak_editor = weak_editor.clone();
 8546                        let breakpoint = breakpoint.clone();
 8547                        move |_window, cx| {
 8548                            weak_editor
 8549                                .update(cx, |this, cx| {
 8550                                    this.edit_breakpoint_at_anchor(
 8551                                        anchor,
 8552                                        breakpoint.as_ref().clone(),
 8553                                        BreakpointEditAction::InvertState,
 8554                                        cx,
 8555                                    );
 8556                                })
 8557                                .log_err();
 8558                        }
 8559                    })
 8560                })
 8561                .entry(set_breakpoint_msg, None, {
 8562                    let weak_editor = weak_editor.clone();
 8563                    let breakpoint = breakpoint.clone();
 8564                    move |_window, cx| {
 8565                        weak_editor
 8566                            .update(cx, |this, cx| {
 8567                                this.edit_breakpoint_at_anchor(
 8568                                    anchor,
 8569                                    breakpoint.as_ref().clone(),
 8570                                    BreakpointEditAction::Toggle,
 8571                                    cx,
 8572                                );
 8573                            })
 8574                            .log_err();
 8575                    }
 8576                })
 8577                .entry(log_breakpoint_msg, None, {
 8578                    let breakpoint = breakpoint.clone();
 8579                    let weak_editor = weak_editor.clone();
 8580                    move |window, cx| {
 8581                        weak_editor
 8582                            .update(cx, |this, cx| {
 8583                                this.add_edit_breakpoint_block(
 8584                                    anchor,
 8585                                    breakpoint.as_ref(),
 8586                                    BreakpointPromptEditAction::Log,
 8587                                    window,
 8588                                    cx,
 8589                                );
 8590                            })
 8591                            .log_err();
 8592                    }
 8593                })
 8594                .entry(condition_breakpoint_msg, None, {
 8595                    let breakpoint = breakpoint.clone();
 8596                    let weak_editor = weak_editor.clone();
 8597                    move |window, cx| {
 8598                        weak_editor
 8599                            .update(cx, |this, cx| {
 8600                                this.add_edit_breakpoint_block(
 8601                                    anchor,
 8602                                    breakpoint.as_ref(),
 8603                                    BreakpointPromptEditAction::Condition,
 8604                                    window,
 8605                                    cx,
 8606                                );
 8607                            })
 8608                            .log_err();
 8609                    }
 8610                })
 8611                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8612                    weak_editor
 8613                        .update(cx, |this, cx| {
 8614                            this.add_edit_breakpoint_block(
 8615                                anchor,
 8616                                breakpoint.as_ref(),
 8617                                BreakpointPromptEditAction::HitCondition,
 8618                                window,
 8619                                cx,
 8620                            );
 8621                        })
 8622                        .log_err();
 8623                })
 8624        })
 8625    }
 8626
 8627    fn render_breakpoint(
 8628        &self,
 8629        position: Anchor,
 8630        row: DisplayRow,
 8631        breakpoint: &Breakpoint,
 8632        state: Option<BreakpointSessionState>,
 8633        cx: &mut Context<Self>,
 8634    ) -> IconButton {
 8635        let is_rejected = state.is_some_and(|s| !s.verified);
 8636        // Is it a breakpoint that shows up when hovering over gutter?
 8637        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8638            (false, false),
 8639            |PhantomBreakpointIndicator {
 8640                 is_active,
 8641                 display_row,
 8642                 collides_with_existing_breakpoint,
 8643             }| {
 8644                (
 8645                    is_active && display_row == row,
 8646                    collides_with_existing_breakpoint,
 8647                )
 8648            },
 8649        );
 8650
 8651        let (color, icon) = {
 8652            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8653                (false, false) => ui::IconName::DebugBreakpoint,
 8654                (true, false) => ui::IconName::DebugLogBreakpoint,
 8655                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8656                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8657            };
 8658
 8659            let theme_colors = cx.theme().colors();
 8660
 8661            let color = if is_phantom {
 8662                if collides_with_existing {
 8663                    Color::Custom(
 8664                        theme_colors
 8665                            .debugger_accent
 8666                            .blend(theme_colors.text.opacity(0.6)),
 8667                    )
 8668                } else {
 8669                    Color::Hint
 8670                }
 8671            } else if is_rejected {
 8672                Color::Disabled
 8673            } else {
 8674                Color::Debugger
 8675            };
 8676
 8677            (color, icon)
 8678        };
 8679
 8680        let breakpoint = Arc::from(breakpoint.clone());
 8681
 8682        let alt_as_text = gpui::Keystroke {
 8683            modifiers: Modifiers::secondary_key(),
 8684            ..Default::default()
 8685        };
 8686        let primary_action_text = if breakpoint.is_disabled() {
 8687            "Enable breakpoint"
 8688        } else if is_phantom && !collides_with_existing {
 8689            "Set breakpoint"
 8690        } else {
 8691            "Unset breakpoint"
 8692        };
 8693        let focus_handle = self.focus_handle.clone();
 8694
 8695        let meta = if is_rejected {
 8696            SharedString::from("No executable code is associated with this line.")
 8697        } else if collides_with_existing && !breakpoint.is_disabled() {
 8698            SharedString::from(format!(
 8699                "{alt_as_text}-click to disable,\nright-click for more options."
 8700            ))
 8701        } else {
 8702            SharedString::from("Right-click for more options.")
 8703        };
 8704        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8705            .icon_size(IconSize::XSmall)
 8706            .size(ui::ButtonSize::None)
 8707            .when(is_rejected, |this| {
 8708                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8709            })
 8710            .icon_color(color)
 8711            .style(ButtonStyle::Transparent)
 8712            .on_click(cx.listener({
 8713                move |editor, event: &ClickEvent, window, cx| {
 8714                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8715                        BreakpointEditAction::InvertState
 8716                    } else {
 8717                        BreakpointEditAction::Toggle
 8718                    };
 8719
 8720                    window.focus(&editor.focus_handle(cx), cx);
 8721                    editor.edit_breakpoint_at_anchor(
 8722                        position,
 8723                        breakpoint.as_ref().clone(),
 8724                        edit_action,
 8725                        cx,
 8726                    );
 8727                }
 8728            }))
 8729            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8730                editor.set_breakpoint_context_menu(
 8731                    row,
 8732                    Some(position),
 8733                    event.position(),
 8734                    window,
 8735                    cx,
 8736                );
 8737            }))
 8738            .tooltip(move |_window, cx| {
 8739                Tooltip::with_meta_in(
 8740                    primary_action_text,
 8741                    Some(&ToggleBreakpoint),
 8742                    meta.clone(),
 8743                    &focus_handle,
 8744                    cx,
 8745                )
 8746            })
 8747    }
 8748
 8749    fn build_tasks_context(
 8750        project: &Entity<Project>,
 8751        buffer: &Entity<Buffer>,
 8752        buffer_row: u32,
 8753        tasks: &Arc<RunnableTasks>,
 8754        cx: &mut Context<Self>,
 8755    ) -> Task<Option<task::TaskContext>> {
 8756        let position = Point::new(buffer_row, tasks.column);
 8757        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8758        let location = Location {
 8759            buffer: buffer.clone(),
 8760            range: range_start..range_start,
 8761        };
 8762        // Fill in the environmental variables from the tree-sitter captures
 8763        let mut captured_task_variables = TaskVariables::default();
 8764        for (capture_name, value) in tasks.extra_variables.clone() {
 8765            captured_task_variables.insert(
 8766                task::VariableName::Custom(capture_name.into()),
 8767                value.clone(),
 8768            );
 8769        }
 8770        project.update(cx, |project, cx| {
 8771            project.task_store().update(cx, |task_store, cx| {
 8772                task_store.task_context_for_location(captured_task_variables, location, cx)
 8773            })
 8774        })
 8775    }
 8776
 8777    pub fn spawn_nearest_task(
 8778        &mut self,
 8779        action: &SpawnNearestTask,
 8780        window: &mut Window,
 8781        cx: &mut Context<Self>,
 8782    ) {
 8783        let Some((workspace, _)) = self.workspace.clone() else {
 8784            return;
 8785        };
 8786        let Some(project) = self.project.clone() else {
 8787            return;
 8788        };
 8789
 8790        // Try to find a closest, enclosing node using tree-sitter that has a task
 8791        let Some((buffer, buffer_row, tasks)) = self
 8792            .find_enclosing_node_task(cx)
 8793            // Or find the task that's closest in row-distance.
 8794            .or_else(|| self.find_closest_task(cx))
 8795        else {
 8796            return;
 8797        };
 8798
 8799        let reveal_strategy = action.reveal;
 8800        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8801        cx.spawn_in(window, async move |_, cx| {
 8802            let context = task_context.await?;
 8803            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8804
 8805            let resolved = &mut resolved_task.resolved;
 8806            resolved.reveal = reveal_strategy;
 8807
 8808            workspace
 8809                .update_in(cx, |workspace, window, cx| {
 8810                    workspace.schedule_resolved_task(
 8811                        task_source_kind,
 8812                        resolved_task,
 8813                        false,
 8814                        window,
 8815                        cx,
 8816                    );
 8817                })
 8818                .ok()
 8819        })
 8820        .detach();
 8821    }
 8822
 8823    fn find_closest_task(
 8824        &mut self,
 8825        cx: &mut Context<Self>,
 8826    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8827        let cursor_row = self
 8828            .selections
 8829            .newest_adjusted(&self.display_snapshot(cx))
 8830            .head()
 8831            .row;
 8832
 8833        let ((buffer_id, row), tasks) = self
 8834            .tasks
 8835            .iter()
 8836            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8837
 8838        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8839        let tasks = Arc::new(tasks.to_owned());
 8840        Some((buffer, *row, tasks))
 8841    }
 8842
 8843    fn find_enclosing_node_task(
 8844        &mut self,
 8845        cx: &mut Context<Self>,
 8846    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8847        let snapshot = self.buffer.read(cx).snapshot(cx);
 8848        let offset = self
 8849            .selections
 8850            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8851            .head();
 8852        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8853        let offset = excerpt.map_offset_to_buffer(offset);
 8854        let buffer_id = excerpt.buffer().remote_id();
 8855
 8856        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8857        let mut cursor = layer.node().walk();
 8858
 8859        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8860            if cursor.node().end_byte() == offset.0 {
 8861                cursor.goto_next_sibling();
 8862            }
 8863        }
 8864
 8865        // Ascend to the smallest ancestor that contains the range and has a task.
 8866        loop {
 8867            let node = cursor.node();
 8868            let node_range = node.byte_range();
 8869            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8870
 8871            // Check if this node contains our offset
 8872            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8873                // If it contains offset, check for task
 8874                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8875                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8876                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8877                }
 8878            }
 8879
 8880            if !cursor.goto_parent() {
 8881                break;
 8882            }
 8883        }
 8884        None
 8885    }
 8886
 8887    fn render_run_indicator(
 8888        &self,
 8889        _style: &EditorStyle,
 8890        is_active: bool,
 8891        row: DisplayRow,
 8892        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8893        cx: &mut Context<Self>,
 8894    ) -> IconButton {
 8895        let color = Color::Muted;
 8896        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8897
 8898        IconButton::new(
 8899            ("run_indicator", row.0 as usize),
 8900            ui::IconName::PlayOutlined,
 8901        )
 8902        .shape(ui::IconButtonShape::Square)
 8903        .icon_size(IconSize::XSmall)
 8904        .icon_color(color)
 8905        .toggle_state(is_active)
 8906        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8907            let quick_launch = match e {
 8908                ClickEvent::Keyboard(_) => true,
 8909                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8910            };
 8911
 8912            window.focus(&editor.focus_handle(cx), cx);
 8913            editor.toggle_code_actions(
 8914                &ToggleCodeActions {
 8915                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8916                    quick_launch,
 8917                },
 8918                window,
 8919                cx,
 8920            );
 8921        }))
 8922        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8923            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8924        }))
 8925    }
 8926
 8927    pub fn context_menu_visible(&self) -> bool {
 8928        !self.edit_prediction_preview_is_active()
 8929            && self
 8930                .context_menu
 8931                .borrow()
 8932                .as_ref()
 8933                .is_some_and(|menu| menu.visible())
 8934    }
 8935
 8936    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8937        self.context_menu
 8938            .borrow()
 8939            .as_ref()
 8940            .map(|menu| menu.origin())
 8941    }
 8942
 8943    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8944        self.context_menu_options = Some(options);
 8945    }
 8946
 8947    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8948    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8949
 8950    fn render_edit_prediction_popover(
 8951        &mut self,
 8952        text_bounds: &Bounds<Pixels>,
 8953        content_origin: gpui::Point<Pixels>,
 8954        right_margin: Pixels,
 8955        editor_snapshot: &EditorSnapshot,
 8956        visible_row_range: Range<DisplayRow>,
 8957        scroll_top: ScrollOffset,
 8958        scroll_bottom: ScrollOffset,
 8959        line_layouts: &[LineWithInvisibles],
 8960        line_height: Pixels,
 8961        scroll_position: gpui::Point<ScrollOffset>,
 8962        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8963        newest_selection_head: Option<DisplayPoint>,
 8964        editor_width: Pixels,
 8965        style: &EditorStyle,
 8966        window: &mut Window,
 8967        cx: &mut App,
 8968    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8969        if self.mode().is_minimap() {
 8970            return None;
 8971        }
 8972        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8973
 8974        if self.edit_prediction_visible_in_cursor_popover(true) {
 8975            return None;
 8976        }
 8977
 8978        match &active_edit_prediction.completion {
 8979            EditPrediction::MoveWithin { target, .. } => {
 8980                let target_display_point = target.to_display_point(editor_snapshot);
 8981
 8982                if self.edit_prediction_requires_modifier() {
 8983                    if !self.edit_prediction_preview_is_active() {
 8984                        return None;
 8985                    }
 8986
 8987                    self.render_edit_prediction_modifier_jump_popover(
 8988                        text_bounds,
 8989                        content_origin,
 8990                        visible_row_range,
 8991                        line_layouts,
 8992                        line_height,
 8993                        scroll_pixel_position,
 8994                        newest_selection_head,
 8995                        target_display_point,
 8996                        window,
 8997                        cx,
 8998                    )
 8999                } else {
 9000                    self.render_edit_prediction_eager_jump_popover(
 9001                        text_bounds,
 9002                        content_origin,
 9003                        editor_snapshot,
 9004                        visible_row_range,
 9005                        scroll_top,
 9006                        scroll_bottom,
 9007                        line_height,
 9008                        scroll_pixel_position,
 9009                        target_display_point,
 9010                        editor_width,
 9011                        window,
 9012                        cx,
 9013                    )
 9014                }
 9015            }
 9016            EditPrediction::Edit {
 9017                display_mode: EditDisplayMode::Inline,
 9018                ..
 9019            } => None,
 9020            EditPrediction::Edit {
 9021                display_mode: EditDisplayMode::TabAccept,
 9022                edits,
 9023                ..
 9024            } => {
 9025                let range = &edits.first()?.0;
 9026                let target_display_point = range.end.to_display_point(editor_snapshot);
 9027
 9028                self.render_edit_prediction_end_of_line_popover(
 9029                    "Accept",
 9030                    editor_snapshot,
 9031                    visible_row_range,
 9032                    target_display_point,
 9033                    line_height,
 9034                    scroll_pixel_position,
 9035                    content_origin,
 9036                    editor_width,
 9037                    window,
 9038                    cx,
 9039                )
 9040            }
 9041            EditPrediction::Edit {
 9042                edits,
 9043                edit_preview,
 9044                display_mode: EditDisplayMode::DiffPopover,
 9045                snapshot,
 9046            } => self.render_edit_prediction_diff_popover(
 9047                text_bounds,
 9048                content_origin,
 9049                right_margin,
 9050                editor_snapshot,
 9051                visible_row_range,
 9052                line_layouts,
 9053                line_height,
 9054                scroll_position,
 9055                scroll_pixel_position,
 9056                newest_selection_head,
 9057                editor_width,
 9058                style,
 9059                edits,
 9060                edit_preview,
 9061                snapshot,
 9062                window,
 9063                cx,
 9064            ),
 9065            EditPrediction::MoveOutside { snapshot, .. } => {
 9066                let mut element = self
 9067                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9068                    .into_any();
 9069
 9070                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9071                let origin_x = text_bounds.size.width - size.width - px(30.);
 9072                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9073                element.prepaint_at(origin, window, cx);
 9074
 9075                Some((element, origin))
 9076            }
 9077        }
 9078    }
 9079
 9080    fn render_edit_prediction_modifier_jump_popover(
 9081        &mut self,
 9082        text_bounds: &Bounds<Pixels>,
 9083        content_origin: gpui::Point<Pixels>,
 9084        visible_row_range: Range<DisplayRow>,
 9085        line_layouts: &[LineWithInvisibles],
 9086        line_height: Pixels,
 9087        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9088        newest_selection_head: Option<DisplayPoint>,
 9089        target_display_point: DisplayPoint,
 9090        window: &mut Window,
 9091        cx: &mut App,
 9092    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9093        let scrolled_content_origin =
 9094            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9095
 9096        const SCROLL_PADDING_Y: Pixels = px(12.);
 9097
 9098        if target_display_point.row() < visible_row_range.start {
 9099            return self.render_edit_prediction_scroll_popover(
 9100                |_| SCROLL_PADDING_Y,
 9101                IconName::ArrowUp,
 9102                visible_row_range,
 9103                line_layouts,
 9104                newest_selection_head,
 9105                scrolled_content_origin,
 9106                window,
 9107                cx,
 9108            );
 9109        } else if target_display_point.row() >= visible_row_range.end {
 9110            return self.render_edit_prediction_scroll_popover(
 9111                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9112                IconName::ArrowDown,
 9113                visible_row_range,
 9114                line_layouts,
 9115                newest_selection_head,
 9116                scrolled_content_origin,
 9117                window,
 9118                cx,
 9119            );
 9120        }
 9121
 9122        const POLE_WIDTH: Pixels = px(2.);
 9123
 9124        let line_layout =
 9125            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9126        let target_column = target_display_point.column() as usize;
 9127
 9128        let target_x = line_layout.x_for_index(target_column);
 9129        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9130            - scroll_pixel_position.y;
 9131
 9132        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9133
 9134        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9135        border_color.l += 0.001;
 9136
 9137        let mut element = v_flex()
 9138            .items_end()
 9139            .when(flag_on_right, |el| el.items_start())
 9140            .child(if flag_on_right {
 9141                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9142                    .rounded_bl(px(0.))
 9143                    .rounded_tl(px(0.))
 9144                    .border_l_2()
 9145                    .border_color(border_color)
 9146            } else {
 9147                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9148                    .rounded_br(px(0.))
 9149                    .rounded_tr(px(0.))
 9150                    .border_r_2()
 9151                    .border_color(border_color)
 9152            })
 9153            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9154            .into_any();
 9155
 9156        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9157
 9158        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9159            - point(
 9160                if flag_on_right {
 9161                    POLE_WIDTH
 9162                } else {
 9163                    size.width - POLE_WIDTH
 9164                },
 9165                size.height - line_height,
 9166            );
 9167
 9168        origin.x = origin.x.max(content_origin.x);
 9169
 9170        element.prepaint_at(origin, window, cx);
 9171
 9172        Some((element, origin))
 9173    }
 9174
 9175    fn render_edit_prediction_scroll_popover(
 9176        &mut self,
 9177        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9178        scroll_icon: IconName,
 9179        visible_row_range: Range<DisplayRow>,
 9180        line_layouts: &[LineWithInvisibles],
 9181        newest_selection_head: Option<DisplayPoint>,
 9182        scrolled_content_origin: gpui::Point<Pixels>,
 9183        window: &mut Window,
 9184        cx: &mut App,
 9185    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9186        let mut element = self
 9187            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9188            .into_any();
 9189
 9190        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9191
 9192        let cursor = newest_selection_head?;
 9193        let cursor_row_layout =
 9194            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9195        let cursor_column = cursor.column() as usize;
 9196
 9197        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9198
 9199        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9200
 9201        element.prepaint_at(origin, window, cx);
 9202        Some((element, origin))
 9203    }
 9204
 9205    fn render_edit_prediction_eager_jump_popover(
 9206        &mut self,
 9207        text_bounds: &Bounds<Pixels>,
 9208        content_origin: gpui::Point<Pixels>,
 9209        editor_snapshot: &EditorSnapshot,
 9210        visible_row_range: Range<DisplayRow>,
 9211        scroll_top: ScrollOffset,
 9212        scroll_bottom: ScrollOffset,
 9213        line_height: Pixels,
 9214        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9215        target_display_point: DisplayPoint,
 9216        editor_width: Pixels,
 9217        window: &mut Window,
 9218        cx: &mut App,
 9219    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9220        if target_display_point.row().as_f64() < scroll_top {
 9221            let mut element = self
 9222                .render_edit_prediction_line_popover(
 9223                    "Jump to Edit",
 9224                    Some(IconName::ArrowUp),
 9225                    window,
 9226                    cx,
 9227                )
 9228                .into_any();
 9229
 9230            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9231            let offset = point(
 9232                (text_bounds.size.width - size.width) / 2.,
 9233                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9234            );
 9235
 9236            let origin = text_bounds.origin + offset;
 9237            element.prepaint_at(origin, window, cx);
 9238            Some((element, origin))
 9239        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9240            let mut element = self
 9241                .render_edit_prediction_line_popover(
 9242                    "Jump to Edit",
 9243                    Some(IconName::ArrowDown),
 9244                    window,
 9245                    cx,
 9246                )
 9247                .into_any();
 9248
 9249            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9250            let offset = point(
 9251                (text_bounds.size.width - size.width) / 2.,
 9252                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9253            );
 9254
 9255            let origin = text_bounds.origin + offset;
 9256            element.prepaint_at(origin, window, cx);
 9257            Some((element, origin))
 9258        } else {
 9259            self.render_edit_prediction_end_of_line_popover(
 9260                "Jump to Edit",
 9261                editor_snapshot,
 9262                visible_row_range,
 9263                target_display_point,
 9264                line_height,
 9265                scroll_pixel_position,
 9266                content_origin,
 9267                editor_width,
 9268                window,
 9269                cx,
 9270            )
 9271        }
 9272    }
 9273
 9274    fn render_edit_prediction_end_of_line_popover(
 9275        self: &mut Editor,
 9276        label: &'static str,
 9277        editor_snapshot: &EditorSnapshot,
 9278        visible_row_range: Range<DisplayRow>,
 9279        target_display_point: DisplayPoint,
 9280        line_height: Pixels,
 9281        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9282        content_origin: gpui::Point<Pixels>,
 9283        editor_width: Pixels,
 9284        window: &mut Window,
 9285        cx: &mut App,
 9286    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9287        let target_line_end = DisplayPoint::new(
 9288            target_display_point.row(),
 9289            editor_snapshot.line_len(target_display_point.row()),
 9290        );
 9291
 9292        let mut element = self
 9293            .render_edit_prediction_line_popover(label, None, window, cx)
 9294            .into_any();
 9295
 9296        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9297
 9298        let line_origin =
 9299            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9300
 9301        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9302        let mut origin = start_point
 9303            + line_origin
 9304            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9305        origin.x = origin.x.max(content_origin.x);
 9306
 9307        let max_x = content_origin.x + editor_width - size.width;
 9308
 9309        if origin.x > max_x {
 9310            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9311
 9312            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9313                origin.y += offset;
 9314                IconName::ArrowUp
 9315            } else {
 9316                origin.y -= offset;
 9317                IconName::ArrowDown
 9318            };
 9319
 9320            element = self
 9321                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9322                .into_any();
 9323
 9324            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9325
 9326            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9327        }
 9328
 9329        element.prepaint_at(origin, window, cx);
 9330        Some((element, origin))
 9331    }
 9332
 9333    fn render_edit_prediction_diff_popover(
 9334        self: &Editor,
 9335        text_bounds: &Bounds<Pixels>,
 9336        content_origin: gpui::Point<Pixels>,
 9337        right_margin: Pixels,
 9338        editor_snapshot: &EditorSnapshot,
 9339        visible_row_range: Range<DisplayRow>,
 9340        line_layouts: &[LineWithInvisibles],
 9341        line_height: Pixels,
 9342        scroll_position: gpui::Point<ScrollOffset>,
 9343        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9344        newest_selection_head: Option<DisplayPoint>,
 9345        editor_width: Pixels,
 9346        style: &EditorStyle,
 9347        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9348        edit_preview: &Option<language::EditPreview>,
 9349        snapshot: &language::BufferSnapshot,
 9350        window: &mut Window,
 9351        cx: &mut App,
 9352    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9353        let edit_start = edits
 9354            .first()
 9355            .unwrap()
 9356            .0
 9357            .start
 9358            .to_display_point(editor_snapshot);
 9359        let edit_end = edits
 9360            .last()
 9361            .unwrap()
 9362            .0
 9363            .end
 9364            .to_display_point(editor_snapshot);
 9365
 9366        let is_visible = visible_row_range.contains(&edit_start.row())
 9367            || visible_row_range.contains(&edit_end.row());
 9368        if !is_visible {
 9369            return None;
 9370        }
 9371
 9372        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9373            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9374        } else {
 9375            // Fallback for providers without edit_preview
 9376            crate::edit_prediction_fallback_text(edits, cx)
 9377        };
 9378
 9379        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9380        let line_count = highlighted_edits.text.lines().count();
 9381
 9382        const BORDER_WIDTH: Pixels = px(1.);
 9383
 9384        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9385        let has_keybind = keybind.is_some();
 9386
 9387        let mut element = h_flex()
 9388            .items_start()
 9389            .child(
 9390                h_flex()
 9391                    .bg(cx.theme().colors().editor_background)
 9392                    .border(BORDER_WIDTH)
 9393                    .shadow_xs()
 9394                    .border_color(cx.theme().colors().border)
 9395                    .rounded_l_lg()
 9396                    .when(line_count > 1, |el| el.rounded_br_lg())
 9397                    .pr_1()
 9398                    .child(styled_text),
 9399            )
 9400            .child(
 9401                h_flex()
 9402                    .h(line_height + BORDER_WIDTH * 2.)
 9403                    .px_1p5()
 9404                    .gap_1()
 9405                    // Workaround: For some reason, there's a gap if we don't do this
 9406                    .ml(-BORDER_WIDTH)
 9407                    .shadow(vec![gpui::BoxShadow {
 9408                        color: gpui::black().opacity(0.05),
 9409                        offset: point(px(1.), px(1.)),
 9410                        blur_radius: px(2.),
 9411                        spread_radius: px(0.),
 9412                    }])
 9413                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9414                    .border(BORDER_WIDTH)
 9415                    .border_color(cx.theme().colors().border)
 9416                    .rounded_r_lg()
 9417                    .id("edit_prediction_diff_popover_keybind")
 9418                    .when(!has_keybind, |el| {
 9419                        let status_colors = cx.theme().status();
 9420
 9421                        el.bg(status_colors.error_background)
 9422                            .border_color(status_colors.error.opacity(0.6))
 9423                            .child(Icon::new(IconName::Info).color(Color::Error))
 9424                            .cursor_default()
 9425                            .hoverable_tooltip(move |_window, cx| {
 9426                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9427                            })
 9428                    })
 9429                    .children(keybind),
 9430            )
 9431            .into_any();
 9432
 9433        let longest_row =
 9434            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9435        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9436            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9437        } else {
 9438            layout_line(
 9439                longest_row,
 9440                editor_snapshot,
 9441                style,
 9442                editor_width,
 9443                |_| false,
 9444                window,
 9445                cx,
 9446            )
 9447            .width
 9448        };
 9449
 9450        let viewport_bounds =
 9451            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9452                right: -right_margin,
 9453                ..Default::default()
 9454            });
 9455
 9456        let x_after_longest = Pixels::from(
 9457            ScrollPixelOffset::from(
 9458                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9459            ) - scroll_pixel_position.x,
 9460        );
 9461
 9462        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9463
 9464        // Fully visible if it can be displayed within the window (allow overlapping other
 9465        // panes). However, this is only allowed if the popover starts within text_bounds.
 9466        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9467            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9468
 9469        let mut origin = if can_position_to_the_right {
 9470            point(
 9471                x_after_longest,
 9472                text_bounds.origin.y
 9473                    + Pixels::from(
 9474                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9475                            - scroll_pixel_position.y,
 9476                    ),
 9477            )
 9478        } else {
 9479            let cursor_row = newest_selection_head.map(|head| head.row());
 9480            let above_edit = edit_start
 9481                .row()
 9482                .0
 9483                .checked_sub(line_count as u32)
 9484                .map(DisplayRow);
 9485            let below_edit = Some(edit_end.row() + 1);
 9486            let above_cursor =
 9487                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9488            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9489
 9490            // Place the edit popover adjacent to the edit if there is a location
 9491            // available that is onscreen and does not obscure the cursor. Otherwise,
 9492            // place it adjacent to the cursor.
 9493            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9494                .into_iter()
 9495                .flatten()
 9496                .find(|&start_row| {
 9497                    let end_row = start_row + line_count as u32;
 9498                    visible_row_range.contains(&start_row)
 9499                        && visible_row_range.contains(&end_row)
 9500                        && cursor_row
 9501                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9502                })?;
 9503
 9504            content_origin
 9505                + point(
 9506                    Pixels::from(-scroll_pixel_position.x),
 9507                    Pixels::from(
 9508                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9509                    ),
 9510                )
 9511        };
 9512
 9513        origin.x -= BORDER_WIDTH;
 9514
 9515        window.defer_draw(element, origin, 1);
 9516
 9517        // Do not return an element, since it will already be drawn due to defer_draw.
 9518        None
 9519    }
 9520
 9521    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9522        px(30.)
 9523    }
 9524
 9525    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9526        if self.read_only(cx) {
 9527            cx.theme().players().read_only()
 9528        } else {
 9529            self.style.as_ref().unwrap().local_player
 9530        }
 9531    }
 9532
 9533    fn render_edit_prediction_accept_keybind(
 9534        &self,
 9535        window: &mut Window,
 9536        cx: &mut App,
 9537    ) -> Option<AnyElement> {
 9538        let accept_binding =
 9539            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9540        let accept_keystroke = accept_binding.keystroke()?;
 9541
 9542        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9543
 9544        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9545            Color::Accent
 9546        } else {
 9547            Color::Muted
 9548        };
 9549
 9550        h_flex()
 9551            .px_0p5()
 9552            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9553            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9554            .text_size(TextSize::XSmall.rems(cx))
 9555            .child(h_flex().children(ui::render_modifiers(
 9556                accept_keystroke.modifiers(),
 9557                PlatformStyle::platform(),
 9558                Some(modifiers_color),
 9559                Some(IconSize::XSmall.rems().into()),
 9560                true,
 9561            )))
 9562            .when(is_platform_style_mac, |parent| {
 9563                parent.child(accept_keystroke.key().to_string())
 9564            })
 9565            .when(!is_platform_style_mac, |parent| {
 9566                parent.child(
 9567                    Key::new(
 9568                        util::capitalize(accept_keystroke.key()),
 9569                        Some(Color::Default),
 9570                    )
 9571                    .size(Some(IconSize::XSmall.rems().into())),
 9572                )
 9573            })
 9574            .into_any()
 9575            .into()
 9576    }
 9577
 9578    fn render_edit_prediction_line_popover(
 9579        &self,
 9580        label: impl Into<SharedString>,
 9581        icon: Option<IconName>,
 9582        window: &mut Window,
 9583        cx: &mut App,
 9584    ) -> Stateful<Div> {
 9585        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9586
 9587        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9588        let has_keybind = keybind.is_some();
 9589
 9590        h_flex()
 9591            .id("ep-line-popover")
 9592            .py_0p5()
 9593            .pl_1()
 9594            .pr(padding_right)
 9595            .gap_1()
 9596            .rounded_md()
 9597            .border_1()
 9598            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9599            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9600            .shadow_xs()
 9601            .when(!has_keybind, |el| {
 9602                let status_colors = cx.theme().status();
 9603
 9604                el.bg(status_colors.error_background)
 9605                    .border_color(status_colors.error.opacity(0.6))
 9606                    .pl_2()
 9607                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9608                    .cursor_default()
 9609                    .hoverable_tooltip(move |_window, cx| {
 9610                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9611                    })
 9612            })
 9613            .children(keybind)
 9614            .child(
 9615                Label::new(label)
 9616                    .size(LabelSize::Small)
 9617                    .when(!has_keybind, |el| {
 9618                        el.color(cx.theme().status().error.into()).strikethrough()
 9619                    }),
 9620            )
 9621            .when(!has_keybind, |el| {
 9622                el.child(
 9623                    h_flex().ml_1().child(
 9624                        Icon::new(IconName::Info)
 9625                            .size(IconSize::Small)
 9626                            .color(cx.theme().status().error.into()),
 9627                    ),
 9628                )
 9629            })
 9630            .when_some(icon, |element, icon| {
 9631                element.child(
 9632                    div()
 9633                        .mt(px(1.5))
 9634                        .child(Icon::new(icon).size(IconSize::Small)),
 9635                )
 9636            })
 9637    }
 9638
 9639    fn render_edit_prediction_jump_outside_popover(
 9640        &self,
 9641        snapshot: &BufferSnapshot,
 9642        window: &mut Window,
 9643        cx: &mut App,
 9644    ) -> Stateful<Div> {
 9645        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9646        let has_keybind = keybind.is_some();
 9647
 9648        let file_name = snapshot
 9649            .file()
 9650            .map(|file| SharedString::new(file.file_name(cx)))
 9651            .unwrap_or(SharedString::new_static("untitled"));
 9652
 9653        h_flex()
 9654            .id("ep-jump-outside-popover")
 9655            .py_1()
 9656            .px_2()
 9657            .gap_1()
 9658            .rounded_md()
 9659            .border_1()
 9660            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9661            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9662            .shadow_xs()
 9663            .when(!has_keybind, |el| {
 9664                let status_colors = cx.theme().status();
 9665
 9666                el.bg(status_colors.error_background)
 9667                    .border_color(status_colors.error.opacity(0.6))
 9668                    .pl_2()
 9669                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9670                    .cursor_default()
 9671                    .hoverable_tooltip(move |_window, cx| {
 9672                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9673                    })
 9674            })
 9675            .children(keybind)
 9676            .child(
 9677                Label::new(file_name)
 9678                    .size(LabelSize::Small)
 9679                    .buffer_font(cx)
 9680                    .when(!has_keybind, |el| {
 9681                        el.color(cx.theme().status().error.into()).strikethrough()
 9682                    }),
 9683            )
 9684            .when(!has_keybind, |el| {
 9685                el.child(
 9686                    h_flex().ml_1().child(
 9687                        Icon::new(IconName::Info)
 9688                            .size(IconSize::Small)
 9689                            .color(cx.theme().status().error.into()),
 9690                    ),
 9691                )
 9692            })
 9693            .child(
 9694                div()
 9695                    .mt(px(1.5))
 9696                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9697            )
 9698    }
 9699
 9700    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9701        let accent_color = cx.theme().colors().text_accent;
 9702        let editor_bg_color = cx.theme().colors().editor_background;
 9703        editor_bg_color.blend(accent_color.opacity(0.1))
 9704    }
 9705
 9706    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9707        let accent_color = cx.theme().colors().text_accent;
 9708        let editor_bg_color = cx.theme().colors().editor_background;
 9709        editor_bg_color.blend(accent_color.opacity(0.6))
 9710    }
 9711    fn get_prediction_provider_icon_name(
 9712        provider: &Option<RegisteredEditPredictionDelegate>,
 9713    ) -> IconName {
 9714        match provider {
 9715            Some(provider) => match provider.provider.name() {
 9716                "copilot" => IconName::Copilot,
 9717                "supermaven" => IconName::Supermaven,
 9718                _ => IconName::ZedPredict,
 9719            },
 9720            None => IconName::ZedPredict,
 9721        }
 9722    }
 9723
 9724    fn render_edit_prediction_cursor_popover(
 9725        &self,
 9726        min_width: Pixels,
 9727        max_width: Pixels,
 9728        cursor_point: Point,
 9729        style: &EditorStyle,
 9730        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9731        _window: &Window,
 9732        cx: &mut Context<Editor>,
 9733    ) -> Option<AnyElement> {
 9734        let provider = self.edit_prediction_provider.as_ref()?;
 9735        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9736
 9737        let is_refreshing = provider.provider.is_refreshing(cx);
 9738
 9739        fn pending_completion_container(icon: IconName) -> Div {
 9740            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9741        }
 9742
 9743        let completion = match &self.active_edit_prediction {
 9744            Some(prediction) => {
 9745                if !self.has_visible_completions_menu() {
 9746                    const RADIUS: Pixels = px(6.);
 9747                    const BORDER_WIDTH: Pixels = px(1.);
 9748
 9749                    return Some(
 9750                        h_flex()
 9751                            .elevation_2(cx)
 9752                            .border(BORDER_WIDTH)
 9753                            .border_color(cx.theme().colors().border)
 9754                            .when(accept_keystroke.is_none(), |el| {
 9755                                el.border_color(cx.theme().status().error)
 9756                            })
 9757                            .rounded(RADIUS)
 9758                            .rounded_tl(px(0.))
 9759                            .overflow_hidden()
 9760                            .child(div().px_1p5().child(match &prediction.completion {
 9761                                EditPrediction::MoveWithin { target, snapshot } => {
 9762                                    use text::ToPoint as _;
 9763                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9764                                    {
 9765                                        Icon::new(IconName::ZedPredictDown)
 9766                                    } else {
 9767                                        Icon::new(IconName::ZedPredictUp)
 9768                                    }
 9769                                }
 9770                                EditPrediction::MoveOutside { .. } => {
 9771                                    // TODO [zeta2] custom icon for external jump?
 9772                                    Icon::new(provider_icon)
 9773                                }
 9774                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9775                            }))
 9776                            .child(
 9777                                h_flex()
 9778                                    .gap_1()
 9779                                    .py_1()
 9780                                    .px_2()
 9781                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9782                                    .border_l_1()
 9783                                    .border_color(cx.theme().colors().border)
 9784                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9785                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9786                                        el.child(
 9787                                            Label::new("Hold")
 9788                                                .size(LabelSize::Small)
 9789                                                .when(accept_keystroke.is_none(), |el| {
 9790                                                    el.strikethrough()
 9791                                                })
 9792                                                .line_height_style(LineHeightStyle::UiLabel),
 9793                                        )
 9794                                    })
 9795                                    .id("edit_prediction_cursor_popover_keybind")
 9796                                    .when(accept_keystroke.is_none(), |el| {
 9797                                        let status_colors = cx.theme().status();
 9798
 9799                                        el.bg(status_colors.error_background)
 9800                                            .border_color(status_colors.error.opacity(0.6))
 9801                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9802                                            .cursor_default()
 9803                                            .hoverable_tooltip(move |_window, cx| {
 9804                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9805                                                    .into()
 9806                                            })
 9807                                    })
 9808                                    .when_some(
 9809                                        accept_keystroke.as_ref(),
 9810                                        |el, accept_keystroke| {
 9811                                            el.child(h_flex().children(ui::render_modifiers(
 9812                                                accept_keystroke.modifiers(),
 9813                                                PlatformStyle::platform(),
 9814                                                Some(Color::Default),
 9815                                                Some(IconSize::XSmall.rems().into()),
 9816                                                false,
 9817                                            )))
 9818                                        },
 9819                                    ),
 9820                            )
 9821                            .into_any(),
 9822                    );
 9823                }
 9824
 9825                self.render_edit_prediction_cursor_popover_preview(
 9826                    prediction,
 9827                    cursor_point,
 9828                    style,
 9829                    cx,
 9830                )?
 9831            }
 9832
 9833            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9834                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9835                    stale_completion,
 9836                    cursor_point,
 9837                    style,
 9838                    cx,
 9839                )?,
 9840
 9841                None => pending_completion_container(provider_icon)
 9842                    .child(Label::new("...").size(LabelSize::Small)),
 9843            },
 9844
 9845            None => pending_completion_container(provider_icon)
 9846                .child(Label::new("...").size(LabelSize::Small)),
 9847        };
 9848
 9849        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9850            completion
 9851                .with_animation(
 9852                    "loading-completion",
 9853                    Animation::new(Duration::from_secs(2))
 9854                        .repeat()
 9855                        .with_easing(pulsating_between(0.4, 0.8)),
 9856                    |label, delta| label.opacity(delta),
 9857                )
 9858                .into_any_element()
 9859        } else {
 9860            completion.into_any_element()
 9861        };
 9862
 9863        let has_completion = self.active_edit_prediction.is_some();
 9864
 9865        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9866        Some(
 9867            h_flex()
 9868                .min_w(min_width)
 9869                .max_w(max_width)
 9870                .flex_1()
 9871                .elevation_2(cx)
 9872                .border_color(cx.theme().colors().border)
 9873                .child(
 9874                    div()
 9875                        .flex_1()
 9876                        .py_1()
 9877                        .px_2()
 9878                        .overflow_hidden()
 9879                        .child(completion),
 9880                )
 9881                .when_some(accept_keystroke, |el, accept_keystroke| {
 9882                    if !accept_keystroke.modifiers().modified() {
 9883                        return el;
 9884                    }
 9885
 9886                    el.child(
 9887                        h_flex()
 9888                            .h_full()
 9889                            .border_l_1()
 9890                            .rounded_r_lg()
 9891                            .border_color(cx.theme().colors().border)
 9892                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9893                            .gap_1()
 9894                            .py_1()
 9895                            .px_2()
 9896                            .child(
 9897                                h_flex()
 9898                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9899                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9900                                    .child(h_flex().children(ui::render_modifiers(
 9901                                        accept_keystroke.modifiers(),
 9902                                        PlatformStyle::platform(),
 9903                                        Some(if !has_completion {
 9904                                            Color::Muted
 9905                                        } else {
 9906                                            Color::Default
 9907                                        }),
 9908                                        None,
 9909                                        false,
 9910                                    ))),
 9911                            )
 9912                            .child(Label::new("Preview").into_any_element())
 9913                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9914                    )
 9915                })
 9916                .into_any(),
 9917        )
 9918    }
 9919
 9920    fn render_edit_prediction_cursor_popover_preview(
 9921        &self,
 9922        completion: &EditPredictionState,
 9923        cursor_point: Point,
 9924        style: &EditorStyle,
 9925        cx: &mut Context<Editor>,
 9926    ) -> Option<Div> {
 9927        use text::ToPoint as _;
 9928
 9929        fn render_relative_row_jump(
 9930            prefix: impl Into<String>,
 9931            current_row: u32,
 9932            target_row: u32,
 9933        ) -> Div {
 9934            let (row_diff, arrow) = if target_row < current_row {
 9935                (current_row - target_row, IconName::ArrowUp)
 9936            } else {
 9937                (target_row - current_row, IconName::ArrowDown)
 9938            };
 9939
 9940            h_flex()
 9941                .child(
 9942                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9943                        .color(Color::Muted)
 9944                        .size(LabelSize::Small),
 9945                )
 9946                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9947        }
 9948
 9949        let supports_jump = self
 9950            .edit_prediction_provider
 9951            .as_ref()
 9952            .map(|provider| provider.provider.supports_jump_to_edit())
 9953            .unwrap_or(true);
 9954
 9955        match &completion.completion {
 9956            EditPrediction::MoveWithin {
 9957                target, snapshot, ..
 9958            } => {
 9959                if !supports_jump {
 9960                    return None;
 9961                }
 9962
 9963                Some(
 9964                    h_flex()
 9965                        .px_2()
 9966                        .gap_2()
 9967                        .flex_1()
 9968                        .child(
 9969                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9970                                Icon::new(IconName::ZedPredictDown)
 9971                            } else {
 9972                                Icon::new(IconName::ZedPredictUp)
 9973                            },
 9974                        )
 9975                        .child(Label::new("Jump to Edit")),
 9976                )
 9977            }
 9978            EditPrediction::MoveOutside { snapshot, .. } => {
 9979                let file_name = snapshot
 9980                    .file()
 9981                    .map(|file| file.file_name(cx))
 9982                    .unwrap_or("untitled");
 9983                Some(
 9984                    h_flex()
 9985                        .px_2()
 9986                        .gap_2()
 9987                        .flex_1()
 9988                        .child(Icon::new(IconName::ZedPredict))
 9989                        .child(Label::new(format!("Jump to {file_name}"))),
 9990                )
 9991            }
 9992            EditPrediction::Edit {
 9993                edits,
 9994                edit_preview,
 9995                snapshot,
 9996                display_mode: _,
 9997            } => {
 9998                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9999
10000                let (highlighted_edits, has_more_lines) =
10001                    if let Some(edit_preview) = edit_preview.as_ref() {
10002                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10003                            .first_line_preview()
10004                    } else {
10005                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10006                    };
10007
10008                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10009                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10010
10011                let preview = h_flex()
10012                    .gap_1()
10013                    .min_w_16()
10014                    .child(styled_text)
10015                    .when(has_more_lines, |parent| parent.child(""));
10016
10017                let left = if supports_jump && first_edit_row != cursor_point.row {
10018                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10019                        .into_any_element()
10020                } else {
10021                    let icon_name =
10022                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10023                    Icon::new(icon_name).into_any_element()
10024                };
10025
10026                Some(
10027                    h_flex()
10028                        .h_full()
10029                        .flex_1()
10030                        .gap_2()
10031                        .pr_1()
10032                        .overflow_x_hidden()
10033                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10034                        .child(left)
10035                        .child(preview),
10036                )
10037            }
10038        }
10039    }
10040
10041    pub fn render_context_menu(
10042        &mut self,
10043        max_height_in_lines: u32,
10044        window: &mut Window,
10045        cx: &mut Context<Editor>,
10046    ) -> Option<AnyElement> {
10047        let menu = self.context_menu.borrow();
10048        let menu = menu.as_ref()?;
10049        if !menu.visible() {
10050            return None;
10051        };
10052        self.style
10053            .as_ref()
10054            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10055    }
10056
10057    fn render_context_menu_aside(
10058        &mut self,
10059        max_size: Size<Pixels>,
10060        window: &mut Window,
10061        cx: &mut Context<Editor>,
10062    ) -> Option<AnyElement> {
10063        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10064            if menu.visible() {
10065                menu.render_aside(max_size, window, cx)
10066            } else {
10067                None
10068            }
10069        })
10070    }
10071
10072    fn hide_context_menu(
10073        &mut self,
10074        window: &mut Window,
10075        cx: &mut Context<Self>,
10076    ) -> Option<CodeContextMenu> {
10077        cx.notify();
10078        self.completion_tasks.clear();
10079        let context_menu = self.context_menu.borrow_mut().take();
10080        self.stale_edit_prediction_in_menu.take();
10081        self.update_visible_edit_prediction(window, cx);
10082        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10083            && let Some(completion_provider) = &self.completion_provider
10084        {
10085            completion_provider.selection_changed(None, window, cx);
10086        }
10087        context_menu
10088    }
10089
10090    fn show_snippet_choices(
10091        &mut self,
10092        choices: &Vec<String>,
10093        selection: Range<Anchor>,
10094        cx: &mut Context<Self>,
10095    ) {
10096        let Some((_, buffer, _)) = self
10097            .buffer()
10098            .read(cx)
10099            .excerpt_containing(selection.start, cx)
10100        else {
10101            return;
10102        };
10103        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10104        else {
10105            return;
10106        };
10107        if buffer != end_buffer {
10108            log::error!("expected anchor range to have matching buffer IDs");
10109            return;
10110        }
10111
10112        let id = post_inc(&mut self.next_completion_id);
10113        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10114        let mut context_menu = self.context_menu.borrow_mut();
10115        let old_menu = context_menu.take();
10116        *context_menu = Some(CodeContextMenu::Completions(
10117            CompletionsMenu::new_snippet_choices(
10118                id,
10119                true,
10120                choices,
10121                selection,
10122                buffer,
10123                old_menu.map(|menu| menu.primary_scroll_handle()),
10124                snippet_sort_order,
10125            ),
10126        ));
10127    }
10128
10129    pub fn insert_snippet(
10130        &mut self,
10131        insertion_ranges: &[Range<MultiBufferOffset>],
10132        snippet: Snippet,
10133        window: &mut Window,
10134        cx: &mut Context<Self>,
10135    ) -> Result<()> {
10136        struct Tabstop<T> {
10137            is_end_tabstop: bool,
10138            ranges: Vec<Range<T>>,
10139            choices: Option<Vec<String>>,
10140        }
10141
10142        let tabstops = self.buffer.update(cx, |buffer, cx| {
10143            let snippet_text: Arc<str> = snippet.text.clone().into();
10144            let edits = insertion_ranges
10145                .iter()
10146                .cloned()
10147                .map(|range| (range, snippet_text.clone()));
10148            let autoindent_mode = AutoindentMode::Block {
10149                original_indent_columns: Vec::new(),
10150            };
10151            buffer.edit(edits, Some(autoindent_mode), cx);
10152
10153            let snapshot = &*buffer.read(cx);
10154            let snippet = &snippet;
10155            snippet
10156                .tabstops
10157                .iter()
10158                .map(|tabstop| {
10159                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10160                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10161                    });
10162                    let mut tabstop_ranges = tabstop
10163                        .ranges
10164                        .iter()
10165                        .flat_map(|tabstop_range| {
10166                            let mut delta = 0_isize;
10167                            insertion_ranges.iter().map(move |insertion_range| {
10168                                let insertion_start = insertion_range.start + delta;
10169                                delta += snippet.text.len() as isize
10170                                    - (insertion_range.end - insertion_range.start) as isize;
10171
10172                                let start =
10173                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10174                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10175                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10176                            })
10177                        })
10178                        .collect::<Vec<_>>();
10179                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10180
10181                    Tabstop {
10182                        is_end_tabstop,
10183                        ranges: tabstop_ranges,
10184                        choices: tabstop.choices.clone(),
10185                    }
10186                })
10187                .collect::<Vec<_>>()
10188        });
10189        if let Some(tabstop) = tabstops.first() {
10190            self.change_selections(Default::default(), window, cx, |s| {
10191                // Reverse order so that the first range is the newest created selection.
10192                // Completions will use it and autoscroll will prioritize it.
10193                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10194            });
10195
10196            if let Some(choices) = &tabstop.choices
10197                && let Some(selection) = tabstop.ranges.first()
10198            {
10199                self.show_snippet_choices(choices, selection.clone(), cx)
10200            }
10201
10202            // If we're already at the last tabstop and it's at the end of the snippet,
10203            // we're done, we don't need to keep the state around.
10204            if !tabstop.is_end_tabstop {
10205                let choices = tabstops
10206                    .iter()
10207                    .map(|tabstop| tabstop.choices.clone())
10208                    .collect();
10209
10210                let ranges = tabstops
10211                    .into_iter()
10212                    .map(|tabstop| tabstop.ranges)
10213                    .collect::<Vec<_>>();
10214
10215                self.snippet_stack.push(SnippetState {
10216                    active_index: 0,
10217                    ranges,
10218                    choices,
10219                });
10220            }
10221
10222            // Check whether the just-entered snippet ends with an auto-closable bracket.
10223            if self.autoclose_regions.is_empty() {
10224                let snapshot = self.buffer.read(cx).snapshot(cx);
10225                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10226                    let selection_head = selection.head();
10227                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10228                        continue;
10229                    };
10230
10231                    let mut bracket_pair = None;
10232                    let max_lookup_length = scope
10233                        .brackets()
10234                        .map(|(pair, _)| {
10235                            pair.start
10236                                .as_str()
10237                                .chars()
10238                                .count()
10239                                .max(pair.end.as_str().chars().count())
10240                        })
10241                        .max();
10242                    if let Some(max_lookup_length) = max_lookup_length {
10243                        let next_text = snapshot
10244                            .chars_at(selection_head)
10245                            .take(max_lookup_length)
10246                            .collect::<String>();
10247                        let prev_text = snapshot
10248                            .reversed_chars_at(selection_head)
10249                            .take(max_lookup_length)
10250                            .collect::<String>();
10251
10252                        for (pair, enabled) in scope.brackets() {
10253                            if enabled
10254                                && pair.close
10255                                && prev_text.starts_with(pair.start.as_str())
10256                                && next_text.starts_with(pair.end.as_str())
10257                            {
10258                                bracket_pair = Some(pair.clone());
10259                                break;
10260                            }
10261                        }
10262                    }
10263
10264                    if let Some(pair) = bracket_pair {
10265                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10266                        let autoclose_enabled =
10267                            self.use_autoclose && snapshot_settings.use_autoclose;
10268                        if autoclose_enabled {
10269                            let start = snapshot.anchor_after(selection_head);
10270                            let end = snapshot.anchor_after(selection_head);
10271                            self.autoclose_regions.push(AutocloseRegion {
10272                                selection_id: selection.id,
10273                                range: start..end,
10274                                pair,
10275                            });
10276                        }
10277                    }
10278                }
10279            }
10280        }
10281        Ok(())
10282    }
10283
10284    pub fn move_to_next_snippet_tabstop(
10285        &mut self,
10286        window: &mut Window,
10287        cx: &mut Context<Self>,
10288    ) -> bool {
10289        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10290    }
10291
10292    pub fn move_to_prev_snippet_tabstop(
10293        &mut self,
10294        window: &mut Window,
10295        cx: &mut Context<Self>,
10296    ) -> bool {
10297        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10298    }
10299
10300    pub fn move_to_snippet_tabstop(
10301        &mut self,
10302        bias: Bias,
10303        window: &mut Window,
10304        cx: &mut Context<Self>,
10305    ) -> bool {
10306        if let Some(mut snippet) = self.snippet_stack.pop() {
10307            match bias {
10308                Bias::Left => {
10309                    if snippet.active_index > 0 {
10310                        snippet.active_index -= 1;
10311                    } else {
10312                        self.snippet_stack.push(snippet);
10313                        return false;
10314                    }
10315                }
10316                Bias::Right => {
10317                    if snippet.active_index + 1 < snippet.ranges.len() {
10318                        snippet.active_index += 1;
10319                    } else {
10320                        self.snippet_stack.push(snippet);
10321                        return false;
10322                    }
10323                }
10324            }
10325            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10326                self.change_selections(Default::default(), window, cx, |s| {
10327                    // Reverse order so that the first range is the newest created selection.
10328                    // Completions will use it and autoscroll will prioritize it.
10329                    s.select_ranges(current_ranges.iter().rev().cloned())
10330                });
10331
10332                if let Some(choices) = &snippet.choices[snippet.active_index]
10333                    && let Some(selection) = current_ranges.first()
10334                {
10335                    self.show_snippet_choices(choices, selection.clone(), cx);
10336                }
10337
10338                // If snippet state is not at the last tabstop, push it back on the stack
10339                if snippet.active_index + 1 < snippet.ranges.len() {
10340                    self.snippet_stack.push(snippet);
10341                }
10342                return true;
10343            }
10344        }
10345
10346        false
10347    }
10348
10349    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10350        self.transact(window, cx, |this, window, cx| {
10351            this.select_all(&SelectAll, window, cx);
10352            this.insert("", window, cx);
10353        });
10354    }
10355
10356    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10357        if self.read_only(cx) {
10358            return;
10359        }
10360        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10361        self.transact(window, cx, |this, window, cx| {
10362            this.select_autoclose_pair(window, cx);
10363
10364            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10365
10366            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10367            if !this.linked_edit_ranges.is_empty() {
10368                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10369                let snapshot = this.buffer.read(cx).snapshot(cx);
10370
10371                for selection in selections.iter() {
10372                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10373                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10374                    if selection_start.buffer_id != selection_end.buffer_id {
10375                        continue;
10376                    }
10377                    if let Some(ranges) =
10378                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10379                    {
10380                        for (buffer, entries) in ranges {
10381                            linked_ranges.entry(buffer).or_default().extend(entries);
10382                        }
10383                    }
10384                }
10385            }
10386
10387            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10388            for selection in &mut selections {
10389                if selection.is_empty() {
10390                    let old_head = selection.head();
10391                    let mut new_head =
10392                        movement::left(&display_map, old_head.to_display_point(&display_map))
10393                            .to_point(&display_map);
10394                    if let Some((buffer, line_buffer_range)) = display_map
10395                        .buffer_snapshot()
10396                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10397                    {
10398                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10399                        let indent_len = match indent_size.kind {
10400                            IndentKind::Space => {
10401                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10402                            }
10403                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10404                        };
10405                        if old_head.column <= indent_size.len && old_head.column > 0 {
10406                            let indent_len = indent_len.get();
10407                            new_head = cmp::min(
10408                                new_head,
10409                                MultiBufferPoint::new(
10410                                    old_head.row,
10411                                    ((old_head.column - 1) / indent_len) * indent_len,
10412                                ),
10413                            );
10414                        }
10415                    }
10416
10417                    selection.set_head(new_head, SelectionGoal::None);
10418                }
10419            }
10420
10421            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10422            this.insert("", window, cx);
10423            let empty_str: Arc<str> = Arc::from("");
10424            for (buffer, edits) in linked_ranges {
10425                let snapshot = buffer.read(cx).snapshot();
10426                use text::ToPoint as TP;
10427
10428                let edits = edits
10429                    .into_iter()
10430                    .map(|range| {
10431                        let end_point = TP::to_point(&range.end, &snapshot);
10432                        let mut start_point = TP::to_point(&range.start, &snapshot);
10433
10434                        if end_point == start_point {
10435                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10436                                .saturating_sub(1);
10437                            start_point =
10438                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10439                        };
10440
10441                        (start_point..end_point, empty_str.clone())
10442                    })
10443                    .sorted_by_key(|(range, _)| range.start)
10444                    .collect::<Vec<_>>();
10445                buffer.update(cx, |this, cx| {
10446                    this.edit(edits, None, cx);
10447                })
10448            }
10449            this.refresh_edit_prediction(true, false, window, cx);
10450            refresh_linked_ranges(this, window, cx);
10451        });
10452    }
10453
10454    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10455        if self.read_only(cx) {
10456            return;
10457        }
10458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459        self.transact(window, cx, |this, window, cx| {
10460            this.change_selections(Default::default(), window, cx, |s| {
10461                s.move_with(|map, selection| {
10462                    if selection.is_empty() {
10463                        let cursor = movement::right(map, selection.head());
10464                        selection.end = cursor;
10465                        selection.reversed = true;
10466                        selection.goal = SelectionGoal::None;
10467                    }
10468                })
10469            });
10470            this.insert("", window, cx);
10471            this.refresh_edit_prediction(true, false, window, cx);
10472        });
10473    }
10474
10475    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10476        if self.mode.is_single_line() {
10477            cx.propagate();
10478            return;
10479        }
10480
10481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10482        if self.move_to_prev_snippet_tabstop(window, cx) {
10483            return;
10484        }
10485        self.outdent(&Outdent, window, cx);
10486    }
10487
10488    pub fn next_snippet_tabstop(
10489        &mut self,
10490        _: &NextSnippetTabstop,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10495            cx.propagate();
10496            return;
10497        }
10498
10499        if self.move_to_next_snippet_tabstop(window, cx) {
10500            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10501            return;
10502        }
10503        cx.propagate();
10504    }
10505
10506    pub fn previous_snippet_tabstop(
10507        &mut self,
10508        _: &PreviousSnippetTabstop,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10513            cx.propagate();
10514            return;
10515        }
10516
10517        if self.move_to_prev_snippet_tabstop(window, cx) {
10518            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10519            return;
10520        }
10521        cx.propagate();
10522    }
10523
10524    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10525        if self.mode.is_single_line() {
10526            cx.propagate();
10527            return;
10528        }
10529
10530        if self.move_to_next_snippet_tabstop(window, cx) {
10531            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10532            return;
10533        }
10534        if self.read_only(cx) {
10535            return;
10536        }
10537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10538        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10539        let buffer = self.buffer.read(cx);
10540        let snapshot = buffer.snapshot(cx);
10541        let rows_iter = selections.iter().map(|s| s.head().row);
10542        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10543
10544        let has_some_cursor_in_whitespace = selections
10545            .iter()
10546            .filter(|selection| selection.is_empty())
10547            .any(|selection| {
10548                let cursor = selection.head();
10549                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10550                cursor.column < current_indent.len
10551            });
10552
10553        let mut edits = Vec::new();
10554        let mut prev_edited_row = 0;
10555        let mut row_delta = 0;
10556        for selection in &mut selections {
10557            if selection.start.row != prev_edited_row {
10558                row_delta = 0;
10559            }
10560            prev_edited_row = selection.end.row;
10561
10562            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10563            if selection.is_empty() {
10564                let cursor = selection.head();
10565                let settings = buffer.language_settings_at(cursor, cx);
10566                if settings.indent_list_on_tab {
10567                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10568                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10569                            row_delta = Self::indent_selection(
10570                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10571                            );
10572                            continue;
10573                        }
10574                    }
10575                }
10576            }
10577
10578            // If the selection is non-empty, then increase the indentation of the selected lines.
10579            if !selection.is_empty() {
10580                row_delta =
10581                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10582                continue;
10583            }
10584
10585            let cursor = selection.head();
10586            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10587            if let Some(suggested_indent) =
10588                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10589            {
10590                // Don't do anything if already at suggested indent
10591                // and there is any other cursor which is not
10592                if has_some_cursor_in_whitespace
10593                    && cursor.column == current_indent.len
10594                    && current_indent.len == suggested_indent.len
10595                {
10596                    continue;
10597                }
10598
10599                // Adjust line and move cursor to suggested indent
10600                // if cursor is not at suggested indent
10601                if cursor.column < suggested_indent.len
10602                    && cursor.column <= current_indent.len
10603                    && current_indent.len <= suggested_indent.len
10604                {
10605                    selection.start = Point::new(cursor.row, suggested_indent.len);
10606                    selection.end = selection.start;
10607                    if row_delta == 0 {
10608                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10609                            cursor.row,
10610                            current_indent,
10611                            suggested_indent,
10612                        ));
10613                        row_delta = suggested_indent.len - current_indent.len;
10614                    }
10615                    continue;
10616                }
10617
10618                // If current indent is more than suggested indent
10619                // only move cursor to current indent and skip indent
10620                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10621                    selection.start = Point::new(cursor.row, current_indent.len);
10622                    selection.end = selection.start;
10623                    continue;
10624                }
10625            }
10626
10627            // Otherwise, insert a hard or soft tab.
10628            let settings = buffer.language_settings_at(cursor, cx);
10629            let tab_size = if settings.hard_tabs {
10630                IndentSize::tab()
10631            } else {
10632                let tab_size = settings.tab_size.get();
10633                let indent_remainder = snapshot
10634                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10635                    .flat_map(str::chars)
10636                    .fold(row_delta % tab_size, |counter: u32, c| {
10637                        if c == '\t' {
10638                            0
10639                        } else {
10640                            (counter + 1) % tab_size
10641                        }
10642                    });
10643
10644                let chars_to_next_tab_stop = tab_size - indent_remainder;
10645                IndentSize::spaces(chars_to_next_tab_stop)
10646            };
10647            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10648            selection.end = selection.start;
10649            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10650            row_delta += tab_size.len;
10651        }
10652
10653        self.transact(window, cx, |this, window, cx| {
10654            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10655            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10656            this.refresh_edit_prediction(true, false, window, cx);
10657        });
10658    }
10659
10660    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10661        if self.read_only(cx) {
10662            return;
10663        }
10664        if self.mode.is_single_line() {
10665            cx.propagate();
10666            return;
10667        }
10668
10669        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10670        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10671        let mut prev_edited_row = 0;
10672        let mut row_delta = 0;
10673        let mut edits = Vec::new();
10674        let buffer = self.buffer.read(cx);
10675        let snapshot = buffer.snapshot(cx);
10676        for selection in &mut selections {
10677            if selection.start.row != prev_edited_row {
10678                row_delta = 0;
10679            }
10680            prev_edited_row = selection.end.row;
10681
10682            row_delta =
10683                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10684        }
10685
10686        self.transact(window, cx, |this, window, cx| {
10687            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10688            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10689        });
10690    }
10691
10692    fn indent_selection(
10693        buffer: &MultiBuffer,
10694        snapshot: &MultiBufferSnapshot,
10695        selection: &mut Selection<Point>,
10696        edits: &mut Vec<(Range<Point>, String)>,
10697        delta_for_start_row: u32,
10698        cx: &App,
10699    ) -> u32 {
10700        let settings = buffer.language_settings_at(selection.start, cx);
10701        let tab_size = settings.tab_size.get();
10702        let indent_kind = if settings.hard_tabs {
10703            IndentKind::Tab
10704        } else {
10705            IndentKind::Space
10706        };
10707        let mut start_row = selection.start.row;
10708        let mut end_row = selection.end.row + 1;
10709
10710        // If a selection ends at the beginning of a line, don't indent
10711        // that last line.
10712        if selection.end.column == 0 && selection.end.row > selection.start.row {
10713            end_row -= 1;
10714        }
10715
10716        // Avoid re-indenting a row that has already been indented by a
10717        // previous selection, but still update this selection's column
10718        // to reflect that indentation.
10719        if delta_for_start_row > 0 {
10720            start_row += 1;
10721            selection.start.column += delta_for_start_row;
10722            if selection.end.row == selection.start.row {
10723                selection.end.column += delta_for_start_row;
10724            }
10725        }
10726
10727        let mut delta_for_end_row = 0;
10728        let has_multiple_rows = start_row + 1 != end_row;
10729        for row in start_row..end_row {
10730            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10731            let indent_delta = match (current_indent.kind, indent_kind) {
10732                (IndentKind::Space, IndentKind::Space) => {
10733                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10734                    IndentSize::spaces(columns_to_next_tab_stop)
10735                }
10736                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10737                (_, IndentKind::Tab) => IndentSize::tab(),
10738            };
10739
10740            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10741                0
10742            } else {
10743                selection.start.column
10744            };
10745            let row_start = Point::new(row, start);
10746            edits.push((
10747                row_start..row_start,
10748                indent_delta.chars().collect::<String>(),
10749            ));
10750
10751            // Update this selection's endpoints to reflect the indentation.
10752            if row == selection.start.row {
10753                selection.start.column += indent_delta.len;
10754            }
10755            if row == selection.end.row {
10756                selection.end.column += indent_delta.len;
10757                delta_for_end_row = indent_delta.len;
10758            }
10759        }
10760
10761        if selection.start.row == selection.end.row {
10762            delta_for_start_row + delta_for_end_row
10763        } else {
10764            delta_for_end_row
10765        }
10766    }
10767
10768    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10769        if self.read_only(cx) {
10770            return;
10771        }
10772        if self.mode.is_single_line() {
10773            cx.propagate();
10774            return;
10775        }
10776
10777        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10779        let selections = self.selections.all::<Point>(&display_map);
10780        let mut deletion_ranges = Vec::new();
10781        let mut last_outdent = None;
10782        {
10783            let buffer = self.buffer.read(cx);
10784            let snapshot = buffer.snapshot(cx);
10785            for selection in &selections {
10786                let settings = buffer.language_settings_at(selection.start, cx);
10787                let tab_size = settings.tab_size.get();
10788                let mut rows = selection.spanned_rows(false, &display_map);
10789
10790                // Avoid re-outdenting a row that has already been outdented by a
10791                // previous selection.
10792                if let Some(last_row) = last_outdent
10793                    && last_row == rows.start
10794                {
10795                    rows.start = rows.start.next_row();
10796                }
10797                let has_multiple_rows = rows.len() > 1;
10798                for row in rows.iter_rows() {
10799                    let indent_size = snapshot.indent_size_for_line(row);
10800                    if indent_size.len > 0 {
10801                        let deletion_len = match indent_size.kind {
10802                            IndentKind::Space => {
10803                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10804                                if columns_to_prev_tab_stop == 0 {
10805                                    tab_size
10806                                } else {
10807                                    columns_to_prev_tab_stop
10808                                }
10809                            }
10810                            IndentKind::Tab => 1,
10811                        };
10812                        let start = if has_multiple_rows
10813                            || deletion_len > selection.start.column
10814                            || indent_size.len < selection.start.column
10815                        {
10816                            0
10817                        } else {
10818                            selection.start.column - deletion_len
10819                        };
10820                        deletion_ranges.push(
10821                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10822                        );
10823                        last_outdent = Some(row);
10824                    }
10825                }
10826            }
10827        }
10828
10829        self.transact(window, cx, |this, window, cx| {
10830            this.buffer.update(cx, |buffer, cx| {
10831                let empty_str: Arc<str> = Arc::default();
10832                buffer.edit(
10833                    deletion_ranges
10834                        .into_iter()
10835                        .map(|range| (range, empty_str.clone())),
10836                    None,
10837                    cx,
10838                );
10839            });
10840            let selections = this
10841                .selections
10842                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10843            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10844        });
10845    }
10846
10847    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10848        if self.read_only(cx) {
10849            return;
10850        }
10851        if self.mode.is_single_line() {
10852            cx.propagate();
10853            return;
10854        }
10855
10856        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10857        let selections = self
10858            .selections
10859            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10860            .into_iter()
10861            .map(|s| s.range());
10862
10863        self.transact(window, cx, |this, window, cx| {
10864            this.buffer.update(cx, |buffer, cx| {
10865                buffer.autoindent_ranges(selections, cx);
10866            });
10867            let selections = this
10868                .selections
10869                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10870            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10871        });
10872    }
10873
10874    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10875        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10876        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10877        let selections = self.selections.all::<Point>(&display_map);
10878
10879        let mut new_cursors = Vec::new();
10880        let mut edit_ranges = Vec::new();
10881        let mut selections = selections.iter().peekable();
10882        while let Some(selection) = selections.next() {
10883            let mut rows = selection.spanned_rows(false, &display_map);
10884
10885            // Accumulate contiguous regions of rows that we want to delete.
10886            while let Some(next_selection) = selections.peek() {
10887                let next_rows = next_selection.spanned_rows(false, &display_map);
10888                if next_rows.start <= rows.end {
10889                    rows.end = next_rows.end;
10890                    selections.next().unwrap();
10891                } else {
10892                    break;
10893                }
10894            }
10895
10896            let buffer = display_map.buffer_snapshot();
10897            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10898            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10899                // If there's a line after the range, delete the \n from the end of the row range
10900                (
10901                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10902                    rows.end,
10903                )
10904            } else {
10905                // If there isn't a line after the range, delete the \n from the line before the
10906                // start of the row range
10907                edit_start = edit_start.saturating_sub_usize(1);
10908                (buffer.len(), rows.start.previous_row())
10909            };
10910
10911            let text_layout_details = self.text_layout_details(window);
10912            let x = display_map.x_for_display_point(
10913                selection.head().to_display_point(&display_map),
10914                &text_layout_details,
10915            );
10916            let row = Point::new(target_row.0, 0)
10917                .to_display_point(&display_map)
10918                .row();
10919            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10920
10921            new_cursors.push((
10922                selection.id,
10923                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10924                SelectionGoal::None,
10925            ));
10926            edit_ranges.push(edit_start..edit_end);
10927        }
10928
10929        self.transact(window, cx, |this, window, cx| {
10930            let buffer = this.buffer.update(cx, |buffer, cx| {
10931                let empty_str: Arc<str> = Arc::default();
10932                buffer.edit(
10933                    edit_ranges
10934                        .into_iter()
10935                        .map(|range| (range, empty_str.clone())),
10936                    None,
10937                    cx,
10938                );
10939                buffer.snapshot(cx)
10940            });
10941            let new_selections = new_cursors
10942                .into_iter()
10943                .map(|(id, cursor, goal)| {
10944                    let cursor = cursor.to_point(&buffer);
10945                    Selection {
10946                        id,
10947                        start: cursor,
10948                        end: cursor,
10949                        reversed: false,
10950                        goal,
10951                    }
10952                })
10953                .collect();
10954
10955            this.change_selections(Default::default(), window, cx, |s| {
10956                s.select(new_selections);
10957            });
10958        });
10959    }
10960
10961    pub fn join_lines_impl(
10962        &mut self,
10963        insert_whitespace: bool,
10964        window: &mut Window,
10965        cx: &mut Context<Self>,
10966    ) {
10967        if self.read_only(cx) {
10968            return;
10969        }
10970        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10971        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10972            let start = MultiBufferRow(selection.start.row);
10973            // Treat single line selections as if they include the next line. Otherwise this action
10974            // would do nothing for single line selections individual cursors.
10975            let end = if selection.start.row == selection.end.row {
10976                MultiBufferRow(selection.start.row + 1)
10977            } else {
10978                MultiBufferRow(selection.end.row)
10979            };
10980
10981            if let Some(last_row_range) = row_ranges.last_mut()
10982                && start <= last_row_range.end
10983            {
10984                last_row_range.end = end;
10985                continue;
10986            }
10987            row_ranges.push(start..end);
10988        }
10989
10990        let snapshot = self.buffer.read(cx).snapshot(cx);
10991        let mut cursor_positions = Vec::new();
10992        for row_range in &row_ranges {
10993            let anchor = snapshot.anchor_before(Point::new(
10994                row_range.end.previous_row().0,
10995                snapshot.line_len(row_range.end.previous_row()),
10996            ));
10997            cursor_positions.push(anchor..anchor);
10998        }
10999
11000        self.transact(window, cx, |this, window, cx| {
11001            for row_range in row_ranges.into_iter().rev() {
11002                for row in row_range.iter_rows().rev() {
11003                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11004                    let next_line_row = row.next_row();
11005                    let indent = snapshot.indent_size_for_line(next_line_row);
11006                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
11007
11008                    let replace =
11009                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11010                            " "
11011                        } else {
11012                            ""
11013                        };
11014
11015                    this.buffer.update(cx, |buffer, cx| {
11016                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11017                    });
11018                }
11019            }
11020
11021            this.change_selections(Default::default(), window, cx, |s| {
11022                s.select_anchor_ranges(cursor_positions)
11023            });
11024        });
11025    }
11026
11027    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11029        self.join_lines_impl(true, window, cx);
11030    }
11031
11032    pub fn sort_lines_case_sensitive(
11033        &mut self,
11034        _: &SortLinesCaseSensitive,
11035        window: &mut Window,
11036        cx: &mut Context<Self>,
11037    ) {
11038        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11039    }
11040
11041    pub fn sort_lines_by_length(
11042        &mut self,
11043        _: &SortLinesByLength,
11044        window: &mut Window,
11045        cx: &mut Context<Self>,
11046    ) {
11047        self.manipulate_immutable_lines(window, cx, |lines| {
11048            lines.sort_by_key(|&line| line.chars().count())
11049        })
11050    }
11051
11052    pub fn sort_lines_case_insensitive(
11053        &mut self,
11054        _: &SortLinesCaseInsensitive,
11055        window: &mut Window,
11056        cx: &mut Context<Self>,
11057    ) {
11058        self.manipulate_immutable_lines(window, cx, |lines| {
11059            lines.sort_by_key(|line| line.to_lowercase())
11060        })
11061    }
11062
11063    pub fn unique_lines_case_insensitive(
11064        &mut self,
11065        _: &UniqueLinesCaseInsensitive,
11066        window: &mut Window,
11067        cx: &mut Context<Self>,
11068    ) {
11069        self.manipulate_immutable_lines(window, cx, |lines| {
11070            let mut seen = HashSet::default();
11071            lines.retain(|line| seen.insert(line.to_lowercase()));
11072        })
11073    }
11074
11075    pub fn unique_lines_case_sensitive(
11076        &mut self,
11077        _: &UniqueLinesCaseSensitive,
11078        window: &mut Window,
11079        cx: &mut Context<Self>,
11080    ) {
11081        self.manipulate_immutable_lines(window, cx, |lines| {
11082            let mut seen = HashSet::default();
11083            lines.retain(|line| seen.insert(*line));
11084        })
11085    }
11086
11087    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11088        let snapshot = self.buffer.read(cx).snapshot(cx);
11089        for selection in self.selections.disjoint_anchors_arc().iter() {
11090            if snapshot
11091                .language_at(selection.start)
11092                .and_then(|lang| lang.config().wrap_characters.as_ref())
11093                .is_some()
11094            {
11095                return true;
11096            }
11097        }
11098        false
11099    }
11100
11101    fn wrap_selections_in_tag(
11102        &mut self,
11103        _: &WrapSelectionsInTag,
11104        window: &mut Window,
11105        cx: &mut Context<Self>,
11106    ) {
11107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11108
11109        let snapshot = self.buffer.read(cx).snapshot(cx);
11110
11111        let mut edits = Vec::new();
11112        let mut boundaries = Vec::new();
11113
11114        for selection in self
11115            .selections
11116            .all_adjusted(&self.display_snapshot(cx))
11117            .iter()
11118        {
11119            let Some(wrap_config) = snapshot
11120                .language_at(selection.start)
11121                .and_then(|lang| lang.config().wrap_characters.clone())
11122            else {
11123                continue;
11124            };
11125
11126            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11127            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11128
11129            let start_before = snapshot.anchor_before(selection.start);
11130            let end_after = snapshot.anchor_after(selection.end);
11131
11132            edits.push((start_before..start_before, open_tag));
11133            edits.push((end_after..end_after, close_tag));
11134
11135            boundaries.push((
11136                start_before,
11137                end_after,
11138                wrap_config.start_prefix.len(),
11139                wrap_config.end_suffix.len(),
11140            ));
11141        }
11142
11143        if edits.is_empty() {
11144            return;
11145        }
11146
11147        self.transact(window, cx, |this, window, cx| {
11148            let buffer = this.buffer.update(cx, |buffer, cx| {
11149                buffer.edit(edits, None, cx);
11150                buffer.snapshot(cx)
11151            });
11152
11153            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11154            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11155                boundaries.into_iter()
11156            {
11157                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11158                let close_offset = end_after
11159                    .to_offset(&buffer)
11160                    .saturating_sub_usize(end_suffix_len);
11161                new_selections.push(open_offset..open_offset);
11162                new_selections.push(close_offset..close_offset);
11163            }
11164
11165            this.change_selections(Default::default(), window, cx, |s| {
11166                s.select_ranges(new_selections);
11167            });
11168
11169            this.request_autoscroll(Autoscroll::fit(), cx);
11170        });
11171    }
11172
11173    pub fn toggle_read_only(
11174        &mut self,
11175        _: &workspace::ToggleReadOnlyFile,
11176        _: &mut Window,
11177        cx: &mut Context<Self>,
11178    ) {
11179        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11180            buffer.update(cx, |buffer, cx| {
11181                buffer.set_capability(
11182                    match buffer.capability() {
11183                        Capability::ReadWrite => Capability::Read,
11184                        Capability::Read => Capability::ReadWrite,
11185                        Capability::ReadOnly => Capability::ReadOnly,
11186                    },
11187                    cx,
11188                );
11189            })
11190        }
11191    }
11192
11193    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11194        let Some(project) = self.project.clone() else {
11195            return;
11196        };
11197        self.reload(project, window, cx)
11198            .detach_and_notify_err(window, cx);
11199    }
11200
11201    pub fn restore_file(
11202        &mut self,
11203        _: &::git::RestoreFile,
11204        window: &mut Window,
11205        cx: &mut Context<Self>,
11206    ) {
11207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11208        let mut buffer_ids = HashSet::default();
11209        let snapshot = self.buffer().read(cx).snapshot(cx);
11210        for selection in self
11211            .selections
11212            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11213        {
11214            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11215        }
11216
11217        let buffer = self.buffer().read(cx);
11218        let ranges = buffer_ids
11219            .into_iter()
11220            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11221            .collect::<Vec<_>>();
11222
11223        self.restore_hunks_in_ranges(ranges, window, cx);
11224    }
11225
11226    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11228        let selections = self
11229            .selections
11230            .all(&self.display_snapshot(cx))
11231            .into_iter()
11232            .map(|s| s.range())
11233            .collect();
11234        self.restore_hunks_in_ranges(selections, window, cx);
11235    }
11236
11237    pub fn restore_hunks_in_ranges(
11238        &mut self,
11239        ranges: Vec<Range<Point>>,
11240        window: &mut Window,
11241        cx: &mut Context<Editor>,
11242    ) {
11243        let mut revert_changes = HashMap::default();
11244        let chunk_by = self
11245            .snapshot(window, cx)
11246            .hunks_for_ranges(ranges)
11247            .into_iter()
11248            .chunk_by(|hunk| hunk.buffer_id);
11249        for (buffer_id, hunks) in &chunk_by {
11250            let hunks = hunks.collect::<Vec<_>>();
11251            for hunk in &hunks {
11252                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11253            }
11254            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11255        }
11256        drop(chunk_by);
11257        if !revert_changes.is_empty() {
11258            self.transact(window, cx, |editor, window, cx| {
11259                editor.restore(revert_changes, window, cx);
11260            });
11261        }
11262    }
11263
11264    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11265        if let Some(status) = self
11266            .addons
11267            .iter()
11268            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11269        {
11270            return Some(status);
11271        }
11272        self.project
11273            .as_ref()?
11274            .read(cx)
11275            .status_for_buffer_id(buffer_id, cx)
11276    }
11277
11278    pub fn open_active_item_in_terminal(
11279        &mut self,
11280        _: &OpenInTerminal,
11281        window: &mut Window,
11282        cx: &mut Context<Self>,
11283    ) {
11284        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11285            let project_path = buffer.read(cx).project_path(cx)?;
11286            let project = self.project()?.read(cx);
11287            let entry = project.entry_for_path(&project_path, cx)?;
11288            let parent = match &entry.canonical_path {
11289                Some(canonical_path) => canonical_path.to_path_buf(),
11290                None => project.absolute_path(&project_path, cx)?,
11291            }
11292            .parent()?
11293            .to_path_buf();
11294            Some(parent)
11295        }) {
11296            window.dispatch_action(
11297                OpenTerminal {
11298                    working_directory,
11299                    local: false,
11300                }
11301                .boxed_clone(),
11302                cx,
11303            );
11304        }
11305    }
11306
11307    fn set_breakpoint_context_menu(
11308        &mut self,
11309        display_row: DisplayRow,
11310        position: Option<Anchor>,
11311        clicked_point: gpui::Point<Pixels>,
11312        window: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        let source = self
11316            .buffer
11317            .read(cx)
11318            .snapshot(cx)
11319            .anchor_before(Point::new(display_row.0, 0u32));
11320
11321        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11322
11323        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11324            self,
11325            source,
11326            clicked_point,
11327            context_menu,
11328            window,
11329            cx,
11330        );
11331    }
11332
11333    fn add_edit_breakpoint_block(
11334        &mut self,
11335        anchor: Anchor,
11336        breakpoint: &Breakpoint,
11337        edit_action: BreakpointPromptEditAction,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        let weak_editor = cx.weak_entity();
11342        let bp_prompt = cx.new(|cx| {
11343            BreakpointPromptEditor::new(
11344                weak_editor,
11345                anchor,
11346                breakpoint.clone(),
11347                edit_action,
11348                window,
11349                cx,
11350            )
11351        });
11352
11353        let height = bp_prompt.update(cx, |this, cx| {
11354            this.prompt
11355                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11356        });
11357        let cloned_prompt = bp_prompt.clone();
11358        let blocks = vec![BlockProperties {
11359            style: BlockStyle::Sticky,
11360            placement: BlockPlacement::Above(anchor),
11361            height: Some(height),
11362            render: Arc::new(move |cx| {
11363                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11364                cloned_prompt.clone().into_any_element()
11365            }),
11366            priority: 0,
11367        }];
11368
11369        let focus_handle = bp_prompt.focus_handle(cx);
11370        window.focus(&focus_handle, cx);
11371
11372        let block_ids = self.insert_blocks(blocks, None, cx);
11373        bp_prompt.update(cx, |prompt, _| {
11374            prompt.add_block_ids(block_ids);
11375        });
11376    }
11377
11378    pub(crate) fn breakpoint_at_row(
11379        &self,
11380        row: u32,
11381        window: &mut Window,
11382        cx: &mut Context<Self>,
11383    ) -> Option<(Anchor, Breakpoint)> {
11384        let snapshot = self.snapshot(window, cx);
11385        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11386
11387        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11388    }
11389
11390    pub(crate) fn breakpoint_at_anchor(
11391        &self,
11392        breakpoint_position: Anchor,
11393        snapshot: &EditorSnapshot,
11394        cx: &mut Context<Self>,
11395    ) -> Option<(Anchor, Breakpoint)> {
11396        let buffer = self
11397            .buffer
11398            .read(cx)
11399            .buffer_for_anchor(breakpoint_position, cx)?;
11400
11401        let enclosing_excerpt = breakpoint_position.excerpt_id;
11402        let buffer_snapshot = buffer.read(cx).snapshot();
11403
11404        let row = buffer_snapshot
11405            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11406            .row;
11407
11408        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11409        let anchor_end = snapshot
11410            .buffer_snapshot()
11411            .anchor_after(Point::new(row, line_len));
11412
11413        self.breakpoint_store
11414            .as_ref()?
11415            .read_with(cx, |breakpoint_store, cx| {
11416                breakpoint_store
11417                    .breakpoints(
11418                        &buffer,
11419                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11420                        &buffer_snapshot,
11421                        cx,
11422                    )
11423                    .next()
11424                    .and_then(|(bp, _)| {
11425                        let breakpoint_row = buffer_snapshot
11426                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11427                            .row;
11428
11429                        if breakpoint_row == row {
11430                            snapshot
11431                                .buffer_snapshot()
11432                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11433                                .map(|position| (position, bp.bp.clone()))
11434                        } else {
11435                            None
11436                        }
11437                    })
11438            })
11439    }
11440
11441    pub fn edit_log_breakpoint(
11442        &mut self,
11443        _: &EditLogBreakpoint,
11444        window: &mut Window,
11445        cx: &mut Context<Self>,
11446    ) {
11447        if self.breakpoint_store.is_none() {
11448            return;
11449        }
11450
11451        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11452            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11453                message: None,
11454                state: BreakpointState::Enabled,
11455                condition: None,
11456                hit_condition: None,
11457            });
11458
11459            self.add_edit_breakpoint_block(
11460                anchor,
11461                &breakpoint,
11462                BreakpointPromptEditAction::Log,
11463                window,
11464                cx,
11465            );
11466        }
11467    }
11468
11469    fn breakpoints_at_cursors(
11470        &self,
11471        window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11474        let snapshot = self.snapshot(window, cx);
11475        let cursors = self
11476            .selections
11477            .disjoint_anchors_arc()
11478            .iter()
11479            .map(|selection| {
11480                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11481
11482                let breakpoint_position = self
11483                    .breakpoint_at_row(cursor_position.row, window, cx)
11484                    .map(|bp| bp.0)
11485                    .unwrap_or_else(|| {
11486                        snapshot
11487                            .display_snapshot
11488                            .buffer_snapshot()
11489                            .anchor_after(Point::new(cursor_position.row, 0))
11490                    });
11491
11492                let breakpoint = self
11493                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11494                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11495
11496                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11497            })
11498            // 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.
11499            .collect::<HashMap<Anchor, _>>();
11500
11501        cursors.into_iter().collect()
11502    }
11503
11504    pub fn enable_breakpoint(
11505        &mut self,
11506        _: &crate::actions::EnableBreakpoint,
11507        window: &mut Window,
11508        cx: &mut Context<Self>,
11509    ) {
11510        if self.breakpoint_store.is_none() {
11511            return;
11512        }
11513
11514        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11515            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11516                continue;
11517            };
11518            self.edit_breakpoint_at_anchor(
11519                anchor,
11520                breakpoint,
11521                BreakpointEditAction::InvertState,
11522                cx,
11523            );
11524        }
11525    }
11526
11527    pub fn disable_breakpoint(
11528        &mut self,
11529        _: &crate::actions::DisableBreakpoint,
11530        window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        if self.breakpoint_store.is_none() {
11534            return;
11535        }
11536
11537        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11538            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11539                continue;
11540            };
11541            self.edit_breakpoint_at_anchor(
11542                anchor,
11543                breakpoint,
11544                BreakpointEditAction::InvertState,
11545                cx,
11546            );
11547        }
11548    }
11549
11550    pub fn toggle_breakpoint(
11551        &mut self,
11552        _: &crate::actions::ToggleBreakpoint,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        if self.breakpoint_store.is_none() {
11557            return;
11558        }
11559
11560        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11561            if let Some(breakpoint) = breakpoint {
11562                self.edit_breakpoint_at_anchor(
11563                    anchor,
11564                    breakpoint,
11565                    BreakpointEditAction::Toggle,
11566                    cx,
11567                );
11568            } else {
11569                self.edit_breakpoint_at_anchor(
11570                    anchor,
11571                    Breakpoint::new_standard(),
11572                    BreakpointEditAction::Toggle,
11573                    cx,
11574                );
11575            }
11576        }
11577    }
11578
11579    pub fn edit_breakpoint_at_anchor(
11580        &mut self,
11581        breakpoint_position: Anchor,
11582        breakpoint: Breakpoint,
11583        edit_action: BreakpointEditAction,
11584        cx: &mut Context<Self>,
11585    ) {
11586        let Some(breakpoint_store) = &self.breakpoint_store else {
11587            return;
11588        };
11589
11590        let Some(buffer) = self
11591            .buffer
11592            .read(cx)
11593            .buffer_for_anchor(breakpoint_position, cx)
11594        else {
11595            return;
11596        };
11597
11598        breakpoint_store.update(cx, |breakpoint_store, cx| {
11599            breakpoint_store.toggle_breakpoint(
11600                buffer,
11601                BreakpointWithPosition {
11602                    position: breakpoint_position.text_anchor,
11603                    bp: breakpoint,
11604                },
11605                edit_action,
11606                cx,
11607            );
11608        });
11609
11610        cx.notify();
11611    }
11612
11613    #[cfg(any(test, feature = "test-support"))]
11614    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11615        self.breakpoint_store.clone()
11616    }
11617
11618    pub fn prepare_restore_change(
11619        &self,
11620        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11621        hunk: &MultiBufferDiffHunk,
11622        cx: &mut App,
11623    ) -> Option<()> {
11624        if hunk.is_created_file() {
11625            return None;
11626        }
11627        let buffer = self.buffer.read(cx);
11628        let diff = buffer.diff_for(hunk.buffer_id)?;
11629        let buffer = buffer.buffer(hunk.buffer_id)?;
11630        let buffer = buffer.read(cx);
11631        let original_text = diff
11632            .read(cx)
11633            .base_text(cx)
11634            .as_rope()
11635            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11636        let buffer_snapshot = buffer.snapshot();
11637        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11638        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11639            probe
11640                .0
11641                .start
11642                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11643                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11644        }) {
11645            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11646            Some(())
11647        } else {
11648            None
11649        }
11650    }
11651
11652    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11653        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11654    }
11655
11656    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11657        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11658    }
11659
11660    pub fn rotate_selections_forward(
11661        &mut self,
11662        _: &RotateSelectionsForward,
11663        window: &mut Window,
11664        cx: &mut Context<Self>,
11665    ) {
11666        self.rotate_selections(window, cx, false)
11667    }
11668
11669    pub fn rotate_selections_backward(
11670        &mut self,
11671        _: &RotateSelectionsBackward,
11672        window: &mut Window,
11673        cx: &mut Context<Self>,
11674    ) {
11675        self.rotate_selections(window, cx, true)
11676    }
11677
11678    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11680        let display_snapshot = self.display_snapshot(cx);
11681        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11682
11683        if selections.len() < 2 {
11684            return;
11685        }
11686
11687        let (edits, new_selections) = {
11688            let buffer = self.buffer.read(cx).read(cx);
11689            let has_selections = selections.iter().any(|s| !s.is_empty());
11690            if has_selections {
11691                let mut selected_texts: Vec<String> = selections
11692                    .iter()
11693                    .map(|selection| {
11694                        buffer
11695                            .text_for_range(selection.start..selection.end)
11696                            .collect()
11697                    })
11698                    .collect();
11699
11700                if reverse {
11701                    selected_texts.rotate_left(1);
11702                } else {
11703                    selected_texts.rotate_right(1);
11704                }
11705
11706                let mut offset_delta: i64 = 0;
11707                let mut new_selections = Vec::new();
11708                let edits: Vec<_> = selections
11709                    .iter()
11710                    .zip(selected_texts.iter())
11711                    .map(|(selection, new_text)| {
11712                        let old_len = (selection.end.0 - selection.start.0) as i64;
11713                        let new_len = new_text.len() as i64;
11714                        let adjusted_start =
11715                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11716                        let adjusted_end =
11717                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11718
11719                        new_selections.push(Selection {
11720                            id: selection.id,
11721                            start: adjusted_start,
11722                            end: adjusted_end,
11723                            reversed: selection.reversed,
11724                            goal: selection.goal,
11725                        });
11726
11727                        offset_delta += new_len - old_len;
11728                        (selection.start..selection.end, new_text.clone())
11729                    })
11730                    .collect();
11731                (edits, new_selections)
11732            } else {
11733                let mut all_rows: Vec<u32> = selections
11734                    .iter()
11735                    .map(|selection| buffer.offset_to_point(selection.start).row)
11736                    .collect();
11737                all_rows.sort_unstable();
11738                all_rows.dedup();
11739
11740                if all_rows.len() < 2 {
11741                    return;
11742                }
11743
11744                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11745                    .iter()
11746                    .map(|&row| {
11747                        let start = Point::new(row, 0);
11748                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11749                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11750                    })
11751                    .collect();
11752
11753                let mut line_texts: Vec<String> = line_ranges
11754                    .iter()
11755                    .map(|range| buffer.text_for_range(range.clone()).collect())
11756                    .collect();
11757
11758                if reverse {
11759                    line_texts.rotate_left(1);
11760                } else {
11761                    line_texts.rotate_right(1);
11762                }
11763
11764                let edits = line_ranges
11765                    .iter()
11766                    .zip(line_texts.iter())
11767                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11768                    .collect();
11769
11770                let num_rows = all_rows.len();
11771                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11772                    .iter()
11773                    .enumerate()
11774                    .map(|(i, &row)| (row, i))
11775                    .collect();
11776
11777                // Compute new line start offsets after rotation (handles CRLF)
11778                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11779                let first_line_start = line_ranges[0].start.0;
11780                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11781                for text in line_texts.iter().take(num_rows - 1) {
11782                    let prev_start = *new_line_starts.last().unwrap();
11783                    new_line_starts.push(prev_start + text.len() + newline_len);
11784                }
11785
11786                let new_selections = selections
11787                    .iter()
11788                    .map(|selection| {
11789                        let point = buffer.offset_to_point(selection.start);
11790                        let old_index = row_to_index[&point.row];
11791                        let new_index = if reverse {
11792                            (old_index + num_rows - 1) % num_rows
11793                        } else {
11794                            (old_index + 1) % num_rows
11795                        };
11796                        let new_offset =
11797                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11798                        Selection {
11799                            id: selection.id,
11800                            start: new_offset,
11801                            end: new_offset,
11802                            reversed: selection.reversed,
11803                            goal: selection.goal,
11804                        }
11805                    })
11806                    .collect();
11807
11808                (edits, new_selections)
11809            }
11810        };
11811
11812        self.transact(window, cx, |this, window, cx| {
11813            this.buffer.update(cx, |buffer, cx| {
11814                buffer.edit(edits, None, cx);
11815            });
11816            this.change_selections(Default::default(), window, cx, |s| {
11817                s.select(new_selections);
11818            });
11819        });
11820    }
11821
11822    fn manipulate_lines<M>(
11823        &mut self,
11824        window: &mut Window,
11825        cx: &mut Context<Self>,
11826        mut manipulate: M,
11827    ) where
11828        M: FnMut(&str) -> LineManipulationResult,
11829    {
11830        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11831
11832        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11833        let buffer = self.buffer.read(cx).snapshot(cx);
11834
11835        let mut edits = Vec::new();
11836
11837        let selections = self.selections.all::<Point>(&display_map);
11838        let mut selections = selections.iter().peekable();
11839        let mut contiguous_row_selections = Vec::new();
11840        let mut new_selections = Vec::new();
11841        let mut added_lines = 0;
11842        let mut removed_lines = 0;
11843
11844        while let Some(selection) = selections.next() {
11845            let (start_row, end_row) = consume_contiguous_rows(
11846                &mut contiguous_row_selections,
11847                selection,
11848                &display_map,
11849                &mut selections,
11850            );
11851
11852            let start_point = Point::new(start_row.0, 0);
11853            let end_point = Point::new(
11854                end_row.previous_row().0,
11855                buffer.line_len(end_row.previous_row()),
11856            );
11857            let text = buffer
11858                .text_for_range(start_point..end_point)
11859                .collect::<String>();
11860
11861            let LineManipulationResult {
11862                new_text,
11863                line_count_before,
11864                line_count_after,
11865            } = manipulate(&text);
11866
11867            edits.push((start_point..end_point, new_text));
11868
11869            // Selections must change based on added and removed line count
11870            let start_row =
11871                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11872            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11873            new_selections.push(Selection {
11874                id: selection.id,
11875                start: start_row,
11876                end: end_row,
11877                goal: SelectionGoal::None,
11878                reversed: selection.reversed,
11879            });
11880
11881            if line_count_after > line_count_before {
11882                added_lines += line_count_after - line_count_before;
11883            } else if line_count_before > line_count_after {
11884                removed_lines += line_count_before - line_count_after;
11885            }
11886        }
11887
11888        self.transact(window, cx, |this, window, cx| {
11889            let buffer = this.buffer.update(cx, |buffer, cx| {
11890                buffer.edit(edits, None, cx);
11891                buffer.snapshot(cx)
11892            });
11893
11894            // Recalculate offsets on newly edited buffer
11895            let new_selections = new_selections
11896                .iter()
11897                .map(|s| {
11898                    let start_point = Point::new(s.start.0, 0);
11899                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11900                    Selection {
11901                        id: s.id,
11902                        start: buffer.point_to_offset(start_point),
11903                        end: buffer.point_to_offset(end_point),
11904                        goal: s.goal,
11905                        reversed: s.reversed,
11906                    }
11907                })
11908                .collect();
11909
11910            this.change_selections(Default::default(), window, cx, |s| {
11911                s.select(new_selections);
11912            });
11913
11914            this.request_autoscroll(Autoscroll::fit(), cx);
11915        });
11916    }
11917
11918    fn manipulate_immutable_lines<Fn>(
11919        &mut self,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922        mut callback: Fn,
11923    ) where
11924        Fn: FnMut(&mut Vec<&str>),
11925    {
11926        self.manipulate_lines(window, cx, |text| {
11927            let mut lines: Vec<&str> = text.split('\n').collect();
11928            let line_count_before = lines.len();
11929
11930            callback(&mut lines);
11931
11932            LineManipulationResult {
11933                new_text: lines.join("\n"),
11934                line_count_before,
11935                line_count_after: lines.len(),
11936            }
11937        });
11938    }
11939
11940    fn manipulate_mutable_lines<Fn>(
11941        &mut self,
11942        window: &mut Window,
11943        cx: &mut Context<Self>,
11944        mut callback: Fn,
11945    ) where
11946        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11947    {
11948        self.manipulate_lines(window, cx, |text| {
11949            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11950            let line_count_before = lines.len();
11951
11952            callback(&mut lines);
11953
11954            LineManipulationResult {
11955                new_text: lines.join("\n"),
11956                line_count_before,
11957                line_count_after: lines.len(),
11958            }
11959        });
11960    }
11961
11962    pub fn convert_indentation_to_spaces(
11963        &mut self,
11964        _: &ConvertIndentationToSpaces,
11965        window: &mut Window,
11966        cx: &mut Context<Self>,
11967    ) {
11968        let settings = self.buffer.read(cx).language_settings(cx);
11969        let tab_size = settings.tab_size.get() as usize;
11970
11971        self.manipulate_mutable_lines(window, cx, |lines| {
11972            // Allocates a reasonably sized scratch buffer once for the whole loop
11973            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11974            // Avoids recomputing spaces that could be inserted many times
11975            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11976                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11977                .collect();
11978
11979            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11980                let mut chars = line.as_ref().chars();
11981                let mut col = 0;
11982                let mut changed = false;
11983
11984                for ch in chars.by_ref() {
11985                    match ch {
11986                        ' ' => {
11987                            reindented_line.push(' ');
11988                            col += 1;
11989                        }
11990                        '\t' => {
11991                            // \t are converted to spaces depending on the current column
11992                            let spaces_len = tab_size - (col % tab_size);
11993                            reindented_line.extend(&space_cache[spaces_len - 1]);
11994                            col += spaces_len;
11995                            changed = true;
11996                        }
11997                        _ => {
11998                            // If we dont append before break, the character is consumed
11999                            reindented_line.push(ch);
12000                            break;
12001                        }
12002                    }
12003                }
12004
12005                if !changed {
12006                    reindented_line.clear();
12007                    continue;
12008                }
12009                // Append the rest of the line and replace old reference with new one
12010                reindented_line.extend(chars);
12011                *line = Cow::Owned(reindented_line.clone());
12012                reindented_line.clear();
12013            }
12014        });
12015    }
12016
12017    pub fn convert_indentation_to_tabs(
12018        &mut self,
12019        _: &ConvertIndentationToTabs,
12020        window: &mut Window,
12021        cx: &mut Context<Self>,
12022    ) {
12023        let settings = self.buffer.read(cx).language_settings(cx);
12024        let tab_size = settings.tab_size.get() as usize;
12025
12026        self.manipulate_mutable_lines(window, cx, |lines| {
12027            // Allocates a reasonably sized buffer once for the whole loop
12028            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12029            // Avoids recomputing spaces that could be inserted many times
12030            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12031                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12032                .collect();
12033
12034            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12035                let mut chars = line.chars();
12036                let mut spaces_count = 0;
12037                let mut first_non_indent_char = None;
12038                let mut changed = false;
12039
12040                for ch in chars.by_ref() {
12041                    match ch {
12042                        ' ' => {
12043                            // Keep track of spaces. Append \t when we reach tab_size
12044                            spaces_count += 1;
12045                            changed = true;
12046                            if spaces_count == tab_size {
12047                                reindented_line.push('\t');
12048                                spaces_count = 0;
12049                            }
12050                        }
12051                        '\t' => {
12052                            reindented_line.push('\t');
12053                            spaces_count = 0;
12054                        }
12055                        _ => {
12056                            // Dont append it yet, we might have remaining spaces
12057                            first_non_indent_char = Some(ch);
12058                            break;
12059                        }
12060                    }
12061                }
12062
12063                if !changed {
12064                    reindented_line.clear();
12065                    continue;
12066                }
12067                // Remaining spaces that didn't make a full tab stop
12068                if spaces_count > 0 {
12069                    reindented_line.extend(&space_cache[spaces_count - 1]);
12070                }
12071                // If we consume an extra character that was not indentation, add it back
12072                if let Some(extra_char) = first_non_indent_char {
12073                    reindented_line.push(extra_char);
12074                }
12075                // Append the rest of the line and replace old reference with new one
12076                reindented_line.extend(chars);
12077                *line = Cow::Owned(reindented_line.clone());
12078                reindented_line.clear();
12079            }
12080        });
12081    }
12082
12083    pub fn convert_to_upper_case(
12084        &mut self,
12085        _: &ConvertToUpperCase,
12086        window: &mut Window,
12087        cx: &mut Context<Self>,
12088    ) {
12089        self.manipulate_text(window, cx, |text| text.to_uppercase())
12090    }
12091
12092    pub fn convert_to_lower_case(
12093        &mut self,
12094        _: &ConvertToLowerCase,
12095        window: &mut Window,
12096        cx: &mut Context<Self>,
12097    ) {
12098        self.manipulate_text(window, cx, |text| text.to_lowercase())
12099    }
12100
12101    pub fn convert_to_title_case(
12102        &mut self,
12103        _: &ConvertToTitleCase,
12104        window: &mut Window,
12105        cx: &mut Context<Self>,
12106    ) {
12107        self.manipulate_text(window, cx, |text| {
12108            text.split('\n')
12109                .map(|line| line.to_case(Case::Title))
12110                .join("\n")
12111        })
12112    }
12113
12114    pub fn convert_to_snake_case(
12115        &mut self,
12116        _: &ConvertToSnakeCase,
12117        window: &mut Window,
12118        cx: &mut Context<Self>,
12119    ) {
12120        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12121    }
12122
12123    pub fn convert_to_kebab_case(
12124        &mut self,
12125        _: &ConvertToKebabCase,
12126        window: &mut Window,
12127        cx: &mut Context<Self>,
12128    ) {
12129        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12130    }
12131
12132    pub fn convert_to_upper_camel_case(
12133        &mut self,
12134        _: &ConvertToUpperCamelCase,
12135        window: &mut Window,
12136        cx: &mut Context<Self>,
12137    ) {
12138        self.manipulate_text(window, cx, |text| {
12139            text.split('\n')
12140                .map(|line| line.to_case(Case::UpperCamel))
12141                .join("\n")
12142        })
12143    }
12144
12145    pub fn convert_to_lower_camel_case(
12146        &mut self,
12147        _: &ConvertToLowerCamelCase,
12148        window: &mut Window,
12149        cx: &mut Context<Self>,
12150    ) {
12151        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12152    }
12153
12154    pub fn convert_to_opposite_case(
12155        &mut self,
12156        _: &ConvertToOppositeCase,
12157        window: &mut Window,
12158        cx: &mut Context<Self>,
12159    ) {
12160        self.manipulate_text(window, cx, |text| {
12161            text.chars()
12162                .fold(String::with_capacity(text.len()), |mut t, c| {
12163                    if c.is_uppercase() {
12164                        t.extend(c.to_lowercase());
12165                    } else {
12166                        t.extend(c.to_uppercase());
12167                    }
12168                    t
12169                })
12170        })
12171    }
12172
12173    pub fn convert_to_sentence_case(
12174        &mut self,
12175        _: &ConvertToSentenceCase,
12176        window: &mut Window,
12177        cx: &mut Context<Self>,
12178    ) {
12179        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12180    }
12181
12182    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12183        self.manipulate_text(window, cx, |text| {
12184            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12185            if has_upper_case_characters {
12186                text.to_lowercase()
12187            } else {
12188                text.to_uppercase()
12189            }
12190        })
12191    }
12192
12193    pub fn convert_to_rot13(
12194        &mut self,
12195        _: &ConvertToRot13,
12196        window: &mut Window,
12197        cx: &mut Context<Self>,
12198    ) {
12199        self.manipulate_text(window, cx, |text| {
12200            text.chars()
12201                .map(|c| match c {
12202                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12203                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12204                    _ => c,
12205                })
12206                .collect()
12207        })
12208    }
12209
12210    pub fn convert_to_rot47(
12211        &mut self,
12212        _: &ConvertToRot47,
12213        window: &mut Window,
12214        cx: &mut Context<Self>,
12215    ) {
12216        self.manipulate_text(window, cx, |text| {
12217            text.chars()
12218                .map(|c| {
12219                    let code_point = c as u32;
12220                    if code_point >= 33 && code_point <= 126 {
12221                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12222                    }
12223                    c
12224                })
12225                .collect()
12226        })
12227    }
12228
12229    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12230    where
12231        Fn: FnMut(&str) -> String,
12232    {
12233        let buffer = self.buffer.read(cx).snapshot(cx);
12234
12235        let mut new_selections = Vec::new();
12236        let mut edits = Vec::new();
12237        let mut selection_adjustment = 0isize;
12238
12239        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12240            let selection_is_empty = selection.is_empty();
12241
12242            let (start, end) = if selection_is_empty {
12243                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12244                (word_range.start, word_range.end)
12245            } else {
12246                (
12247                    buffer.point_to_offset(selection.start),
12248                    buffer.point_to_offset(selection.end),
12249                )
12250            };
12251
12252            let text = buffer.text_for_range(start..end).collect::<String>();
12253            let old_length = text.len() as isize;
12254            let text = callback(&text);
12255
12256            new_selections.push(Selection {
12257                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12258                end: MultiBufferOffset(
12259                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12260                ),
12261                goal: SelectionGoal::None,
12262                id: selection.id,
12263                reversed: selection.reversed,
12264            });
12265
12266            selection_adjustment += old_length - text.len() as isize;
12267
12268            edits.push((start..end, text));
12269        }
12270
12271        self.transact(window, cx, |this, window, cx| {
12272            this.buffer.update(cx, |buffer, cx| {
12273                buffer.edit(edits, None, cx);
12274            });
12275
12276            this.change_selections(Default::default(), window, cx, |s| {
12277                s.select(new_selections);
12278            });
12279
12280            this.request_autoscroll(Autoscroll::fit(), cx);
12281        });
12282    }
12283
12284    pub fn move_selection_on_drop(
12285        &mut self,
12286        selection: &Selection<Anchor>,
12287        target: DisplayPoint,
12288        is_cut: bool,
12289        window: &mut Window,
12290        cx: &mut Context<Self>,
12291    ) {
12292        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12293        let buffer = display_map.buffer_snapshot();
12294        let mut edits = Vec::new();
12295        let insert_point = display_map
12296            .clip_point(target, Bias::Left)
12297            .to_point(&display_map);
12298        let text = buffer
12299            .text_for_range(selection.start..selection.end)
12300            .collect::<String>();
12301        if is_cut {
12302            edits.push(((selection.start..selection.end), String::new()));
12303        }
12304        let insert_anchor = buffer.anchor_before(insert_point);
12305        edits.push(((insert_anchor..insert_anchor), text));
12306        let last_edit_start = insert_anchor.bias_left(buffer);
12307        let last_edit_end = insert_anchor.bias_right(buffer);
12308        self.transact(window, cx, |this, window, cx| {
12309            this.buffer.update(cx, |buffer, cx| {
12310                buffer.edit(edits, None, cx);
12311            });
12312            this.change_selections(Default::default(), window, cx, |s| {
12313                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12314            });
12315        });
12316    }
12317
12318    pub fn clear_selection_drag_state(&mut self) {
12319        self.selection_drag_state = SelectionDragState::None;
12320    }
12321
12322    pub fn duplicate(
12323        &mut self,
12324        upwards: bool,
12325        whole_lines: bool,
12326        window: &mut Window,
12327        cx: &mut Context<Self>,
12328    ) {
12329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12330
12331        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12332        let buffer = display_map.buffer_snapshot();
12333        let selections = self.selections.all::<Point>(&display_map);
12334
12335        let mut edits = Vec::new();
12336        let mut selections_iter = selections.iter().peekable();
12337        while let Some(selection) = selections_iter.next() {
12338            let mut rows = selection.spanned_rows(false, &display_map);
12339            // duplicate line-wise
12340            if whole_lines || selection.start == selection.end {
12341                // Avoid duplicating the same lines twice.
12342                while let Some(next_selection) = selections_iter.peek() {
12343                    let next_rows = next_selection.spanned_rows(false, &display_map);
12344                    if next_rows.start < rows.end {
12345                        rows.end = next_rows.end;
12346                        selections_iter.next().unwrap();
12347                    } else {
12348                        break;
12349                    }
12350                }
12351
12352                // Copy the text from the selected row region and splice it either at the start
12353                // or end of the region.
12354                let start = Point::new(rows.start.0, 0);
12355                let end = Point::new(
12356                    rows.end.previous_row().0,
12357                    buffer.line_len(rows.end.previous_row()),
12358                );
12359
12360                let mut text = buffer.text_for_range(start..end).collect::<String>();
12361
12362                let insert_location = if upwards {
12363                    // When duplicating upward, we need to insert before the current line.
12364                    // If we're on the last line and it doesn't end with a newline,
12365                    // we need to add a newline before the duplicated content.
12366                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12367                        && buffer.max_point().column > 0
12368                        && !text.ends_with('\n');
12369
12370                    if needs_leading_newline {
12371                        text.insert(0, '\n');
12372                        end
12373                    } else {
12374                        text.push('\n');
12375                        Point::new(rows.start.0, 0)
12376                    }
12377                } else {
12378                    text.push('\n');
12379                    start
12380                };
12381                edits.push((insert_location..insert_location, text));
12382            } else {
12383                // duplicate character-wise
12384                let start = selection.start;
12385                let end = selection.end;
12386                let text = buffer.text_for_range(start..end).collect::<String>();
12387                edits.push((selection.end..selection.end, text));
12388            }
12389        }
12390
12391        self.transact(window, cx, |this, window, cx| {
12392            this.buffer.update(cx, |buffer, cx| {
12393                buffer.edit(edits, None, cx);
12394            });
12395
12396            // When duplicating upward with whole lines, move the cursor to the duplicated line
12397            if upwards && whole_lines {
12398                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12399
12400                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12401                    let mut new_ranges = Vec::new();
12402                    let selections = s.all::<Point>(&display_map);
12403                    let mut selections_iter = selections.iter().peekable();
12404
12405                    while let Some(first_selection) = selections_iter.next() {
12406                        // Group contiguous selections together to find the total row span
12407                        let mut group_selections = vec![first_selection];
12408                        let mut rows = first_selection.spanned_rows(false, &display_map);
12409
12410                        while let Some(next_selection) = selections_iter.peek() {
12411                            let next_rows = next_selection.spanned_rows(false, &display_map);
12412                            if next_rows.start < rows.end {
12413                                rows.end = next_rows.end;
12414                                group_selections.push(selections_iter.next().unwrap());
12415                            } else {
12416                                break;
12417                            }
12418                        }
12419
12420                        let row_count = rows.end.0 - rows.start.0;
12421
12422                        // Move all selections in this group up by the total number of duplicated rows
12423                        for selection in group_selections {
12424                            let new_start = Point::new(
12425                                selection.start.row.saturating_sub(row_count),
12426                                selection.start.column,
12427                            );
12428
12429                            let new_end = Point::new(
12430                                selection.end.row.saturating_sub(row_count),
12431                                selection.end.column,
12432                            );
12433
12434                            new_ranges.push(new_start..new_end);
12435                        }
12436                    }
12437
12438                    s.select_ranges(new_ranges);
12439                });
12440            }
12441
12442            this.request_autoscroll(Autoscroll::fit(), cx);
12443        });
12444    }
12445
12446    pub fn duplicate_line_up(
12447        &mut self,
12448        _: &DuplicateLineUp,
12449        window: &mut Window,
12450        cx: &mut Context<Self>,
12451    ) {
12452        self.duplicate(true, true, window, cx);
12453    }
12454
12455    pub fn duplicate_line_down(
12456        &mut self,
12457        _: &DuplicateLineDown,
12458        window: &mut Window,
12459        cx: &mut Context<Self>,
12460    ) {
12461        self.duplicate(false, true, window, cx);
12462    }
12463
12464    pub fn duplicate_selection(
12465        &mut self,
12466        _: &DuplicateSelection,
12467        window: &mut Window,
12468        cx: &mut Context<Self>,
12469    ) {
12470        self.duplicate(false, false, window, cx);
12471    }
12472
12473    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12474        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12475        if self.mode.is_single_line() {
12476            cx.propagate();
12477            return;
12478        }
12479
12480        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12481        let buffer = self.buffer.read(cx).snapshot(cx);
12482
12483        let mut edits = Vec::new();
12484        let mut unfold_ranges = Vec::new();
12485        let mut refold_creases = Vec::new();
12486
12487        let selections = self.selections.all::<Point>(&display_map);
12488        let mut selections = selections.iter().peekable();
12489        let mut contiguous_row_selections = Vec::new();
12490        let mut new_selections = Vec::new();
12491
12492        while let Some(selection) = selections.next() {
12493            // Find all the selections that span a contiguous row range
12494            let (start_row, end_row) = consume_contiguous_rows(
12495                &mut contiguous_row_selections,
12496                selection,
12497                &display_map,
12498                &mut selections,
12499            );
12500
12501            // Move the text spanned by the row range to be before the line preceding the row range
12502            if start_row.0 > 0 {
12503                let range_to_move = Point::new(
12504                    start_row.previous_row().0,
12505                    buffer.line_len(start_row.previous_row()),
12506                )
12507                    ..Point::new(
12508                        end_row.previous_row().0,
12509                        buffer.line_len(end_row.previous_row()),
12510                    );
12511                let insertion_point = display_map
12512                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12513                    .0;
12514
12515                // Don't move lines across excerpts
12516                if buffer
12517                    .excerpt_containing(insertion_point..range_to_move.end)
12518                    .is_some()
12519                {
12520                    let text = buffer
12521                        .text_for_range(range_to_move.clone())
12522                        .flat_map(|s| s.chars())
12523                        .skip(1)
12524                        .chain(['\n'])
12525                        .collect::<String>();
12526
12527                    edits.push((
12528                        buffer.anchor_after(range_to_move.start)
12529                            ..buffer.anchor_before(range_to_move.end),
12530                        String::new(),
12531                    ));
12532                    let insertion_anchor = buffer.anchor_after(insertion_point);
12533                    edits.push((insertion_anchor..insertion_anchor, text));
12534
12535                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12536
12537                    // Move selections up
12538                    new_selections.extend(contiguous_row_selections.drain(..).map(
12539                        |mut selection| {
12540                            selection.start.row -= row_delta;
12541                            selection.end.row -= row_delta;
12542                            selection
12543                        },
12544                    ));
12545
12546                    // Move folds up
12547                    unfold_ranges.push(range_to_move.clone());
12548                    for fold in display_map.folds_in_range(
12549                        buffer.anchor_before(range_to_move.start)
12550                            ..buffer.anchor_after(range_to_move.end),
12551                    ) {
12552                        let mut start = fold.range.start.to_point(&buffer);
12553                        let mut end = fold.range.end.to_point(&buffer);
12554                        start.row -= row_delta;
12555                        end.row -= row_delta;
12556                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12557                    }
12558                }
12559            }
12560
12561            // If we didn't move line(s), preserve the existing selections
12562            new_selections.append(&mut contiguous_row_selections);
12563        }
12564
12565        self.transact(window, cx, |this, window, cx| {
12566            this.unfold_ranges(&unfold_ranges, true, true, cx);
12567            this.buffer.update(cx, |buffer, cx| {
12568                for (range, text) in edits {
12569                    buffer.edit([(range, text)], None, cx);
12570                }
12571            });
12572            this.fold_creases(refold_creases, true, window, cx);
12573            this.change_selections(Default::default(), window, cx, |s| {
12574                s.select(new_selections);
12575            })
12576        });
12577    }
12578
12579    pub fn move_line_down(
12580        &mut self,
12581        _: &MoveLineDown,
12582        window: &mut Window,
12583        cx: &mut Context<Self>,
12584    ) {
12585        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12586        if self.mode.is_single_line() {
12587            cx.propagate();
12588            return;
12589        }
12590
12591        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12592        let buffer = self.buffer.read(cx).snapshot(cx);
12593
12594        let mut edits = Vec::new();
12595        let mut unfold_ranges = Vec::new();
12596        let mut refold_creases = Vec::new();
12597
12598        let selections = self.selections.all::<Point>(&display_map);
12599        let mut selections = selections.iter().peekable();
12600        let mut contiguous_row_selections = Vec::new();
12601        let mut new_selections = Vec::new();
12602
12603        while let Some(selection) = selections.next() {
12604            // Find all the selections that span a contiguous row range
12605            let (start_row, end_row) = consume_contiguous_rows(
12606                &mut contiguous_row_selections,
12607                selection,
12608                &display_map,
12609                &mut selections,
12610            );
12611
12612            // Move the text spanned by the row range to be after the last line of the row range
12613            if end_row.0 <= buffer.max_point().row {
12614                let range_to_move =
12615                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12616                let insertion_point = display_map
12617                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12618                    .0;
12619
12620                // Don't move lines across excerpt boundaries
12621                if buffer
12622                    .excerpt_containing(range_to_move.start..insertion_point)
12623                    .is_some()
12624                {
12625                    let mut text = String::from("\n");
12626                    text.extend(buffer.text_for_range(range_to_move.clone()));
12627                    text.pop(); // Drop trailing newline
12628                    edits.push((
12629                        buffer.anchor_after(range_to_move.start)
12630                            ..buffer.anchor_before(range_to_move.end),
12631                        String::new(),
12632                    ));
12633                    let insertion_anchor = buffer.anchor_after(insertion_point);
12634                    edits.push((insertion_anchor..insertion_anchor, text));
12635
12636                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12637
12638                    // Move selections down
12639                    new_selections.extend(contiguous_row_selections.drain(..).map(
12640                        |mut selection| {
12641                            selection.start.row += row_delta;
12642                            selection.end.row += row_delta;
12643                            selection
12644                        },
12645                    ));
12646
12647                    // Move folds down
12648                    unfold_ranges.push(range_to_move.clone());
12649                    for fold in display_map.folds_in_range(
12650                        buffer.anchor_before(range_to_move.start)
12651                            ..buffer.anchor_after(range_to_move.end),
12652                    ) {
12653                        let mut start = fold.range.start.to_point(&buffer);
12654                        let mut end = fold.range.end.to_point(&buffer);
12655                        start.row += row_delta;
12656                        end.row += row_delta;
12657                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12658                    }
12659                }
12660            }
12661
12662            // If we didn't move line(s), preserve the existing selections
12663            new_selections.append(&mut contiguous_row_selections);
12664        }
12665
12666        self.transact(window, cx, |this, window, cx| {
12667            this.unfold_ranges(&unfold_ranges, true, true, cx);
12668            this.buffer.update(cx, |buffer, cx| {
12669                for (range, text) in edits {
12670                    buffer.edit([(range, text)], None, cx);
12671                }
12672            });
12673            this.fold_creases(refold_creases, true, window, cx);
12674            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12675        });
12676    }
12677
12678    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12680        let text_layout_details = &self.text_layout_details(window);
12681        self.transact(window, cx, |this, window, cx| {
12682            let edits = this.change_selections(Default::default(), window, cx, |s| {
12683                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12684                s.move_with(|display_map, selection| {
12685                    if !selection.is_empty() {
12686                        return;
12687                    }
12688
12689                    let mut head = selection.head();
12690                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12691                    if head.column() == display_map.line_len(head.row()) {
12692                        transpose_offset = display_map
12693                            .buffer_snapshot()
12694                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12695                    }
12696
12697                    if transpose_offset == MultiBufferOffset(0) {
12698                        return;
12699                    }
12700
12701                    *head.column_mut() += 1;
12702                    head = display_map.clip_point(head, Bias::Right);
12703                    let goal = SelectionGoal::HorizontalPosition(
12704                        display_map
12705                            .x_for_display_point(head, text_layout_details)
12706                            .into(),
12707                    );
12708                    selection.collapse_to(head, goal);
12709
12710                    let transpose_start = display_map
12711                        .buffer_snapshot()
12712                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12713                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12714                        let transpose_end = display_map
12715                            .buffer_snapshot()
12716                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12717                        if let Some(ch) = display_map
12718                            .buffer_snapshot()
12719                            .chars_at(transpose_start)
12720                            .next()
12721                        {
12722                            edits.push((transpose_start..transpose_offset, String::new()));
12723                            edits.push((transpose_end..transpose_end, ch.to_string()));
12724                        }
12725                    }
12726                });
12727                edits
12728            });
12729            this.buffer
12730                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12731            let selections = this
12732                .selections
12733                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12734            this.change_selections(Default::default(), window, cx, |s| {
12735                s.select(selections);
12736            });
12737        });
12738    }
12739
12740    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12741        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12742        if self.mode.is_single_line() {
12743            cx.propagate();
12744            return;
12745        }
12746
12747        self.rewrap_impl(RewrapOptions::default(), cx)
12748    }
12749
12750    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12751        let buffer = self.buffer.read(cx).snapshot(cx);
12752        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12753
12754        #[derive(Clone, Debug, PartialEq)]
12755        enum CommentFormat {
12756            /// single line comment, with prefix for line
12757            Line(String),
12758            /// single line within a block comment, with prefix for line
12759            BlockLine(String),
12760            /// a single line of a block comment that includes the initial delimiter
12761            BlockCommentWithStart(BlockCommentConfig),
12762            /// a single line of a block comment that includes the ending delimiter
12763            BlockCommentWithEnd(BlockCommentConfig),
12764        }
12765
12766        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12767        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12768            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12769                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12770                .peekable();
12771
12772            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12773                row
12774            } else {
12775                return Vec::new();
12776            };
12777
12778            let language_settings = buffer.language_settings_at(selection.head(), cx);
12779            let language_scope = buffer.language_scope_at(selection.head());
12780
12781            let indent_and_prefix_for_row =
12782                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12783                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12784                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12785                        &language_scope
12786                    {
12787                        let indent_end = Point::new(row, indent.len);
12788                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12789                        let line_text_after_indent = buffer
12790                            .text_for_range(indent_end..line_end)
12791                            .collect::<String>();
12792
12793                        let is_within_comment_override = buffer
12794                            .language_scope_at(indent_end)
12795                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12796                        let comment_delimiters = if is_within_comment_override {
12797                            // we are within a comment syntax node, but we don't
12798                            // yet know what kind of comment: block, doc or line
12799                            match (
12800                                language_scope.documentation_comment(),
12801                                language_scope.block_comment(),
12802                            ) {
12803                                (Some(config), _) | (_, Some(config))
12804                                    if buffer.contains_str_at(indent_end, &config.start) =>
12805                                {
12806                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12807                                }
12808                                (Some(config), _) | (_, Some(config))
12809                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12810                                {
12811                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12812                                }
12813                                (Some(config), _) | (_, Some(config))
12814                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12815                                {
12816                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12817                                }
12818                                (_, _) => language_scope
12819                                    .line_comment_prefixes()
12820                                    .iter()
12821                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12822                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12823                            }
12824                        } else {
12825                            // we not in an overridden comment node, but we may
12826                            // be within a non-overridden line comment node
12827                            language_scope
12828                                .line_comment_prefixes()
12829                                .iter()
12830                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12831                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12832                        };
12833
12834                        let rewrap_prefix = language_scope
12835                            .rewrap_prefixes()
12836                            .iter()
12837                            .find_map(|prefix_regex| {
12838                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12839                                    if mat.start() == 0 {
12840                                        Some(mat.as_str().to_string())
12841                                    } else {
12842                                        None
12843                                    }
12844                                })
12845                            })
12846                            .flatten();
12847                        (comment_delimiters, rewrap_prefix)
12848                    } else {
12849                        (None, None)
12850                    };
12851                    (indent, comment_prefix, rewrap_prefix)
12852                };
12853
12854            let mut ranges = Vec::new();
12855            let from_empty_selection = selection.is_empty();
12856
12857            let mut current_range_start = first_row;
12858            let mut prev_row = first_row;
12859            let (
12860                mut current_range_indent,
12861                mut current_range_comment_delimiters,
12862                mut current_range_rewrap_prefix,
12863            ) = indent_and_prefix_for_row(first_row);
12864
12865            for row in non_blank_rows_iter.skip(1) {
12866                let has_paragraph_break = row > prev_row + 1;
12867
12868                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12869                    indent_and_prefix_for_row(row);
12870
12871                let has_indent_change = row_indent != current_range_indent;
12872                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12873
12874                let has_boundary_change = has_comment_change
12875                    || row_rewrap_prefix.is_some()
12876                    || (has_indent_change && current_range_comment_delimiters.is_some());
12877
12878                if has_paragraph_break || has_boundary_change {
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.clone(),
12885                        current_range_rewrap_prefix.clone(),
12886                        from_empty_selection,
12887                    ));
12888                    current_range_start = row;
12889                    current_range_indent = row_indent;
12890                    current_range_comment_delimiters = row_comment_delimiters;
12891                    current_range_rewrap_prefix = row_rewrap_prefix;
12892                }
12893                prev_row = row;
12894            }
12895
12896            ranges.push((
12897                language_settings.clone(),
12898                Point::new(current_range_start, 0)
12899                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12900                current_range_indent,
12901                current_range_comment_delimiters,
12902                current_range_rewrap_prefix,
12903                from_empty_selection,
12904            ));
12905
12906            ranges
12907        });
12908
12909        let mut edits = Vec::new();
12910        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12911
12912        for (
12913            language_settings,
12914            wrap_range,
12915            mut indent_size,
12916            comment_prefix,
12917            rewrap_prefix,
12918            from_empty_selection,
12919        ) in wrap_ranges
12920        {
12921            let mut start_row = wrap_range.start.row;
12922            let mut end_row = wrap_range.end.row;
12923
12924            // Skip selections that overlap with a range that has already been rewrapped.
12925            let selection_range = start_row..end_row;
12926            if rewrapped_row_ranges
12927                .iter()
12928                .any(|range| range.overlaps(&selection_range))
12929            {
12930                continue;
12931            }
12932
12933            let tab_size = language_settings.tab_size;
12934
12935            let (line_prefix, inside_comment) = match &comment_prefix {
12936                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12937                    (Some(prefix.as_str()), true)
12938                }
12939                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12940                    (Some(prefix.as_ref()), true)
12941                }
12942                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12943                    start: _,
12944                    end: _,
12945                    prefix,
12946                    tab_size,
12947                })) => {
12948                    indent_size.len += tab_size;
12949                    (Some(prefix.as_ref()), true)
12950                }
12951                None => (None, false),
12952            };
12953            let indent_prefix = indent_size.chars().collect::<String>();
12954            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12955
12956            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12957                RewrapBehavior::InComments => inside_comment,
12958                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12959                RewrapBehavior::Anywhere => true,
12960            };
12961
12962            let should_rewrap = options.override_language_settings
12963                || allow_rewrap_based_on_language
12964                || self.hard_wrap.is_some();
12965            if !should_rewrap {
12966                continue;
12967            }
12968
12969            if from_empty_selection {
12970                'expand_upwards: while start_row > 0 {
12971                    let prev_row = start_row - 1;
12972                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12973                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12974                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12975                    {
12976                        start_row = prev_row;
12977                    } else {
12978                        break 'expand_upwards;
12979                    }
12980                }
12981
12982                'expand_downwards: while end_row < buffer.max_point().row {
12983                    let next_row = end_row + 1;
12984                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12985                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12986                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12987                    {
12988                        end_row = next_row;
12989                    } else {
12990                        break 'expand_downwards;
12991                    }
12992                }
12993            }
12994
12995            let start = Point::new(start_row, 0);
12996            let start_offset = ToOffset::to_offset(&start, &buffer);
12997            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12998            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12999            let mut first_line_delimiter = None;
13000            let mut last_line_delimiter = None;
13001            let Some(lines_without_prefixes) = selection_text
13002                .lines()
13003                .enumerate()
13004                .map(|(ix, line)| {
13005                    let line_trimmed = line.trim_start();
13006                    if rewrap_prefix.is_some() && ix > 0 {
13007                        Ok(line_trimmed)
13008                    } else if let Some(
13009                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13010                            start,
13011                            prefix,
13012                            end,
13013                            tab_size,
13014                        })
13015                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13016                            start,
13017                            prefix,
13018                            end,
13019                            tab_size,
13020                        }),
13021                    ) = &comment_prefix
13022                    {
13023                        let line_trimmed = line_trimmed
13024                            .strip_prefix(start.as_ref())
13025                            .map(|s| {
13026                                let mut indent_size = indent_size;
13027                                indent_size.len -= tab_size;
13028                                let indent_prefix: String = indent_size.chars().collect();
13029                                first_line_delimiter = Some((indent_prefix, start));
13030                                s.trim_start()
13031                            })
13032                            .unwrap_or(line_trimmed);
13033                        let line_trimmed = line_trimmed
13034                            .strip_suffix(end.as_ref())
13035                            .map(|s| {
13036                                last_line_delimiter = Some(end);
13037                                s.trim_end()
13038                            })
13039                            .unwrap_or(line_trimmed);
13040                        let line_trimmed = line_trimmed
13041                            .strip_prefix(prefix.as_ref())
13042                            .unwrap_or(line_trimmed);
13043                        Ok(line_trimmed)
13044                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13045                        line_trimmed.strip_prefix(prefix).with_context(|| {
13046                            format!("line did not start with prefix {prefix:?}: {line:?}")
13047                        })
13048                    } else {
13049                        line_trimmed
13050                            .strip_prefix(&line_prefix.trim_start())
13051                            .with_context(|| {
13052                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13053                            })
13054                    }
13055                })
13056                .collect::<Result<Vec<_>, _>>()
13057                .log_err()
13058            else {
13059                continue;
13060            };
13061
13062            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13063                buffer
13064                    .language_settings_at(Point::new(start_row, 0), cx)
13065                    .preferred_line_length as usize
13066            });
13067
13068            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13069                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13070            } else {
13071                line_prefix.clone()
13072            };
13073
13074            let wrapped_text = {
13075                let mut wrapped_text = wrap_with_prefix(
13076                    line_prefix,
13077                    subsequent_lines_prefix,
13078                    lines_without_prefixes.join("\n"),
13079                    wrap_column,
13080                    tab_size,
13081                    options.preserve_existing_whitespace,
13082                );
13083
13084                if let Some((indent, delimiter)) = first_line_delimiter {
13085                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13086                }
13087                if let Some(last_line) = last_line_delimiter {
13088                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13089                }
13090
13091                wrapped_text
13092            };
13093
13094            // TODO: should always use char-based diff while still supporting cursor behavior that
13095            // matches vim.
13096            let mut diff_options = DiffOptions::default();
13097            if options.override_language_settings {
13098                diff_options.max_word_diff_len = 0;
13099                diff_options.max_word_diff_line_count = 0;
13100            } else {
13101                diff_options.max_word_diff_len = usize::MAX;
13102                diff_options.max_word_diff_line_count = usize::MAX;
13103            }
13104
13105            for (old_range, new_text) in
13106                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13107            {
13108                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13109                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13110                edits.push((edit_start..edit_end, new_text));
13111            }
13112
13113            rewrapped_row_ranges.push(start_row..=end_row);
13114        }
13115
13116        self.buffer
13117            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13118    }
13119
13120    pub fn cut_common(
13121        &mut self,
13122        cut_no_selection_line: bool,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) -> ClipboardItem {
13126        let mut text = String::new();
13127        let buffer = self.buffer.read(cx).snapshot(cx);
13128        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13129        let mut clipboard_selections = Vec::with_capacity(selections.len());
13130        {
13131            let max_point = buffer.max_point();
13132            let mut is_first = true;
13133            let mut prev_selection_was_entire_line = false;
13134            for selection in &mut selections {
13135                let is_entire_line =
13136                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13137                if is_entire_line {
13138                    selection.start = Point::new(selection.start.row, 0);
13139                    if !selection.is_empty() && selection.end.column == 0 {
13140                        selection.end = cmp::min(max_point, selection.end);
13141                    } else {
13142                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13143                    }
13144                    selection.goal = SelectionGoal::None;
13145                }
13146                if is_first {
13147                    is_first = false;
13148                } else if !prev_selection_was_entire_line {
13149                    text += "\n";
13150                }
13151                prev_selection_was_entire_line = is_entire_line;
13152                let mut len = 0;
13153                for chunk in buffer.text_for_range(selection.start..selection.end) {
13154                    text.push_str(chunk);
13155                    len += chunk.len();
13156                }
13157
13158                clipboard_selections.push(ClipboardSelection::for_buffer(
13159                    len,
13160                    is_entire_line,
13161                    selection.range(),
13162                    &buffer,
13163                    self.project.as_ref(),
13164                    cx,
13165                ));
13166            }
13167        }
13168
13169        self.transact(window, cx, |this, window, cx| {
13170            this.change_selections(Default::default(), window, cx, |s| {
13171                s.select(selections);
13172            });
13173            this.insert("", window, cx);
13174        });
13175        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13176    }
13177
13178    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13179        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13180        let item = self.cut_common(true, window, cx);
13181        cx.write_to_clipboard(item);
13182    }
13183
13184    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13185        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13186        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13187            s.move_with(|snapshot, sel| {
13188                if sel.is_empty() {
13189                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13190                }
13191                if sel.is_empty() {
13192                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13193                }
13194            });
13195        });
13196        let item = self.cut_common(false, window, cx);
13197        cx.set_global(KillRing(item))
13198    }
13199
13200    pub fn kill_ring_yank(
13201        &mut self,
13202        _: &KillRingYank,
13203        window: &mut Window,
13204        cx: &mut Context<Self>,
13205    ) {
13206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13207        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13208            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13209                (kill_ring.text().to_string(), kill_ring.metadata_json())
13210            } else {
13211                return;
13212            }
13213        } else {
13214            return;
13215        };
13216        self.do_paste(&text, metadata, false, window, cx);
13217    }
13218
13219    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13220        self.do_copy(true, cx);
13221    }
13222
13223    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13224        self.do_copy(false, cx);
13225    }
13226
13227    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13228        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13229        let buffer = self.buffer.read(cx).read(cx);
13230        let mut text = String::new();
13231
13232        let mut clipboard_selections = Vec::with_capacity(selections.len());
13233        {
13234            let max_point = buffer.max_point();
13235            let mut is_first = true;
13236            let mut prev_selection_was_entire_line = false;
13237            for selection in &selections {
13238                let mut start = selection.start;
13239                let mut end = selection.end;
13240                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13241                let mut add_trailing_newline = false;
13242                if is_entire_line {
13243                    start = Point::new(start.row, 0);
13244                    let next_line_start = Point::new(end.row + 1, 0);
13245                    if next_line_start <= max_point {
13246                        end = next_line_start;
13247                    } else {
13248                        // We're on the last line without a trailing newline.
13249                        // Copy to the end of the line and add a newline afterwards.
13250                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13251                        add_trailing_newline = true;
13252                    }
13253                }
13254
13255                let mut trimmed_selections = Vec::new();
13256                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13257                    let row = MultiBufferRow(start.row);
13258                    let first_indent = buffer.indent_size_for_line(row);
13259                    if first_indent.len == 0 || start.column > first_indent.len {
13260                        trimmed_selections.push(start..end);
13261                    } else {
13262                        trimmed_selections.push(
13263                            Point::new(row.0, first_indent.len)
13264                                ..Point::new(row.0, buffer.line_len(row)),
13265                        );
13266                        for row in start.row + 1..=end.row {
13267                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13268                            if row == end.row {
13269                                line_len = end.column;
13270                            }
13271                            if line_len == 0 {
13272                                trimmed_selections
13273                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13274                                continue;
13275                            }
13276                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13277                            if row_indent_size.len >= first_indent.len {
13278                                trimmed_selections.push(
13279                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13280                                );
13281                            } else {
13282                                trimmed_selections.clear();
13283                                trimmed_selections.push(start..end);
13284                                break;
13285                            }
13286                        }
13287                    }
13288                } else {
13289                    trimmed_selections.push(start..end);
13290                }
13291
13292                let is_multiline_trim = trimmed_selections.len() > 1;
13293                for trimmed_range in trimmed_selections {
13294                    if is_first {
13295                        is_first = false;
13296                    } else if is_multiline_trim || !prev_selection_was_entire_line {
13297                        text += "\n";
13298                    }
13299                    prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13300                    let mut len = 0;
13301                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13302                        text.push_str(chunk);
13303                        len += chunk.len();
13304                    }
13305                    if add_trailing_newline {
13306                        text.push('\n');
13307                        len += 1;
13308                    }
13309                    clipboard_selections.push(ClipboardSelection::for_buffer(
13310                        len,
13311                        is_entire_line,
13312                        trimmed_range,
13313                        &buffer,
13314                        self.project.as_ref(),
13315                        cx,
13316                    ));
13317                }
13318            }
13319        }
13320
13321        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13322            text,
13323            clipboard_selections,
13324        ));
13325    }
13326
13327    pub fn do_paste(
13328        &mut self,
13329        text: &String,
13330        clipboard_selections: Option<Vec<ClipboardSelection>>,
13331        handle_entire_lines: bool,
13332        window: &mut Window,
13333        cx: &mut Context<Self>,
13334    ) {
13335        if self.read_only(cx) {
13336            return;
13337        }
13338
13339        let clipboard_text = Cow::Borrowed(text.as_str());
13340
13341        self.transact(window, cx, |this, window, cx| {
13342            let had_active_edit_prediction = this.has_active_edit_prediction();
13343            let display_map = this.display_snapshot(cx);
13344            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13345            let cursor_offset = this
13346                .selections
13347                .last::<MultiBufferOffset>(&display_map)
13348                .head();
13349
13350            if let Some(mut clipboard_selections) = clipboard_selections {
13351                let all_selections_were_entire_line =
13352                    clipboard_selections.iter().all(|s| s.is_entire_line);
13353                let first_selection_indent_column =
13354                    clipboard_selections.first().map(|s| s.first_line_indent);
13355                if clipboard_selections.len() != old_selections.len() {
13356                    clipboard_selections.drain(..);
13357                }
13358                let mut auto_indent_on_paste = true;
13359
13360                this.buffer.update(cx, |buffer, cx| {
13361                    let snapshot = buffer.read(cx);
13362                    auto_indent_on_paste = snapshot
13363                        .language_settings_at(cursor_offset, cx)
13364                        .auto_indent_on_paste;
13365
13366                    let mut start_offset = 0;
13367                    let mut edits = Vec::new();
13368                    let mut original_indent_columns = Vec::new();
13369                    for (ix, selection) in old_selections.iter().enumerate() {
13370                        let to_insert;
13371                        let entire_line;
13372                        let original_indent_column;
13373                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13374                            let end_offset = start_offset + clipboard_selection.len;
13375                            to_insert = &clipboard_text[start_offset..end_offset];
13376                            entire_line = clipboard_selection.is_entire_line;
13377                            start_offset = if entire_line {
13378                                end_offset
13379                            } else {
13380                                end_offset + 1
13381                            };
13382                            original_indent_column = Some(clipboard_selection.first_line_indent);
13383                        } else {
13384                            to_insert = &*clipboard_text;
13385                            entire_line = all_selections_were_entire_line;
13386                            original_indent_column = first_selection_indent_column
13387                        }
13388
13389                        let (range, to_insert) =
13390                            if selection.is_empty() && handle_entire_lines && entire_line {
13391                                // If the corresponding selection was empty when this slice of the
13392                                // clipboard text was written, then the entire line containing the
13393                                // selection was copied. If this selection is also currently empty,
13394                                // then paste the line before the current line of the buffer.
13395                                let column = selection.start.to_point(&snapshot).column as usize;
13396                                let line_start = selection.start - column;
13397                                (line_start..line_start, Cow::Borrowed(to_insert))
13398                            } else {
13399                                let language = snapshot.language_at(selection.head());
13400                                let range = selection.range();
13401                                if let Some(language) = language
13402                                    && language.name() == "Markdown".into()
13403                                {
13404                                    edit_for_markdown_paste(
13405                                        &snapshot,
13406                                        range,
13407                                        to_insert,
13408                                        url::Url::parse(to_insert).ok(),
13409                                    )
13410                                } else {
13411                                    (range, Cow::Borrowed(to_insert))
13412                                }
13413                            };
13414
13415                        edits.push((range, to_insert));
13416                        original_indent_columns.push(original_indent_column);
13417                    }
13418                    drop(snapshot);
13419
13420                    buffer.edit(
13421                        edits,
13422                        if auto_indent_on_paste {
13423                            Some(AutoindentMode::Block {
13424                                original_indent_columns,
13425                            })
13426                        } else {
13427                            None
13428                        },
13429                        cx,
13430                    );
13431                });
13432
13433                let selections = this
13434                    .selections
13435                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13436                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13437            } else {
13438                let url = url::Url::parse(&clipboard_text).ok();
13439
13440                let auto_indent_mode = if !clipboard_text.is_empty() {
13441                    Some(AutoindentMode::Block {
13442                        original_indent_columns: Vec::new(),
13443                    })
13444                } else {
13445                    None
13446                };
13447
13448                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13449                    let snapshot = buffer.snapshot(cx);
13450
13451                    let anchors = old_selections
13452                        .iter()
13453                        .map(|s| {
13454                            let anchor = snapshot.anchor_after(s.head());
13455                            s.map(|_| anchor)
13456                        })
13457                        .collect::<Vec<_>>();
13458
13459                    let mut edits = Vec::new();
13460
13461                    for selection in old_selections.iter() {
13462                        let language = snapshot.language_at(selection.head());
13463                        let range = selection.range();
13464
13465                        let (edit_range, edit_text) = if let Some(language) = language
13466                            && language.name() == "Markdown".into()
13467                        {
13468                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13469                        } else {
13470                            (range, clipboard_text.clone())
13471                        };
13472
13473                        edits.push((edit_range, edit_text));
13474                    }
13475
13476                    drop(snapshot);
13477                    buffer.edit(edits, auto_indent_mode, cx);
13478
13479                    anchors
13480                });
13481
13482                this.change_selections(Default::default(), window, cx, |s| {
13483                    s.select_anchors(selection_anchors);
13484                });
13485            }
13486
13487            //   🤔                 |    ..     | show_in_menu |
13488            // | ..                  |   true        true
13489            // | had_edit_prediction |   false       true
13490
13491            let trigger_in_words =
13492                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13493
13494            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13495        });
13496    }
13497
13498    pub fn diff_clipboard_with_selection(
13499        &mut self,
13500        _: &DiffClipboardWithSelection,
13501        window: &mut Window,
13502        cx: &mut Context<Self>,
13503    ) {
13504        let selections = self
13505            .selections
13506            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13507
13508        if selections.is_empty() {
13509            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13510            return;
13511        };
13512
13513        let clipboard_text = match cx.read_from_clipboard() {
13514            Some(item) => match item.entries().first() {
13515                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13516                _ => None,
13517            },
13518            None => None,
13519        };
13520
13521        let Some(clipboard_text) = clipboard_text else {
13522            log::warn!("Clipboard doesn't contain text.");
13523            return;
13524        };
13525
13526        window.dispatch_action(
13527            Box::new(DiffClipboardWithSelectionData {
13528                clipboard_text,
13529                editor: cx.entity(),
13530            }),
13531            cx,
13532        );
13533    }
13534
13535    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13537        if let Some(item) = cx.read_from_clipboard() {
13538            let entries = item.entries();
13539
13540            match entries.first() {
13541                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13542                // of all the pasted entries.
13543                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13544                    .do_paste(
13545                        clipboard_string.text(),
13546                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13547                        true,
13548                        window,
13549                        cx,
13550                    ),
13551                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13552            }
13553        }
13554    }
13555
13556    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13557        if self.read_only(cx) {
13558            return;
13559        }
13560
13561        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13562
13563        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13564            if let Some((selections, _)) =
13565                self.selection_history.transaction(transaction_id).cloned()
13566            {
13567                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13568                    s.select_anchors(selections.to_vec());
13569                });
13570            } else {
13571                log::error!(
13572                    "No entry in selection_history found for undo. \
13573                     This may correspond to a bug where undo does not update the selection. \
13574                     If this is occurring, please add details to \
13575                     https://github.com/zed-industries/zed/issues/22692"
13576                );
13577            }
13578            self.request_autoscroll(Autoscroll::fit(), cx);
13579            self.unmark_text(window, cx);
13580            self.refresh_edit_prediction(true, false, window, cx);
13581            cx.emit(EditorEvent::Edited { transaction_id });
13582            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13583        }
13584    }
13585
13586    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13587        if self.read_only(cx) {
13588            return;
13589        }
13590
13591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13592
13593        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13594            if let Some((_, Some(selections))) =
13595                self.selection_history.transaction(transaction_id).cloned()
13596            {
13597                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13598                    s.select_anchors(selections.to_vec());
13599                });
13600            } else {
13601                log::error!(
13602                    "No entry in selection_history found for redo. \
13603                     This may correspond to a bug where undo does not update the selection. \
13604                     If this is occurring, please add details to \
13605                     https://github.com/zed-industries/zed/issues/22692"
13606                );
13607            }
13608            self.request_autoscroll(Autoscroll::fit(), cx);
13609            self.unmark_text(window, cx);
13610            self.refresh_edit_prediction(true, false, window, cx);
13611            cx.emit(EditorEvent::Edited { transaction_id });
13612        }
13613    }
13614
13615    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13616        self.buffer
13617            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13618    }
13619
13620    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13621        self.buffer
13622            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13623    }
13624
13625    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13627        self.change_selections(Default::default(), window, cx, |s| {
13628            s.move_with(|map, selection| {
13629                let cursor = if selection.is_empty() {
13630                    movement::left(map, selection.start)
13631                } else {
13632                    selection.start
13633                };
13634                selection.collapse_to(cursor, SelectionGoal::None);
13635            });
13636        })
13637    }
13638
13639    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13641        self.change_selections(Default::default(), window, cx, |s| {
13642            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13643        })
13644    }
13645
13646    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13648        self.change_selections(Default::default(), window, cx, |s| {
13649            s.move_with(|map, selection| {
13650                let cursor = if selection.is_empty() {
13651                    movement::right(map, selection.end)
13652                } else {
13653                    selection.end
13654                };
13655                selection.collapse_to(cursor, SelectionGoal::None)
13656            });
13657        })
13658    }
13659
13660    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13662        self.change_selections(Default::default(), window, cx, |s| {
13663            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13664        });
13665    }
13666
13667    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13668        if self.take_rename(true, window, cx).is_some() {
13669            return;
13670        }
13671
13672        if self.mode.is_single_line() {
13673            cx.propagate();
13674            return;
13675        }
13676
13677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13678
13679        let text_layout_details = &self.text_layout_details(window);
13680        let selection_count = self.selections.count();
13681        let first_selection = self.selections.first_anchor();
13682
13683        self.change_selections(Default::default(), window, cx, |s| {
13684            s.move_with(|map, selection| {
13685                if !selection.is_empty() {
13686                    selection.goal = SelectionGoal::None;
13687                }
13688                let (cursor, goal) = movement::up(
13689                    map,
13690                    selection.start,
13691                    selection.goal,
13692                    false,
13693                    text_layout_details,
13694                );
13695                selection.collapse_to(cursor, goal);
13696            });
13697        });
13698
13699        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13700        {
13701            cx.propagate();
13702        }
13703    }
13704
13705    pub fn move_up_by_lines(
13706        &mut self,
13707        action: &MoveUpByLines,
13708        window: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        if self.take_rename(true, window, cx).is_some() {
13712            return;
13713        }
13714
13715        if self.mode.is_single_line() {
13716            cx.propagate();
13717            return;
13718        }
13719
13720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13721
13722        let text_layout_details = &self.text_layout_details(window);
13723
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                if !selection.is_empty() {
13727                    selection.goal = SelectionGoal::None;
13728                }
13729                let (cursor, goal) = movement::up_by_rows(
13730                    map,
13731                    selection.start,
13732                    action.lines,
13733                    selection.goal,
13734                    false,
13735                    text_layout_details,
13736                );
13737                selection.collapse_to(cursor, goal);
13738            });
13739        })
13740    }
13741
13742    pub fn move_down_by_lines(
13743        &mut self,
13744        action: &MoveDownByLines,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        if self.take_rename(true, window, cx).is_some() {
13749            return;
13750        }
13751
13752        if self.mode.is_single_line() {
13753            cx.propagate();
13754            return;
13755        }
13756
13757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13758
13759        let text_layout_details = &self.text_layout_details(window);
13760
13761        self.change_selections(Default::default(), window, cx, |s| {
13762            s.move_with(|map, selection| {
13763                if !selection.is_empty() {
13764                    selection.goal = SelectionGoal::None;
13765                }
13766                let (cursor, goal) = movement::down_by_rows(
13767                    map,
13768                    selection.start,
13769                    action.lines,
13770                    selection.goal,
13771                    false,
13772                    text_layout_details,
13773                );
13774                selection.collapse_to(cursor, goal);
13775            });
13776        })
13777    }
13778
13779    pub fn select_down_by_lines(
13780        &mut self,
13781        action: &SelectDownByLines,
13782        window: &mut Window,
13783        cx: &mut Context<Self>,
13784    ) {
13785        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13786        let text_layout_details = &self.text_layout_details(window);
13787        self.change_selections(Default::default(), window, cx, |s| {
13788            s.move_heads_with(|map, head, goal| {
13789                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13790            })
13791        })
13792    }
13793
13794    pub fn select_up_by_lines(
13795        &mut self,
13796        action: &SelectUpByLines,
13797        window: &mut Window,
13798        cx: &mut Context<Self>,
13799    ) {
13800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13801        let text_layout_details = &self.text_layout_details(window);
13802        self.change_selections(Default::default(), window, cx, |s| {
13803            s.move_heads_with(|map, head, goal| {
13804                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13805            })
13806        })
13807    }
13808
13809    pub fn select_page_up(
13810        &mut self,
13811        _: &SelectPageUp,
13812        window: &mut Window,
13813        cx: &mut Context<Self>,
13814    ) {
13815        let Some(row_count) = self.visible_row_count() else {
13816            return;
13817        };
13818
13819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13820
13821        let text_layout_details = &self.text_layout_details(window);
13822
13823        self.change_selections(Default::default(), window, cx, |s| {
13824            s.move_heads_with(|map, head, goal| {
13825                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13826            })
13827        })
13828    }
13829
13830    pub fn move_page_up(
13831        &mut self,
13832        action: &MovePageUp,
13833        window: &mut Window,
13834        cx: &mut Context<Self>,
13835    ) {
13836        if self.take_rename(true, window, cx).is_some() {
13837            return;
13838        }
13839
13840        if self
13841            .context_menu
13842            .borrow_mut()
13843            .as_mut()
13844            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13845            .unwrap_or(false)
13846        {
13847            return;
13848        }
13849
13850        if matches!(self.mode, EditorMode::SingleLine) {
13851            cx.propagate();
13852            return;
13853        }
13854
13855        let Some(row_count) = self.visible_row_count() else {
13856            return;
13857        };
13858
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13860
13861        let effects = if action.center_cursor {
13862            SelectionEffects::scroll(Autoscroll::center())
13863        } else {
13864            SelectionEffects::default()
13865        };
13866
13867        let text_layout_details = &self.text_layout_details(window);
13868
13869        self.change_selections(effects, window, cx, |s| {
13870            s.move_with(|map, selection| {
13871                if !selection.is_empty() {
13872                    selection.goal = SelectionGoal::None;
13873                }
13874                let (cursor, goal) = movement::up_by_rows(
13875                    map,
13876                    selection.end,
13877                    row_count,
13878                    selection.goal,
13879                    false,
13880                    text_layout_details,
13881                );
13882                selection.collapse_to(cursor, goal);
13883            });
13884        });
13885    }
13886
13887    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13889        let text_layout_details = &self.text_layout_details(window);
13890        self.change_selections(Default::default(), window, cx, |s| {
13891            s.move_heads_with(|map, head, goal| {
13892                movement::up(map, head, goal, false, text_layout_details)
13893            })
13894        })
13895    }
13896
13897    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13898        self.take_rename(true, window, cx);
13899
13900        if self.mode.is_single_line() {
13901            cx.propagate();
13902            return;
13903        }
13904
13905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13906
13907        let text_layout_details = &self.text_layout_details(window);
13908        let selection_count = self.selections.count();
13909        let first_selection = self.selections.first_anchor();
13910
13911        self.change_selections(Default::default(), window, cx, |s| {
13912            s.move_with(|map, selection| {
13913                if !selection.is_empty() {
13914                    selection.goal = SelectionGoal::None;
13915                }
13916                let (cursor, goal) = movement::down(
13917                    map,
13918                    selection.end,
13919                    selection.goal,
13920                    false,
13921                    text_layout_details,
13922                );
13923                selection.collapse_to(cursor, goal);
13924            });
13925        });
13926
13927        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13928        {
13929            cx.propagate();
13930        }
13931    }
13932
13933    pub fn select_page_down(
13934        &mut self,
13935        _: &SelectPageDown,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        let Some(row_count) = self.visible_row_count() else {
13940            return;
13941        };
13942
13943        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13944
13945        let text_layout_details = &self.text_layout_details(window);
13946
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_heads_with(|map, head, goal| {
13949                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13950            })
13951        })
13952    }
13953
13954    pub fn move_page_down(
13955        &mut self,
13956        action: &MovePageDown,
13957        window: &mut Window,
13958        cx: &mut Context<Self>,
13959    ) {
13960        if self.take_rename(true, window, cx).is_some() {
13961            return;
13962        }
13963
13964        if self
13965            .context_menu
13966            .borrow_mut()
13967            .as_mut()
13968            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13969            .unwrap_or(false)
13970        {
13971            return;
13972        }
13973
13974        if matches!(self.mode, EditorMode::SingleLine) {
13975            cx.propagate();
13976            return;
13977        }
13978
13979        let Some(row_count) = self.visible_row_count() else {
13980            return;
13981        };
13982
13983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13984
13985        let effects = if action.center_cursor {
13986            SelectionEffects::scroll(Autoscroll::center())
13987        } else {
13988            SelectionEffects::default()
13989        };
13990
13991        let text_layout_details = &self.text_layout_details(window);
13992        self.change_selections(effects, window, cx, |s| {
13993            s.move_with(|map, selection| {
13994                if !selection.is_empty() {
13995                    selection.goal = SelectionGoal::None;
13996                }
13997                let (cursor, goal) = movement::down_by_rows(
13998                    map,
13999                    selection.end,
14000                    row_count,
14001                    selection.goal,
14002                    false,
14003                    text_layout_details,
14004                );
14005                selection.collapse_to(cursor, goal);
14006            });
14007        });
14008    }
14009
14010    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14012        let text_layout_details = &self.text_layout_details(window);
14013        self.change_selections(Default::default(), window, cx, |s| {
14014            s.move_heads_with(|map, head, goal| {
14015                movement::down(map, head, goal, false, text_layout_details)
14016            })
14017        });
14018    }
14019
14020    pub fn context_menu_first(
14021        &mut self,
14022        _: &ContextMenuFirst,
14023        window: &mut Window,
14024        cx: &mut Context<Self>,
14025    ) {
14026        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14027            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14028        }
14029    }
14030
14031    pub fn context_menu_prev(
14032        &mut self,
14033        _: &ContextMenuPrevious,
14034        window: &mut Window,
14035        cx: &mut Context<Self>,
14036    ) {
14037        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14038            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14039        }
14040    }
14041
14042    pub fn context_menu_next(
14043        &mut self,
14044        _: &ContextMenuNext,
14045        window: &mut Window,
14046        cx: &mut Context<Self>,
14047    ) {
14048        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14049            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14050        }
14051    }
14052
14053    pub fn context_menu_last(
14054        &mut self,
14055        _: &ContextMenuLast,
14056        window: &mut Window,
14057        cx: &mut Context<Self>,
14058    ) {
14059        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14060            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14061        }
14062    }
14063
14064    pub fn signature_help_prev(
14065        &mut self,
14066        _: &SignatureHelpPrevious,
14067        _: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) {
14070        if let Some(popover) = self.signature_help_state.popover_mut() {
14071            if popover.current_signature == 0 {
14072                popover.current_signature = popover.signatures.len() - 1;
14073            } else {
14074                popover.current_signature -= 1;
14075            }
14076            cx.notify();
14077        }
14078    }
14079
14080    pub fn signature_help_next(
14081        &mut self,
14082        _: &SignatureHelpNext,
14083        _: &mut Window,
14084        cx: &mut Context<Self>,
14085    ) {
14086        if let Some(popover) = self.signature_help_state.popover_mut() {
14087            if popover.current_signature + 1 == popover.signatures.len() {
14088                popover.current_signature = 0;
14089            } else {
14090                popover.current_signature += 1;
14091            }
14092            cx.notify();
14093        }
14094    }
14095
14096    pub fn move_to_previous_word_start(
14097        &mut self,
14098        _: &MoveToPreviousWordStart,
14099        window: &mut Window,
14100        cx: &mut Context<Self>,
14101    ) {
14102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14103        self.change_selections(Default::default(), window, cx, |s| {
14104            s.move_cursors_with(|map, head, _| {
14105                (
14106                    movement::previous_word_start(map, head),
14107                    SelectionGoal::None,
14108                )
14109            });
14110        })
14111    }
14112
14113    pub fn move_to_previous_subword_start(
14114        &mut self,
14115        _: &MoveToPreviousSubwordStart,
14116        window: &mut Window,
14117        cx: &mut Context<Self>,
14118    ) {
14119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14120        self.change_selections(Default::default(), window, cx, |s| {
14121            s.move_cursors_with(|map, head, _| {
14122                (
14123                    movement::previous_subword_start(map, head),
14124                    SelectionGoal::None,
14125                )
14126            });
14127        })
14128    }
14129
14130    pub fn select_to_previous_word_start(
14131        &mut self,
14132        _: &SelectToPreviousWordStart,
14133        window: &mut Window,
14134        cx: &mut Context<Self>,
14135    ) {
14136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14137        self.change_selections(Default::default(), window, cx, |s| {
14138            s.move_heads_with(|map, head, _| {
14139                (
14140                    movement::previous_word_start(map, head),
14141                    SelectionGoal::None,
14142                )
14143            });
14144        })
14145    }
14146
14147    pub fn select_to_previous_subword_start(
14148        &mut self,
14149        _: &SelectToPreviousSubwordStart,
14150        window: &mut Window,
14151        cx: &mut Context<Self>,
14152    ) {
14153        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14154        self.change_selections(Default::default(), window, cx, |s| {
14155            s.move_heads_with(|map, head, _| {
14156                (
14157                    movement::previous_subword_start(map, head),
14158                    SelectionGoal::None,
14159                )
14160            });
14161        })
14162    }
14163
14164    pub fn delete_to_previous_word_start(
14165        &mut self,
14166        action: &DeleteToPreviousWordStart,
14167        window: &mut Window,
14168        cx: &mut Context<Self>,
14169    ) {
14170        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14171        self.transact(window, cx, |this, window, cx| {
14172            this.select_autoclose_pair(window, cx);
14173            this.change_selections(Default::default(), window, cx, |s| {
14174                s.move_with(|map, selection| {
14175                    if selection.is_empty() {
14176                        let mut cursor = if action.ignore_newlines {
14177                            movement::previous_word_start(map, selection.head())
14178                        } else {
14179                            movement::previous_word_start_or_newline(map, selection.head())
14180                        };
14181                        cursor = movement::adjust_greedy_deletion(
14182                            map,
14183                            selection.head(),
14184                            cursor,
14185                            action.ignore_brackets,
14186                        );
14187                        selection.set_head(cursor, SelectionGoal::None);
14188                    }
14189                });
14190            });
14191            this.insert("", window, cx);
14192        });
14193    }
14194
14195    pub fn delete_to_previous_subword_start(
14196        &mut self,
14197        action: &DeleteToPreviousSubwordStart,
14198        window: &mut Window,
14199        cx: &mut Context<Self>,
14200    ) {
14201        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14202        self.transact(window, cx, |this, window, cx| {
14203            this.select_autoclose_pair(window, cx);
14204            this.change_selections(Default::default(), window, cx, |s| {
14205                s.move_with(|map, selection| {
14206                    if selection.is_empty() {
14207                        let mut cursor = if action.ignore_newlines {
14208                            movement::previous_subword_start(map, selection.head())
14209                        } else {
14210                            movement::previous_subword_start_or_newline(map, selection.head())
14211                        };
14212                        cursor = movement::adjust_greedy_deletion(
14213                            map,
14214                            selection.head(),
14215                            cursor,
14216                            action.ignore_brackets,
14217                        );
14218                        selection.set_head(cursor, SelectionGoal::None);
14219                    }
14220                });
14221            });
14222            this.insert("", window, cx);
14223        });
14224    }
14225
14226    pub fn move_to_next_word_end(
14227        &mut self,
14228        _: &MoveToNextWordEnd,
14229        window: &mut Window,
14230        cx: &mut Context<Self>,
14231    ) {
14232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14233        self.change_selections(Default::default(), window, cx, |s| {
14234            s.move_cursors_with(|map, head, _| {
14235                (movement::next_word_end(map, head), SelectionGoal::None)
14236            });
14237        })
14238    }
14239
14240    pub fn move_to_next_subword_end(
14241        &mut self,
14242        _: &MoveToNextSubwordEnd,
14243        window: &mut Window,
14244        cx: &mut Context<Self>,
14245    ) {
14246        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14247        self.change_selections(Default::default(), window, cx, |s| {
14248            s.move_cursors_with(|map, head, _| {
14249                (movement::next_subword_end(map, head), SelectionGoal::None)
14250            });
14251        })
14252    }
14253
14254    pub fn select_to_next_word_end(
14255        &mut self,
14256        _: &SelectToNextWordEnd,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) {
14260        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14261        self.change_selections(Default::default(), window, cx, |s| {
14262            s.move_heads_with(|map, head, _| {
14263                (movement::next_word_end(map, head), SelectionGoal::None)
14264            });
14265        })
14266    }
14267
14268    pub fn select_to_next_subword_end(
14269        &mut self,
14270        _: &SelectToNextSubwordEnd,
14271        window: &mut Window,
14272        cx: &mut Context<Self>,
14273    ) {
14274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14275        self.change_selections(Default::default(), window, cx, |s| {
14276            s.move_heads_with(|map, head, _| {
14277                (movement::next_subword_end(map, head), SelectionGoal::None)
14278            });
14279        })
14280    }
14281
14282    pub fn delete_to_next_word_end(
14283        &mut self,
14284        action: &DeleteToNextWordEnd,
14285        window: &mut Window,
14286        cx: &mut Context<Self>,
14287    ) {
14288        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14289        self.transact(window, cx, |this, window, cx| {
14290            this.change_selections(Default::default(), window, cx, |s| {
14291                s.move_with(|map, selection| {
14292                    if selection.is_empty() {
14293                        let mut cursor = if action.ignore_newlines {
14294                            movement::next_word_end(map, selection.head())
14295                        } else {
14296                            movement::next_word_end_or_newline(map, selection.head())
14297                        };
14298                        cursor = movement::adjust_greedy_deletion(
14299                            map,
14300                            selection.head(),
14301                            cursor,
14302                            action.ignore_brackets,
14303                        );
14304                        selection.set_head(cursor, SelectionGoal::None);
14305                    }
14306                });
14307            });
14308            this.insert("", window, cx);
14309        });
14310    }
14311
14312    pub fn delete_to_next_subword_end(
14313        &mut self,
14314        action: &DeleteToNextSubwordEnd,
14315        window: &mut Window,
14316        cx: &mut Context<Self>,
14317    ) {
14318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14319        self.transact(window, cx, |this, window, cx| {
14320            this.change_selections(Default::default(), window, cx, |s| {
14321                s.move_with(|map, selection| {
14322                    if selection.is_empty() {
14323                        let mut cursor = if action.ignore_newlines {
14324                            movement::next_subword_end(map, selection.head())
14325                        } else {
14326                            movement::next_subword_end_or_newline(map, selection.head())
14327                        };
14328                        cursor = movement::adjust_greedy_deletion(
14329                            map,
14330                            selection.head(),
14331                            cursor,
14332                            action.ignore_brackets,
14333                        );
14334                        selection.set_head(cursor, SelectionGoal::None);
14335                    }
14336                });
14337            });
14338            this.insert("", window, cx);
14339        });
14340    }
14341
14342    pub fn move_to_beginning_of_line(
14343        &mut self,
14344        action: &MoveToBeginningOfLine,
14345        window: &mut Window,
14346        cx: &mut Context<Self>,
14347    ) {
14348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14349        self.change_selections(Default::default(), window, cx, |s| {
14350            s.move_cursors_with(|map, head, _| {
14351                (
14352                    movement::indented_line_beginning(
14353                        map,
14354                        head,
14355                        action.stop_at_soft_wraps,
14356                        action.stop_at_indent,
14357                    ),
14358                    SelectionGoal::None,
14359                )
14360            });
14361        })
14362    }
14363
14364    pub fn select_to_beginning_of_line(
14365        &mut self,
14366        action: &SelectToBeginningOfLine,
14367        window: &mut Window,
14368        cx: &mut Context<Self>,
14369    ) {
14370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14371        self.change_selections(Default::default(), window, cx, |s| {
14372            s.move_heads_with(|map, head, _| {
14373                (
14374                    movement::indented_line_beginning(
14375                        map,
14376                        head,
14377                        action.stop_at_soft_wraps,
14378                        action.stop_at_indent,
14379                    ),
14380                    SelectionGoal::None,
14381                )
14382            });
14383        });
14384    }
14385
14386    pub fn delete_to_beginning_of_line(
14387        &mut self,
14388        action: &DeleteToBeginningOfLine,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) {
14392        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14393        self.transact(window, cx, |this, window, cx| {
14394            this.change_selections(Default::default(), window, cx, |s| {
14395                s.move_with(|_, selection| {
14396                    selection.reversed = true;
14397                });
14398            });
14399
14400            this.select_to_beginning_of_line(
14401                &SelectToBeginningOfLine {
14402                    stop_at_soft_wraps: false,
14403                    stop_at_indent: action.stop_at_indent,
14404                },
14405                window,
14406                cx,
14407            );
14408            this.backspace(&Backspace, window, cx);
14409        });
14410    }
14411
14412    pub fn move_to_end_of_line(
14413        &mut self,
14414        action: &MoveToEndOfLine,
14415        window: &mut Window,
14416        cx: &mut Context<Self>,
14417    ) {
14418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14419        self.change_selections(Default::default(), window, cx, |s| {
14420            s.move_cursors_with(|map, head, _| {
14421                (
14422                    movement::line_end(map, head, action.stop_at_soft_wraps),
14423                    SelectionGoal::None,
14424                )
14425            });
14426        })
14427    }
14428
14429    pub fn select_to_end_of_line(
14430        &mut self,
14431        action: &SelectToEndOfLine,
14432        window: &mut Window,
14433        cx: &mut Context<Self>,
14434    ) {
14435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14436        self.change_selections(Default::default(), window, cx, |s| {
14437            s.move_heads_with(|map, head, _| {
14438                (
14439                    movement::line_end(map, head, action.stop_at_soft_wraps),
14440                    SelectionGoal::None,
14441                )
14442            });
14443        })
14444    }
14445
14446    pub fn delete_to_end_of_line(
14447        &mut self,
14448        _: &DeleteToEndOfLine,
14449        window: &mut Window,
14450        cx: &mut Context<Self>,
14451    ) {
14452        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14453        self.transact(window, cx, |this, window, cx| {
14454            this.select_to_end_of_line(
14455                &SelectToEndOfLine {
14456                    stop_at_soft_wraps: false,
14457                },
14458                window,
14459                cx,
14460            );
14461            this.delete(&Delete, window, cx);
14462        });
14463    }
14464
14465    pub fn cut_to_end_of_line(
14466        &mut self,
14467        action: &CutToEndOfLine,
14468        window: &mut Window,
14469        cx: &mut Context<Self>,
14470    ) {
14471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14472        self.transact(window, cx, |this, window, cx| {
14473            this.select_to_end_of_line(
14474                &SelectToEndOfLine {
14475                    stop_at_soft_wraps: false,
14476                },
14477                window,
14478                cx,
14479            );
14480            if !action.stop_at_newlines {
14481                this.change_selections(Default::default(), window, cx, |s| {
14482                    s.move_with(|_, sel| {
14483                        if sel.is_empty() {
14484                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14485                        }
14486                    });
14487                });
14488            }
14489            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14490            let item = this.cut_common(false, window, cx);
14491            cx.write_to_clipboard(item);
14492        });
14493    }
14494
14495    pub fn move_to_start_of_paragraph(
14496        &mut self,
14497        _: &MoveToStartOfParagraph,
14498        window: &mut Window,
14499        cx: &mut Context<Self>,
14500    ) {
14501        if matches!(self.mode, EditorMode::SingleLine) {
14502            cx.propagate();
14503            return;
14504        }
14505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14506        self.change_selections(Default::default(), window, cx, |s| {
14507            s.move_with(|map, selection| {
14508                selection.collapse_to(
14509                    movement::start_of_paragraph(map, selection.head(), 1),
14510                    SelectionGoal::None,
14511                )
14512            });
14513        })
14514    }
14515
14516    pub fn move_to_end_of_paragraph(
14517        &mut self,
14518        _: &MoveToEndOfParagraph,
14519        window: &mut Window,
14520        cx: &mut Context<Self>,
14521    ) {
14522        if matches!(self.mode, EditorMode::SingleLine) {
14523            cx.propagate();
14524            return;
14525        }
14526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14527        self.change_selections(Default::default(), window, cx, |s| {
14528            s.move_with(|map, selection| {
14529                selection.collapse_to(
14530                    movement::end_of_paragraph(map, selection.head(), 1),
14531                    SelectionGoal::None,
14532                )
14533            });
14534        })
14535    }
14536
14537    pub fn select_to_start_of_paragraph(
14538        &mut self,
14539        _: &SelectToStartOfParagraph,
14540        window: &mut Window,
14541        cx: &mut Context<Self>,
14542    ) {
14543        if matches!(self.mode, EditorMode::SingleLine) {
14544            cx.propagate();
14545            return;
14546        }
14547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14548        self.change_selections(Default::default(), window, cx, |s| {
14549            s.move_heads_with(|map, head, _| {
14550                (
14551                    movement::start_of_paragraph(map, head, 1),
14552                    SelectionGoal::None,
14553                )
14554            });
14555        })
14556    }
14557
14558    pub fn select_to_end_of_paragraph(
14559        &mut self,
14560        _: &SelectToEndOfParagraph,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        if matches!(self.mode, EditorMode::SingleLine) {
14565            cx.propagate();
14566            return;
14567        }
14568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14569        self.change_selections(Default::default(), window, cx, |s| {
14570            s.move_heads_with(|map, head, _| {
14571                (
14572                    movement::end_of_paragraph(map, head, 1),
14573                    SelectionGoal::None,
14574                )
14575            });
14576        })
14577    }
14578
14579    pub fn move_to_start_of_excerpt(
14580        &mut self,
14581        _: &MoveToStartOfExcerpt,
14582        window: &mut Window,
14583        cx: &mut Context<Self>,
14584    ) {
14585        if matches!(self.mode, EditorMode::SingleLine) {
14586            cx.propagate();
14587            return;
14588        }
14589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14590        self.change_selections(Default::default(), window, cx, |s| {
14591            s.move_with(|map, selection| {
14592                selection.collapse_to(
14593                    movement::start_of_excerpt(
14594                        map,
14595                        selection.head(),
14596                        workspace::searchable::Direction::Prev,
14597                    ),
14598                    SelectionGoal::None,
14599                )
14600            });
14601        })
14602    }
14603
14604    pub fn move_to_start_of_next_excerpt(
14605        &mut self,
14606        _: &MoveToStartOfNextExcerpt,
14607        window: &mut Window,
14608        cx: &mut Context<Self>,
14609    ) {
14610        if matches!(self.mode, EditorMode::SingleLine) {
14611            cx.propagate();
14612            return;
14613        }
14614
14615        self.change_selections(Default::default(), window, cx, |s| {
14616            s.move_with(|map, selection| {
14617                selection.collapse_to(
14618                    movement::start_of_excerpt(
14619                        map,
14620                        selection.head(),
14621                        workspace::searchable::Direction::Next,
14622                    ),
14623                    SelectionGoal::None,
14624                )
14625            });
14626        })
14627    }
14628
14629    pub fn move_to_end_of_excerpt(
14630        &mut self,
14631        _: &MoveToEndOfExcerpt,
14632        window: &mut Window,
14633        cx: &mut Context<Self>,
14634    ) {
14635        if matches!(self.mode, EditorMode::SingleLine) {
14636            cx.propagate();
14637            return;
14638        }
14639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14640        self.change_selections(Default::default(), window, cx, |s| {
14641            s.move_with(|map, selection| {
14642                selection.collapse_to(
14643                    movement::end_of_excerpt(
14644                        map,
14645                        selection.head(),
14646                        workspace::searchable::Direction::Next,
14647                    ),
14648                    SelectionGoal::None,
14649                )
14650            });
14651        })
14652    }
14653
14654    pub fn move_to_end_of_previous_excerpt(
14655        &mut self,
14656        _: &MoveToEndOfPreviousExcerpt,
14657        window: &mut Window,
14658        cx: &mut Context<Self>,
14659    ) {
14660        if matches!(self.mode, EditorMode::SingleLine) {
14661            cx.propagate();
14662            return;
14663        }
14664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14665        self.change_selections(Default::default(), window, cx, |s| {
14666            s.move_with(|map, selection| {
14667                selection.collapse_to(
14668                    movement::end_of_excerpt(
14669                        map,
14670                        selection.head(),
14671                        workspace::searchable::Direction::Prev,
14672                    ),
14673                    SelectionGoal::None,
14674                )
14675            });
14676        })
14677    }
14678
14679    pub fn select_to_start_of_excerpt(
14680        &mut self,
14681        _: &SelectToStartOfExcerpt,
14682        window: &mut Window,
14683        cx: &mut Context<Self>,
14684    ) {
14685        if matches!(self.mode, EditorMode::SingleLine) {
14686            cx.propagate();
14687            return;
14688        }
14689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14690        self.change_selections(Default::default(), window, cx, |s| {
14691            s.move_heads_with(|map, head, _| {
14692                (
14693                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14694                    SelectionGoal::None,
14695                )
14696            });
14697        })
14698    }
14699
14700    pub fn select_to_start_of_next_excerpt(
14701        &mut self,
14702        _: &SelectToStartOfNextExcerpt,
14703        window: &mut Window,
14704        cx: &mut Context<Self>,
14705    ) {
14706        if matches!(self.mode, EditorMode::SingleLine) {
14707            cx.propagate();
14708            return;
14709        }
14710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14711        self.change_selections(Default::default(), window, cx, |s| {
14712            s.move_heads_with(|map, head, _| {
14713                (
14714                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14715                    SelectionGoal::None,
14716                )
14717            });
14718        })
14719    }
14720
14721    pub fn select_to_end_of_excerpt(
14722        &mut self,
14723        _: &SelectToEndOfExcerpt,
14724        window: &mut Window,
14725        cx: &mut Context<Self>,
14726    ) {
14727        if matches!(self.mode, EditorMode::SingleLine) {
14728            cx.propagate();
14729            return;
14730        }
14731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14732        self.change_selections(Default::default(), window, cx, |s| {
14733            s.move_heads_with(|map, head, _| {
14734                (
14735                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14736                    SelectionGoal::None,
14737                )
14738            });
14739        })
14740    }
14741
14742    pub fn select_to_end_of_previous_excerpt(
14743        &mut self,
14744        _: &SelectToEndOfPreviousExcerpt,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) {
14748        if matches!(self.mode, EditorMode::SingleLine) {
14749            cx.propagate();
14750            return;
14751        }
14752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14753        self.change_selections(Default::default(), window, cx, |s| {
14754            s.move_heads_with(|map, head, _| {
14755                (
14756                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14757                    SelectionGoal::None,
14758                )
14759            });
14760        })
14761    }
14762
14763    pub fn move_to_beginning(
14764        &mut self,
14765        _: &MoveToBeginning,
14766        window: &mut Window,
14767        cx: &mut Context<Self>,
14768    ) {
14769        if matches!(self.mode, EditorMode::SingleLine) {
14770            cx.propagate();
14771            return;
14772        }
14773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14774        self.change_selections(Default::default(), window, cx, |s| {
14775            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14776        });
14777    }
14778
14779    pub fn select_to_beginning(
14780        &mut self,
14781        _: &SelectToBeginning,
14782        window: &mut Window,
14783        cx: &mut Context<Self>,
14784    ) {
14785        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14786        selection.set_head(Point::zero(), SelectionGoal::None);
14787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14788        self.change_selections(Default::default(), window, cx, |s| {
14789            s.select(vec![selection]);
14790        });
14791    }
14792
14793    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14794        if matches!(self.mode, EditorMode::SingleLine) {
14795            cx.propagate();
14796            return;
14797        }
14798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14799        let cursor = self.buffer.read(cx).read(cx).len();
14800        self.change_selections(Default::default(), window, cx, |s| {
14801            s.select_ranges(vec![cursor..cursor])
14802        });
14803    }
14804
14805    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14806        self.nav_history = nav_history;
14807    }
14808
14809    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14810        self.nav_history.as_ref()
14811    }
14812
14813    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14814        self.push_to_nav_history(
14815            self.selections.newest_anchor().head(),
14816            None,
14817            false,
14818            true,
14819            cx,
14820        );
14821    }
14822
14823    fn push_to_nav_history(
14824        &mut self,
14825        cursor_anchor: Anchor,
14826        new_position: Option<Point>,
14827        is_deactivate: bool,
14828        always: bool,
14829        cx: &mut Context<Self>,
14830    ) {
14831        if let Some(nav_history) = self.nav_history.as_mut() {
14832            let buffer = self.buffer.read(cx).read(cx);
14833            let cursor_position = cursor_anchor.to_point(&buffer);
14834            let scroll_state = self.scroll_manager.anchor();
14835            let scroll_top_row = scroll_state.top_row(&buffer);
14836            drop(buffer);
14837
14838            if let Some(new_position) = new_position {
14839                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14840                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14841                    return;
14842                }
14843            }
14844
14845            nav_history.push(
14846                Some(NavigationData {
14847                    cursor_anchor,
14848                    cursor_position,
14849                    scroll_anchor: scroll_state,
14850                    scroll_top_row,
14851                }),
14852                cx,
14853            );
14854            cx.emit(EditorEvent::PushedToNavHistory {
14855                anchor: cursor_anchor,
14856                is_deactivate,
14857            })
14858        }
14859    }
14860
14861    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14863        let buffer = self.buffer.read(cx).snapshot(cx);
14864        let mut selection = self
14865            .selections
14866            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14867        selection.set_head(buffer.len(), SelectionGoal::None);
14868        self.change_selections(Default::default(), window, cx, |s| {
14869            s.select(vec![selection]);
14870        });
14871    }
14872
14873    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14874        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14875        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14876            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14877        });
14878    }
14879
14880    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14882        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14883        let mut selections = self.selections.all::<Point>(&display_map);
14884        let max_point = display_map.buffer_snapshot().max_point();
14885        for selection in &mut selections {
14886            let rows = selection.spanned_rows(true, &display_map);
14887            selection.start = Point::new(rows.start.0, 0);
14888            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14889            selection.reversed = false;
14890        }
14891        self.change_selections(Default::default(), window, cx, |s| {
14892            s.select(selections);
14893        });
14894    }
14895
14896    pub fn split_selection_into_lines(
14897        &mut self,
14898        action: &SplitSelectionIntoLines,
14899        window: &mut Window,
14900        cx: &mut Context<Self>,
14901    ) {
14902        let selections = self
14903            .selections
14904            .all::<Point>(&self.display_snapshot(cx))
14905            .into_iter()
14906            .map(|selection| selection.start..selection.end)
14907            .collect::<Vec<_>>();
14908        self.unfold_ranges(&selections, true, true, cx);
14909
14910        let mut new_selection_ranges = Vec::new();
14911        {
14912            let buffer = self.buffer.read(cx).read(cx);
14913            for selection in selections {
14914                for row in selection.start.row..selection.end.row {
14915                    let line_start = Point::new(row, 0);
14916                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14917
14918                    if action.keep_selections {
14919                        // Keep the selection range for each line
14920                        let selection_start = if row == selection.start.row {
14921                            selection.start
14922                        } else {
14923                            line_start
14924                        };
14925                        new_selection_ranges.push(selection_start..line_end);
14926                    } else {
14927                        // Collapse to cursor at end of line
14928                        new_selection_ranges.push(line_end..line_end);
14929                    }
14930                }
14931
14932                let is_multiline_selection = selection.start.row != selection.end.row;
14933                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14934                // so this action feels more ergonomic when paired with other selection operations
14935                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14936                if !should_skip_last {
14937                    if action.keep_selections {
14938                        if is_multiline_selection {
14939                            let line_start = Point::new(selection.end.row, 0);
14940                            new_selection_ranges.push(line_start..selection.end);
14941                        } else {
14942                            new_selection_ranges.push(selection.start..selection.end);
14943                        }
14944                    } else {
14945                        new_selection_ranges.push(selection.end..selection.end);
14946                    }
14947                }
14948            }
14949        }
14950        self.change_selections(Default::default(), window, cx, |s| {
14951            s.select_ranges(new_selection_ranges);
14952        });
14953    }
14954
14955    pub fn add_selection_above(
14956        &mut self,
14957        action: &AddSelectionAbove,
14958        window: &mut Window,
14959        cx: &mut Context<Self>,
14960    ) {
14961        self.add_selection(true, action.skip_soft_wrap, window, cx);
14962    }
14963
14964    pub fn add_selection_below(
14965        &mut self,
14966        action: &AddSelectionBelow,
14967        window: &mut Window,
14968        cx: &mut Context<Self>,
14969    ) {
14970        self.add_selection(false, action.skip_soft_wrap, window, cx);
14971    }
14972
14973    fn add_selection(
14974        &mut self,
14975        above: bool,
14976        skip_soft_wrap: bool,
14977        window: &mut Window,
14978        cx: &mut Context<Self>,
14979    ) {
14980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14981
14982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14983        let all_selections = self.selections.all::<Point>(&display_map);
14984        let text_layout_details = self.text_layout_details(window);
14985
14986        let (mut columnar_selections, new_selections_to_columnarize) = {
14987            if let Some(state) = self.add_selections_state.as_ref() {
14988                let columnar_selection_ids: HashSet<_> = state
14989                    .groups
14990                    .iter()
14991                    .flat_map(|group| group.stack.iter())
14992                    .copied()
14993                    .collect();
14994
14995                all_selections
14996                    .into_iter()
14997                    .partition(|s| columnar_selection_ids.contains(&s.id))
14998            } else {
14999                (Vec::new(), all_selections)
15000            }
15001        };
15002
15003        let mut state = self
15004            .add_selections_state
15005            .take()
15006            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15007
15008        for selection in new_selections_to_columnarize {
15009            let range = selection.display_range(&display_map).sorted();
15010            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15011            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15012            let positions = start_x.min(end_x)..start_x.max(end_x);
15013            let mut stack = Vec::new();
15014            for row in range.start.row().0..=range.end.row().0 {
15015                if let Some(selection) = self.selections.build_columnar_selection(
15016                    &display_map,
15017                    DisplayRow(row),
15018                    &positions,
15019                    selection.reversed,
15020                    &text_layout_details,
15021                ) {
15022                    stack.push(selection.id);
15023                    columnar_selections.push(selection);
15024                }
15025            }
15026            if !stack.is_empty() {
15027                if above {
15028                    stack.reverse();
15029                }
15030                state.groups.push(AddSelectionsGroup { above, stack });
15031            }
15032        }
15033
15034        let mut final_selections = Vec::new();
15035        let end_row = if above {
15036            DisplayRow(0)
15037        } else {
15038            display_map.max_point().row()
15039        };
15040
15041        let mut last_added_item_per_group = HashMap::default();
15042        for group in state.groups.iter_mut() {
15043            if let Some(last_id) = group.stack.last() {
15044                last_added_item_per_group.insert(*last_id, group);
15045            }
15046        }
15047
15048        for selection in columnar_selections {
15049            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15050                if above == group.above {
15051                    let range = selection.display_range(&display_map).sorted();
15052                    debug_assert_eq!(range.start.row(), range.end.row());
15053                    let mut row = range.start.row();
15054                    let positions =
15055                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15056                            Pixels::from(start)..Pixels::from(end)
15057                        } else {
15058                            let start_x =
15059                                display_map.x_for_display_point(range.start, &text_layout_details);
15060                            let end_x =
15061                                display_map.x_for_display_point(range.end, &text_layout_details);
15062                            start_x.min(end_x)..start_x.max(end_x)
15063                        };
15064
15065                    let mut maybe_new_selection = None;
15066                    let direction = if above { -1 } else { 1 };
15067
15068                    while row != end_row {
15069                        let new_buffer_row = if skip_soft_wrap {
15070                            let new_row = display_map
15071                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction);
15072                            row = new_row.row();
15073                            Some(new_row.to_point(&display_map).row)
15074                        } else {
15075                            if above {
15076                                row.0 -= 1;
15077                            } else {
15078                                row.0 += 1;
15079                            }
15080                            None
15081                        };
15082
15083                        let new_selection = if let Some(buffer_row) = new_buffer_row {
15084                            let start_col = selection.start.column;
15085                            let end_col = selection.end.column;
15086                            let buffer_columns = start_col.min(end_col)..start_col.max(end_col);
15087
15088                            self.selections
15089                                .build_columnar_selection_from_buffer_columns(
15090                                    &display_map,
15091                                    buffer_row,
15092                                    &buffer_columns,
15093                                    selection.reversed,
15094                                    &text_layout_details,
15095                                )
15096                        } else {
15097                            self.selections.build_columnar_selection(
15098                                &display_map,
15099                                row,
15100                                &positions,
15101                                selection.reversed,
15102                                &text_layout_details,
15103                            )
15104                        };
15105
15106                        if let Some(new_selection) = new_selection {
15107                            maybe_new_selection = Some(new_selection);
15108                            break;
15109                        }
15110                    }
15111
15112                    if let Some(new_selection) = maybe_new_selection {
15113                        group.stack.push(new_selection.id);
15114                        if above {
15115                            final_selections.push(new_selection);
15116                            final_selections.push(selection);
15117                        } else {
15118                            final_selections.push(selection);
15119                            final_selections.push(new_selection);
15120                        }
15121                    } else {
15122                        final_selections.push(selection);
15123                    }
15124                } else {
15125                    group.stack.pop();
15126                }
15127            } else {
15128                final_selections.push(selection);
15129            }
15130        }
15131
15132        self.change_selections(Default::default(), window, cx, |s| {
15133            s.select(final_selections);
15134        });
15135
15136        let final_selection_ids: HashSet<_> = self
15137            .selections
15138            .all::<Point>(&display_map)
15139            .iter()
15140            .map(|s| s.id)
15141            .collect();
15142        state.groups.retain_mut(|group| {
15143            // selections might get merged above so we remove invalid items from stacks
15144            group.stack.retain(|id| final_selection_ids.contains(id));
15145
15146            // single selection in stack can be treated as initial state
15147            group.stack.len() > 1
15148        });
15149
15150        if !state.groups.is_empty() {
15151            self.add_selections_state = Some(state);
15152        }
15153    }
15154
15155    pub fn insert_snippet_at_selections(
15156        &mut self,
15157        action: &InsertSnippet,
15158        window: &mut Window,
15159        cx: &mut Context<Self>,
15160    ) {
15161        self.try_insert_snippet_at_selections(action, window, cx)
15162            .log_err();
15163    }
15164
15165    fn try_insert_snippet_at_selections(
15166        &mut self,
15167        action: &InsertSnippet,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) -> Result<()> {
15171        let insertion_ranges = self
15172            .selections
15173            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15174            .into_iter()
15175            .map(|selection| selection.range())
15176            .collect_vec();
15177
15178        let snippet = if let Some(snippet_body) = &action.snippet {
15179            if action.language.is_none() && action.name.is_none() {
15180                Snippet::parse(snippet_body)?
15181            } else {
15182                bail!("`snippet` is mutually exclusive with `language` and `name`")
15183            }
15184        } else if let Some(name) = &action.name {
15185            let project = self.project().context("no project")?;
15186            let snippet_store = project.read(cx).snippets().read(cx);
15187            let snippet = snippet_store
15188                .snippets_for(action.language.clone(), cx)
15189                .into_iter()
15190                .find(|snippet| snippet.name == *name)
15191                .context("snippet not found")?;
15192            Snippet::parse(&snippet.body)?
15193        } else {
15194            // todo(andrew): open modal to select snippet
15195            bail!("`name` or `snippet` is required")
15196        };
15197
15198        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15199    }
15200
15201    fn select_match_ranges(
15202        &mut self,
15203        range: Range<MultiBufferOffset>,
15204        reversed: bool,
15205        replace_newest: bool,
15206        auto_scroll: Option<Autoscroll>,
15207        window: &mut Window,
15208        cx: &mut Context<Editor>,
15209    ) {
15210        self.unfold_ranges(
15211            std::slice::from_ref(&range),
15212            false,
15213            auto_scroll.is_some(),
15214            cx,
15215        );
15216        let effects = if let Some(scroll) = auto_scroll {
15217            SelectionEffects::scroll(scroll)
15218        } else {
15219            SelectionEffects::no_scroll()
15220        };
15221        self.change_selections(effects, window, cx, |s| {
15222            if replace_newest {
15223                s.delete(s.newest_anchor().id);
15224            }
15225            if reversed {
15226                s.insert_range(range.end..range.start);
15227            } else {
15228                s.insert_range(range);
15229            }
15230        });
15231    }
15232
15233    pub fn select_next_match_internal(
15234        &mut self,
15235        display_map: &DisplaySnapshot,
15236        replace_newest: bool,
15237        autoscroll: Option<Autoscroll>,
15238        window: &mut Window,
15239        cx: &mut Context<Self>,
15240    ) -> Result<()> {
15241        let buffer = display_map.buffer_snapshot();
15242        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15243        if let Some(mut select_next_state) = self.select_next_state.take() {
15244            let query = &select_next_state.query;
15245            if !select_next_state.done {
15246                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15247                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15248                let mut next_selected_range = None;
15249
15250                let bytes_after_last_selection =
15251                    buffer.bytes_in_range(last_selection.end..buffer.len());
15252                let bytes_before_first_selection =
15253                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15254                let query_matches = query
15255                    .stream_find_iter(bytes_after_last_selection)
15256                    .map(|result| (last_selection.end, result))
15257                    .chain(
15258                        query
15259                            .stream_find_iter(bytes_before_first_selection)
15260                            .map(|result| (MultiBufferOffset(0), result)),
15261                    );
15262
15263                for (start_offset, query_match) in query_matches {
15264                    let query_match = query_match.unwrap(); // can only fail due to I/O
15265                    let offset_range =
15266                        start_offset + query_match.start()..start_offset + query_match.end();
15267
15268                    if !select_next_state.wordwise
15269                        || (!buffer.is_inside_word(offset_range.start, None)
15270                            && !buffer.is_inside_word(offset_range.end, None))
15271                    {
15272                        let idx = selections
15273                            .partition_point(|selection| selection.end <= offset_range.start);
15274                        let overlaps = selections
15275                            .get(idx)
15276                            .map_or(false, |selection| selection.start < offset_range.end);
15277
15278                        if !overlaps {
15279                            next_selected_range = Some(offset_range);
15280                            break;
15281                        }
15282                    }
15283                }
15284
15285                if let Some(next_selected_range) = next_selected_range {
15286                    self.select_match_ranges(
15287                        next_selected_range,
15288                        last_selection.reversed,
15289                        replace_newest,
15290                        autoscroll,
15291                        window,
15292                        cx,
15293                    );
15294                } else {
15295                    select_next_state.done = true;
15296                }
15297            }
15298
15299            self.select_next_state = Some(select_next_state);
15300        } else {
15301            let mut only_carets = true;
15302            let mut same_text_selected = true;
15303            let mut selected_text = None;
15304
15305            let mut selections_iter = selections.iter().peekable();
15306            while let Some(selection) = selections_iter.next() {
15307                if selection.start != selection.end {
15308                    only_carets = false;
15309                }
15310
15311                if same_text_selected {
15312                    if selected_text.is_none() {
15313                        selected_text =
15314                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15315                    }
15316
15317                    if let Some(next_selection) = selections_iter.peek() {
15318                        if next_selection.len() == selection.len() {
15319                            let next_selected_text = buffer
15320                                .text_for_range(next_selection.range())
15321                                .collect::<String>();
15322                            if Some(next_selected_text) != selected_text {
15323                                same_text_selected = false;
15324                                selected_text = None;
15325                            }
15326                        } else {
15327                            same_text_selected = false;
15328                            selected_text = None;
15329                        }
15330                    }
15331                }
15332            }
15333
15334            if only_carets {
15335                for selection in &mut selections {
15336                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15337                    selection.start = word_range.start;
15338                    selection.end = word_range.end;
15339                    selection.goal = SelectionGoal::None;
15340                    selection.reversed = false;
15341                    self.select_match_ranges(
15342                        selection.start..selection.end,
15343                        selection.reversed,
15344                        replace_newest,
15345                        autoscroll,
15346                        window,
15347                        cx,
15348                    );
15349                }
15350
15351                if selections.len() == 1 {
15352                    let selection = selections
15353                        .last()
15354                        .expect("ensured that there's only one selection");
15355                    let query = buffer
15356                        .text_for_range(selection.start..selection.end)
15357                        .collect::<String>();
15358                    let is_empty = query.is_empty();
15359                    let select_state = SelectNextState {
15360                        query: self.build_query(&[query], cx)?,
15361                        wordwise: true,
15362                        done: is_empty,
15363                    };
15364                    self.select_next_state = Some(select_state);
15365                } else {
15366                    self.select_next_state = None;
15367                }
15368            } else if let Some(selected_text) = selected_text {
15369                self.select_next_state = Some(SelectNextState {
15370                    query: self.build_query(&[selected_text], cx)?,
15371                    wordwise: false,
15372                    done: false,
15373                });
15374                self.select_next_match_internal(
15375                    display_map,
15376                    replace_newest,
15377                    autoscroll,
15378                    window,
15379                    cx,
15380                )?;
15381            }
15382        }
15383        Ok(())
15384    }
15385
15386    pub fn select_all_matches(
15387        &mut self,
15388        _action: &SelectAllMatches,
15389        window: &mut Window,
15390        cx: &mut Context<Self>,
15391    ) -> Result<()> {
15392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15393
15394        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15395
15396        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15397        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15398        else {
15399            return Ok(());
15400        };
15401
15402        let mut new_selections = Vec::new();
15403
15404        let reversed = self
15405            .selections
15406            .oldest::<MultiBufferOffset>(&display_map)
15407            .reversed;
15408        let buffer = display_map.buffer_snapshot();
15409        let query_matches = select_next_state
15410            .query
15411            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15412
15413        for query_match in query_matches.into_iter() {
15414            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15415            let offset_range = if reversed {
15416                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15417            } else {
15418                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15419            };
15420
15421            if !select_next_state.wordwise
15422                || (!buffer.is_inside_word(offset_range.start, None)
15423                    && !buffer.is_inside_word(offset_range.end, None))
15424            {
15425                new_selections.push(offset_range.start..offset_range.end);
15426            }
15427        }
15428
15429        select_next_state.done = true;
15430
15431        if new_selections.is_empty() {
15432            log::error!("bug: new_selections is empty in select_all_matches");
15433            return Ok(());
15434        }
15435
15436        self.unfold_ranges(&new_selections, false, false, cx);
15437        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15438            selections.select_ranges(new_selections)
15439        });
15440
15441        Ok(())
15442    }
15443
15444    pub fn select_next(
15445        &mut self,
15446        action: &SelectNext,
15447        window: &mut Window,
15448        cx: &mut Context<Self>,
15449    ) -> Result<()> {
15450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15452        self.select_next_match_internal(
15453            &display_map,
15454            action.replace_newest,
15455            Some(Autoscroll::newest()),
15456            window,
15457            cx,
15458        )
15459    }
15460
15461    pub fn select_previous(
15462        &mut self,
15463        action: &SelectPrevious,
15464        window: &mut Window,
15465        cx: &mut Context<Self>,
15466    ) -> Result<()> {
15467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15469        let buffer = display_map.buffer_snapshot();
15470        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15471        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15472            let query = &select_prev_state.query;
15473            if !select_prev_state.done {
15474                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15475                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15476                let mut next_selected_range = None;
15477                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15478                let bytes_before_last_selection =
15479                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15480                let bytes_after_first_selection =
15481                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15482                let query_matches = query
15483                    .stream_find_iter(bytes_before_last_selection)
15484                    .map(|result| (last_selection.start, result))
15485                    .chain(
15486                        query
15487                            .stream_find_iter(bytes_after_first_selection)
15488                            .map(|result| (buffer.len(), result)),
15489                    );
15490                for (end_offset, query_match) in query_matches {
15491                    let query_match = query_match.unwrap(); // can only fail due to I/O
15492                    let offset_range =
15493                        end_offset - query_match.end()..end_offset - query_match.start();
15494
15495                    if !select_prev_state.wordwise
15496                        || (!buffer.is_inside_word(offset_range.start, None)
15497                            && !buffer.is_inside_word(offset_range.end, None))
15498                    {
15499                        next_selected_range = Some(offset_range);
15500                        break;
15501                    }
15502                }
15503
15504                if let Some(next_selected_range) = next_selected_range {
15505                    self.select_match_ranges(
15506                        next_selected_range,
15507                        last_selection.reversed,
15508                        action.replace_newest,
15509                        Some(Autoscroll::newest()),
15510                        window,
15511                        cx,
15512                    );
15513                } else {
15514                    select_prev_state.done = true;
15515                }
15516            }
15517
15518            self.select_prev_state = Some(select_prev_state);
15519        } else {
15520            let mut only_carets = true;
15521            let mut same_text_selected = true;
15522            let mut selected_text = None;
15523
15524            let mut selections_iter = selections.iter().peekable();
15525            while let Some(selection) = selections_iter.next() {
15526                if selection.start != selection.end {
15527                    only_carets = false;
15528                }
15529
15530                if same_text_selected {
15531                    if selected_text.is_none() {
15532                        selected_text =
15533                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15534                    }
15535
15536                    if let Some(next_selection) = selections_iter.peek() {
15537                        if next_selection.len() == selection.len() {
15538                            let next_selected_text = buffer
15539                                .text_for_range(next_selection.range())
15540                                .collect::<String>();
15541                            if Some(next_selected_text) != selected_text {
15542                                same_text_selected = false;
15543                                selected_text = None;
15544                            }
15545                        } else {
15546                            same_text_selected = false;
15547                            selected_text = None;
15548                        }
15549                    }
15550                }
15551            }
15552
15553            if only_carets {
15554                for selection in &mut selections {
15555                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15556                    selection.start = word_range.start;
15557                    selection.end = word_range.end;
15558                    selection.goal = SelectionGoal::None;
15559                    selection.reversed = false;
15560                    self.select_match_ranges(
15561                        selection.start..selection.end,
15562                        selection.reversed,
15563                        action.replace_newest,
15564                        Some(Autoscroll::newest()),
15565                        window,
15566                        cx,
15567                    );
15568                }
15569                if selections.len() == 1 {
15570                    let selection = selections
15571                        .last()
15572                        .expect("ensured that there's only one selection");
15573                    let query = buffer
15574                        .text_for_range(selection.start..selection.end)
15575                        .collect::<String>();
15576                    let is_empty = query.is_empty();
15577                    let select_state = SelectNextState {
15578                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15579                        wordwise: true,
15580                        done: is_empty,
15581                    };
15582                    self.select_prev_state = Some(select_state);
15583                } else {
15584                    self.select_prev_state = None;
15585                }
15586            } else if let Some(selected_text) = selected_text {
15587                self.select_prev_state = Some(SelectNextState {
15588                    query: self
15589                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15590                    wordwise: false,
15591                    done: false,
15592                });
15593                self.select_previous(action, window, cx)?;
15594            }
15595        }
15596        Ok(())
15597    }
15598
15599    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15600    /// setting the case sensitivity based on the global
15601    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15602    /// editor's settings.
15603    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15604    where
15605        I: IntoIterator<Item = P>,
15606        P: AsRef<[u8]>,
15607    {
15608        let case_sensitive = self
15609            .select_next_is_case_sensitive
15610            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15611
15612        let mut builder = AhoCorasickBuilder::new();
15613        builder.ascii_case_insensitive(!case_sensitive);
15614        builder.build(patterns)
15615    }
15616
15617    pub fn find_next_match(
15618        &mut self,
15619        _: &FindNextMatch,
15620        window: &mut Window,
15621        cx: &mut Context<Self>,
15622    ) -> Result<()> {
15623        let selections = self.selections.disjoint_anchors_arc();
15624        match selections.first() {
15625            Some(first) if selections.len() >= 2 => {
15626                self.change_selections(Default::default(), window, cx, |s| {
15627                    s.select_ranges([first.range()]);
15628                });
15629            }
15630            _ => self.select_next(
15631                &SelectNext {
15632                    replace_newest: true,
15633                },
15634                window,
15635                cx,
15636            )?,
15637        }
15638        Ok(())
15639    }
15640
15641    pub fn find_previous_match(
15642        &mut self,
15643        _: &FindPreviousMatch,
15644        window: &mut Window,
15645        cx: &mut Context<Self>,
15646    ) -> Result<()> {
15647        let selections = self.selections.disjoint_anchors_arc();
15648        match selections.last() {
15649            Some(last) if selections.len() >= 2 => {
15650                self.change_selections(Default::default(), window, cx, |s| {
15651                    s.select_ranges([last.range()]);
15652                });
15653            }
15654            _ => self.select_previous(
15655                &SelectPrevious {
15656                    replace_newest: true,
15657                },
15658                window,
15659                cx,
15660            )?,
15661        }
15662        Ok(())
15663    }
15664
15665    pub fn toggle_comments(
15666        &mut self,
15667        action: &ToggleComments,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) {
15671        if self.read_only(cx) {
15672            return;
15673        }
15674        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15675        let text_layout_details = &self.text_layout_details(window);
15676        self.transact(window, cx, |this, window, cx| {
15677            let mut selections = this
15678                .selections
15679                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15680            let mut edits = Vec::new();
15681            let mut selection_edit_ranges = Vec::new();
15682            let mut last_toggled_row = None;
15683            let snapshot = this.buffer.read(cx).read(cx);
15684            let empty_str: Arc<str> = Arc::default();
15685            let mut suffixes_inserted = Vec::new();
15686            let ignore_indent = action.ignore_indent;
15687
15688            fn comment_prefix_range(
15689                snapshot: &MultiBufferSnapshot,
15690                row: MultiBufferRow,
15691                comment_prefix: &str,
15692                comment_prefix_whitespace: &str,
15693                ignore_indent: bool,
15694            ) -> Range<Point> {
15695                let indent_size = if ignore_indent {
15696                    0
15697                } else {
15698                    snapshot.indent_size_for_line(row).len
15699                };
15700
15701                let start = Point::new(row.0, indent_size);
15702
15703                let mut line_bytes = snapshot
15704                    .bytes_in_range(start..snapshot.max_point())
15705                    .flatten()
15706                    .copied();
15707
15708                // If this line currently begins with the line comment prefix, then record
15709                // the range containing the prefix.
15710                if line_bytes
15711                    .by_ref()
15712                    .take(comment_prefix.len())
15713                    .eq(comment_prefix.bytes())
15714                {
15715                    // Include any whitespace that matches the comment prefix.
15716                    let matching_whitespace_len = line_bytes
15717                        .zip(comment_prefix_whitespace.bytes())
15718                        .take_while(|(a, b)| a == b)
15719                        .count() as u32;
15720                    let end = Point::new(
15721                        start.row,
15722                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15723                    );
15724                    start..end
15725                } else {
15726                    start..start
15727                }
15728            }
15729
15730            fn comment_suffix_range(
15731                snapshot: &MultiBufferSnapshot,
15732                row: MultiBufferRow,
15733                comment_suffix: &str,
15734                comment_suffix_has_leading_space: bool,
15735            ) -> Range<Point> {
15736                let end = Point::new(row.0, snapshot.line_len(row));
15737                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15738
15739                let mut line_end_bytes = snapshot
15740                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15741                    .flatten()
15742                    .copied();
15743
15744                let leading_space_len = if suffix_start_column > 0
15745                    && line_end_bytes.next() == Some(b' ')
15746                    && comment_suffix_has_leading_space
15747                {
15748                    1
15749                } else {
15750                    0
15751                };
15752
15753                // If this line currently begins with the line comment prefix, then record
15754                // the range containing the prefix.
15755                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15756                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15757                    start..end
15758                } else {
15759                    end..end
15760                }
15761            }
15762
15763            // TODO: Handle selections that cross excerpts
15764            for selection in &mut selections {
15765                let start_column = snapshot
15766                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15767                    .len;
15768                let language = if let Some(language) =
15769                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15770                {
15771                    language
15772                } else {
15773                    continue;
15774                };
15775
15776                selection_edit_ranges.clear();
15777
15778                // If multiple selections contain a given row, avoid processing that
15779                // row more than once.
15780                let mut start_row = MultiBufferRow(selection.start.row);
15781                if last_toggled_row == Some(start_row) {
15782                    start_row = start_row.next_row();
15783                }
15784                let end_row =
15785                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15786                        MultiBufferRow(selection.end.row - 1)
15787                    } else {
15788                        MultiBufferRow(selection.end.row)
15789                    };
15790                last_toggled_row = Some(end_row);
15791
15792                if start_row > end_row {
15793                    continue;
15794                }
15795
15796                // If the language has line comments, toggle those.
15797                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15798
15799                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15800                if ignore_indent {
15801                    full_comment_prefixes = full_comment_prefixes
15802                        .into_iter()
15803                        .map(|s| Arc::from(s.trim_end()))
15804                        .collect();
15805                }
15806
15807                if !full_comment_prefixes.is_empty() {
15808                    let first_prefix = full_comment_prefixes
15809                        .first()
15810                        .expect("prefixes is non-empty");
15811                    let prefix_trimmed_lengths = full_comment_prefixes
15812                        .iter()
15813                        .map(|p| p.trim_end_matches(' ').len())
15814                        .collect::<SmallVec<[usize; 4]>>();
15815
15816                    let mut all_selection_lines_are_comments = true;
15817
15818                    for row in start_row.0..=end_row.0 {
15819                        let row = MultiBufferRow(row);
15820                        if start_row < end_row && snapshot.is_line_blank(row) {
15821                            continue;
15822                        }
15823
15824                        let prefix_range = full_comment_prefixes
15825                            .iter()
15826                            .zip(prefix_trimmed_lengths.iter().copied())
15827                            .map(|(prefix, trimmed_prefix_len)| {
15828                                comment_prefix_range(
15829                                    snapshot.deref(),
15830                                    row,
15831                                    &prefix[..trimmed_prefix_len],
15832                                    &prefix[trimmed_prefix_len..],
15833                                    ignore_indent,
15834                                )
15835                            })
15836                            .max_by_key(|range| range.end.column - range.start.column)
15837                            .expect("prefixes is non-empty");
15838
15839                        if prefix_range.is_empty() {
15840                            all_selection_lines_are_comments = false;
15841                        }
15842
15843                        selection_edit_ranges.push(prefix_range);
15844                    }
15845
15846                    if all_selection_lines_are_comments {
15847                        edits.extend(
15848                            selection_edit_ranges
15849                                .iter()
15850                                .cloned()
15851                                .map(|range| (range, empty_str.clone())),
15852                        );
15853                    } else {
15854                        let min_column = selection_edit_ranges
15855                            .iter()
15856                            .map(|range| range.start.column)
15857                            .min()
15858                            .unwrap_or(0);
15859                        edits.extend(selection_edit_ranges.iter().map(|range| {
15860                            let position = Point::new(range.start.row, min_column);
15861                            (position..position, first_prefix.clone())
15862                        }));
15863                    }
15864                } else if let Some(BlockCommentConfig {
15865                    start: full_comment_prefix,
15866                    end: comment_suffix,
15867                    ..
15868                }) = language.block_comment()
15869                {
15870                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15871                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15872                    let prefix_range = comment_prefix_range(
15873                        snapshot.deref(),
15874                        start_row,
15875                        comment_prefix,
15876                        comment_prefix_whitespace,
15877                        ignore_indent,
15878                    );
15879                    let suffix_range = comment_suffix_range(
15880                        snapshot.deref(),
15881                        end_row,
15882                        comment_suffix.trim_start_matches(' '),
15883                        comment_suffix.starts_with(' '),
15884                    );
15885
15886                    if prefix_range.is_empty() || suffix_range.is_empty() {
15887                        edits.push((
15888                            prefix_range.start..prefix_range.start,
15889                            full_comment_prefix.clone(),
15890                        ));
15891                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15892                        suffixes_inserted.push((end_row, comment_suffix.len()));
15893                    } else {
15894                        edits.push((prefix_range, empty_str.clone()));
15895                        edits.push((suffix_range, empty_str.clone()));
15896                    }
15897                } else {
15898                    continue;
15899                }
15900            }
15901
15902            drop(snapshot);
15903            this.buffer.update(cx, |buffer, cx| {
15904                buffer.edit(edits, None, cx);
15905            });
15906
15907            // Adjust selections so that they end before any comment suffixes that
15908            // were inserted.
15909            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15910            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15911            let snapshot = this.buffer.read(cx).read(cx);
15912            for selection in &mut selections {
15913                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15914                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15915                        Ordering::Less => {
15916                            suffixes_inserted.next();
15917                            continue;
15918                        }
15919                        Ordering::Greater => break,
15920                        Ordering::Equal => {
15921                            if selection.end.column == snapshot.line_len(row) {
15922                                if selection.is_empty() {
15923                                    selection.start.column -= suffix_len as u32;
15924                                }
15925                                selection.end.column -= suffix_len as u32;
15926                            }
15927                            break;
15928                        }
15929                    }
15930                }
15931            }
15932
15933            drop(snapshot);
15934            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15935
15936            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15937            let selections_on_single_row = selections.windows(2).all(|selections| {
15938                selections[0].start.row == selections[1].start.row
15939                    && selections[0].end.row == selections[1].end.row
15940                    && selections[0].start.row == selections[0].end.row
15941            });
15942            let selections_selecting = selections
15943                .iter()
15944                .any(|selection| selection.start != selection.end);
15945            let advance_downwards = action.advance_downwards
15946                && selections_on_single_row
15947                && !selections_selecting
15948                && !matches!(this.mode, EditorMode::SingleLine);
15949
15950            if advance_downwards {
15951                let snapshot = this.buffer.read(cx).snapshot(cx);
15952
15953                this.change_selections(Default::default(), window, cx, |s| {
15954                    s.move_cursors_with(|display_snapshot, display_point, _| {
15955                        let mut point = display_point.to_point(display_snapshot);
15956                        point.row += 1;
15957                        point = snapshot.clip_point(point, Bias::Left);
15958                        let display_point = point.to_display_point(display_snapshot);
15959                        let goal = SelectionGoal::HorizontalPosition(
15960                            display_snapshot
15961                                .x_for_display_point(display_point, text_layout_details)
15962                                .into(),
15963                        );
15964                        (display_point, goal)
15965                    })
15966                });
15967            }
15968        });
15969    }
15970
15971    pub fn select_enclosing_symbol(
15972        &mut self,
15973        _: &SelectEnclosingSymbol,
15974        window: &mut Window,
15975        cx: &mut Context<Self>,
15976    ) {
15977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15978
15979        let buffer = self.buffer.read(cx).snapshot(cx);
15980        let old_selections = self
15981            .selections
15982            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15983            .into_boxed_slice();
15984
15985        fn update_selection(
15986            selection: &Selection<MultiBufferOffset>,
15987            buffer_snap: &MultiBufferSnapshot,
15988        ) -> Option<Selection<MultiBufferOffset>> {
15989            let cursor = selection.head();
15990            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15991            for symbol in symbols.iter().rev() {
15992                let start = symbol.range.start.to_offset(buffer_snap);
15993                let end = symbol.range.end.to_offset(buffer_snap);
15994                let new_range = start..end;
15995                if start < selection.start || end > selection.end {
15996                    return Some(Selection {
15997                        id: selection.id,
15998                        start: new_range.start,
15999                        end: new_range.end,
16000                        goal: SelectionGoal::None,
16001                        reversed: selection.reversed,
16002                    });
16003                }
16004            }
16005            None
16006        }
16007
16008        let mut selected_larger_symbol = false;
16009        let new_selections = old_selections
16010            .iter()
16011            .map(|selection| match update_selection(selection, &buffer) {
16012                Some(new_selection) => {
16013                    if new_selection.range() != selection.range() {
16014                        selected_larger_symbol = true;
16015                    }
16016                    new_selection
16017                }
16018                None => selection.clone(),
16019            })
16020            .collect::<Vec<_>>();
16021
16022        if selected_larger_symbol {
16023            self.change_selections(Default::default(), window, cx, |s| {
16024                s.select(new_selections);
16025            });
16026        }
16027    }
16028
16029    pub fn select_larger_syntax_node(
16030        &mut self,
16031        _: &SelectLargerSyntaxNode,
16032        window: &mut Window,
16033        cx: &mut Context<Self>,
16034    ) {
16035        let Some(visible_row_count) = self.visible_row_count() else {
16036            return;
16037        };
16038        let old_selections: Box<[_]> = self
16039            .selections
16040            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16041            .into();
16042        if old_selections.is_empty() {
16043            return;
16044        }
16045
16046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16047
16048        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16049        let buffer = self.buffer.read(cx).snapshot(cx);
16050
16051        let mut selected_larger_node = false;
16052        let mut new_selections = old_selections
16053            .iter()
16054            .map(|selection| {
16055                let old_range = selection.start..selection.end;
16056
16057                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16058                    // manually select word at selection
16059                    if ["string_content", "inline"].contains(&node.kind()) {
16060                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16061                        // ignore if word is already selected
16062                        if !word_range.is_empty() && old_range != word_range {
16063                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16064                            // only select word if start and end point belongs to same word
16065                            if word_range == last_word_range {
16066                                selected_larger_node = true;
16067                                return Selection {
16068                                    id: selection.id,
16069                                    start: word_range.start,
16070                                    end: word_range.end,
16071                                    goal: SelectionGoal::None,
16072                                    reversed: selection.reversed,
16073                                };
16074                            }
16075                        }
16076                    }
16077                }
16078
16079                let mut new_range = old_range.clone();
16080                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16081                    new_range = range;
16082                    if !node.is_named() {
16083                        continue;
16084                    }
16085                    if !display_map.intersects_fold(new_range.start)
16086                        && !display_map.intersects_fold(new_range.end)
16087                    {
16088                        break;
16089                    }
16090                }
16091
16092                selected_larger_node |= new_range != old_range;
16093                Selection {
16094                    id: selection.id,
16095                    start: new_range.start,
16096                    end: new_range.end,
16097                    goal: SelectionGoal::None,
16098                    reversed: selection.reversed,
16099                }
16100            })
16101            .collect::<Vec<_>>();
16102
16103        if !selected_larger_node {
16104            return; // don't put this call in the history
16105        }
16106
16107        // scroll based on transformation done to the last selection created by the user
16108        let (last_old, last_new) = old_selections
16109            .last()
16110            .zip(new_selections.last().cloned())
16111            .expect("old_selections isn't empty");
16112
16113        // revert selection
16114        let is_selection_reversed = {
16115            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16116            new_selections.last_mut().expect("checked above").reversed =
16117                should_newest_selection_be_reversed;
16118            should_newest_selection_be_reversed
16119        };
16120
16121        if selected_larger_node {
16122            self.select_syntax_node_history.disable_clearing = true;
16123            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16124                s.select(new_selections.clone());
16125            });
16126            self.select_syntax_node_history.disable_clearing = false;
16127        }
16128
16129        let start_row = last_new.start.to_display_point(&display_map).row().0;
16130        let end_row = last_new.end.to_display_point(&display_map).row().0;
16131        let selection_height = end_row - start_row + 1;
16132        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16133
16134        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16135        let scroll_behavior = if fits_on_the_screen {
16136            self.request_autoscroll(Autoscroll::fit(), cx);
16137            SelectSyntaxNodeScrollBehavior::FitSelection
16138        } else if is_selection_reversed {
16139            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16140            SelectSyntaxNodeScrollBehavior::CursorTop
16141        } else {
16142            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16143            SelectSyntaxNodeScrollBehavior::CursorBottom
16144        };
16145
16146        self.select_syntax_node_history.push((
16147            old_selections,
16148            scroll_behavior,
16149            is_selection_reversed,
16150        ));
16151    }
16152
16153    pub fn select_smaller_syntax_node(
16154        &mut self,
16155        _: &SelectSmallerSyntaxNode,
16156        window: &mut Window,
16157        cx: &mut Context<Self>,
16158    ) {
16159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16160
16161        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16162            self.select_syntax_node_history.pop()
16163        {
16164            if let Some(selection) = selections.last_mut() {
16165                selection.reversed = is_selection_reversed;
16166            }
16167
16168            self.select_syntax_node_history.disable_clearing = true;
16169            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16170                s.select(selections.to_vec());
16171            });
16172            self.select_syntax_node_history.disable_clearing = false;
16173
16174            match scroll_behavior {
16175                SelectSyntaxNodeScrollBehavior::CursorTop => {
16176                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16177                }
16178                SelectSyntaxNodeScrollBehavior::FitSelection => {
16179                    self.request_autoscroll(Autoscroll::fit(), cx);
16180                }
16181                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16182                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16183                }
16184            }
16185        }
16186    }
16187
16188    pub fn unwrap_syntax_node(
16189        &mut self,
16190        _: &UnwrapSyntaxNode,
16191        window: &mut Window,
16192        cx: &mut Context<Self>,
16193    ) {
16194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16195
16196        let buffer = self.buffer.read(cx).snapshot(cx);
16197        let selections = self
16198            .selections
16199            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16200            .into_iter()
16201            // subtracting the offset requires sorting
16202            .sorted_by_key(|i| i.start);
16203
16204        let full_edits = selections
16205            .into_iter()
16206            .filter_map(|selection| {
16207                let child = if selection.is_empty()
16208                    && let Some((_, ancestor_range)) =
16209                        buffer.syntax_ancestor(selection.start..selection.end)
16210                {
16211                    ancestor_range
16212                } else {
16213                    selection.range()
16214                };
16215
16216                let mut parent = child.clone();
16217                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16218                    parent = ancestor_range;
16219                    if parent.start < child.start || parent.end > child.end {
16220                        break;
16221                    }
16222                }
16223
16224                if parent == child {
16225                    return None;
16226                }
16227                let text = buffer.text_for_range(child).collect::<String>();
16228                Some((selection.id, parent, text))
16229            })
16230            .collect::<Vec<_>>();
16231        if full_edits.is_empty() {
16232            return;
16233        }
16234
16235        self.transact(window, cx, |this, window, cx| {
16236            this.buffer.update(cx, |buffer, cx| {
16237                buffer.edit(
16238                    full_edits
16239                        .iter()
16240                        .map(|(_, p, t)| (p.clone(), t.clone()))
16241                        .collect::<Vec<_>>(),
16242                    None,
16243                    cx,
16244                );
16245            });
16246            this.change_selections(Default::default(), window, cx, |s| {
16247                let mut offset = 0;
16248                let mut selections = vec![];
16249                for (id, parent, text) in full_edits {
16250                    let start = parent.start - offset;
16251                    offset += (parent.end - parent.start) - text.len();
16252                    selections.push(Selection {
16253                        id,
16254                        start,
16255                        end: start + text.len(),
16256                        reversed: false,
16257                        goal: Default::default(),
16258                    });
16259                }
16260                s.select(selections);
16261            });
16262        });
16263    }
16264
16265    pub fn select_next_syntax_node(
16266        &mut self,
16267        _: &SelectNextSyntaxNode,
16268        window: &mut Window,
16269        cx: &mut Context<Self>,
16270    ) {
16271        let old_selections: Box<[_]> = self
16272            .selections
16273            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16274            .into();
16275        if old_selections.is_empty() {
16276            return;
16277        }
16278
16279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16280
16281        let buffer = self.buffer.read(cx).snapshot(cx);
16282        let mut selected_sibling = false;
16283
16284        let new_selections = old_selections
16285            .iter()
16286            .map(|selection| {
16287                let old_range = selection.start..selection.end;
16288
16289                let old_range =
16290                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16291                let excerpt = buffer.excerpt_containing(old_range.clone());
16292
16293                if let Some(mut excerpt) = excerpt
16294                    && let Some(node) = excerpt
16295                        .buffer()
16296                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16297                {
16298                    let new_range = excerpt.map_range_from_buffer(
16299                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16300                    );
16301                    selected_sibling = true;
16302                    Selection {
16303                        id: selection.id,
16304                        start: new_range.start,
16305                        end: new_range.end,
16306                        goal: SelectionGoal::None,
16307                        reversed: selection.reversed,
16308                    }
16309                } else {
16310                    selection.clone()
16311                }
16312            })
16313            .collect::<Vec<_>>();
16314
16315        if selected_sibling {
16316            self.change_selections(
16317                SelectionEffects::scroll(Autoscroll::fit()),
16318                window,
16319                cx,
16320                |s| {
16321                    s.select(new_selections);
16322                },
16323            );
16324        }
16325    }
16326
16327    pub fn select_prev_syntax_node(
16328        &mut self,
16329        _: &SelectPreviousSyntaxNode,
16330        window: &mut Window,
16331        cx: &mut Context<Self>,
16332    ) {
16333        let old_selections: Box<[_]> = self
16334            .selections
16335            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16336            .into();
16337        if old_selections.is_empty() {
16338            return;
16339        }
16340
16341        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16342
16343        let buffer = self.buffer.read(cx).snapshot(cx);
16344        let mut selected_sibling = false;
16345
16346        let new_selections = old_selections
16347            .iter()
16348            .map(|selection| {
16349                let old_range = selection.start..selection.end;
16350                let old_range =
16351                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16352                let excerpt = buffer.excerpt_containing(old_range.clone());
16353
16354                if let Some(mut excerpt) = excerpt
16355                    && let Some(node) = excerpt
16356                        .buffer()
16357                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16358                {
16359                    let new_range = excerpt.map_range_from_buffer(
16360                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16361                    );
16362                    selected_sibling = true;
16363                    Selection {
16364                        id: selection.id,
16365                        start: new_range.start,
16366                        end: new_range.end,
16367                        goal: SelectionGoal::None,
16368                        reversed: selection.reversed,
16369                    }
16370                } else {
16371                    selection.clone()
16372                }
16373            })
16374            .collect::<Vec<_>>();
16375
16376        if selected_sibling {
16377            self.change_selections(
16378                SelectionEffects::scroll(Autoscroll::fit()),
16379                window,
16380                cx,
16381                |s| {
16382                    s.select(new_selections);
16383                },
16384            );
16385        }
16386    }
16387
16388    pub fn move_to_start_of_larger_syntax_node(
16389        &mut self,
16390        _: &MoveToStartOfLargerSyntaxNode,
16391        window: &mut Window,
16392        cx: &mut Context<Self>,
16393    ) {
16394        self.move_cursors_to_syntax_nodes(window, cx, false);
16395    }
16396
16397    pub fn move_to_end_of_larger_syntax_node(
16398        &mut self,
16399        _: &MoveToEndOfLargerSyntaxNode,
16400        window: &mut Window,
16401        cx: &mut Context<Self>,
16402    ) {
16403        self.move_cursors_to_syntax_nodes(window, cx, true);
16404    }
16405
16406    fn move_cursors_to_syntax_nodes(
16407        &mut self,
16408        window: &mut Window,
16409        cx: &mut Context<Self>,
16410        move_to_end: bool,
16411    ) -> bool {
16412        let old_selections: Box<[_]> = self
16413            .selections
16414            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16415            .into();
16416        if old_selections.is_empty() {
16417            return false;
16418        }
16419
16420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16421
16422        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16423        let buffer = self.buffer.read(cx).snapshot(cx);
16424
16425        let mut any_cursor_moved = false;
16426        let new_selections = old_selections
16427            .iter()
16428            .map(|selection| {
16429                if !selection.is_empty() {
16430                    return selection.clone();
16431                }
16432
16433                let selection_pos = selection.head();
16434                let old_range = selection_pos..selection_pos;
16435
16436                let mut new_pos = selection_pos;
16437                let mut search_range = old_range;
16438                while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
16439                    search_range = range.clone();
16440                    if !node.is_named()
16441                        || display_map.intersects_fold(range.start)
16442                        || display_map.intersects_fold(range.end)
16443                        // If cursor is already at the end of the syntax node, continue searching
16444                        || (move_to_end && range.end == selection_pos)
16445                        // If cursor is already at the start of the syntax node, continue searching
16446                        || (!move_to_end && range.start == selection_pos)
16447                    {
16448                        continue;
16449                    }
16450
16451                    // If we found a string_content node, find the largest parent that is still string_content
16452                    // Enables us to skip to the end of strings without taking multiple steps inside the string
16453                    let (_, final_range) = if node.kind() == "string_content" {
16454                        let mut current_node = node;
16455                        let mut current_range = range;
16456                        while let Some((parent, parent_range)) =
16457                            buffer.syntax_ancestor(current_range.clone())
16458                        {
16459                            if parent.kind() == "string_content" {
16460                                current_node = parent;
16461                                current_range = parent_range;
16462                            } else {
16463                                break;
16464                            }
16465                        }
16466
16467                        (current_node, current_range)
16468                    } else {
16469                        (node, range)
16470                    };
16471
16472                    new_pos = if move_to_end {
16473                        final_range.end
16474                    } else {
16475                        final_range.start
16476                    };
16477
16478                    break;
16479                }
16480
16481                any_cursor_moved |= new_pos != selection_pos;
16482
16483                Selection {
16484                    id: selection.id,
16485                    start: new_pos,
16486                    end: new_pos,
16487                    goal: SelectionGoal::None,
16488                    reversed: false,
16489                }
16490            })
16491            .collect::<Vec<_>>();
16492
16493        self.change_selections(Default::default(), window, cx, |s| {
16494            s.select(new_selections);
16495        });
16496        self.request_autoscroll(Autoscroll::newest(), cx);
16497
16498        any_cursor_moved
16499    }
16500
16501    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16502        if !EditorSettings::get_global(cx).gutter.runnables {
16503            self.clear_tasks();
16504            return Task::ready(());
16505        }
16506        let project = self.project().map(Entity::downgrade);
16507        let task_sources = self.lsp_task_sources(cx);
16508        let multi_buffer = self.buffer.downgrade();
16509        cx.spawn_in(window, async move |editor, cx| {
16510            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16511            let Some(project) = project.and_then(|p| p.upgrade()) else {
16512                return;
16513            };
16514            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16515                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16516            }) else {
16517                return;
16518            };
16519
16520            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16521            if hide_runnables {
16522                return;
16523            }
16524            let new_rows =
16525                cx.background_spawn({
16526                    let snapshot = display_snapshot.clone();
16527                    async move {
16528                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16529                    }
16530                })
16531                    .await;
16532            let Ok(lsp_tasks) =
16533                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16534            else {
16535                return;
16536            };
16537            let lsp_tasks = lsp_tasks.await;
16538
16539            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16540                lsp_tasks
16541                    .into_iter()
16542                    .flat_map(|(kind, tasks)| {
16543                        tasks.into_iter().filter_map(move |(location, task)| {
16544                            Some((kind.clone(), location?, task))
16545                        })
16546                    })
16547                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16548                        let buffer = location.target.buffer;
16549                        let buffer_snapshot = buffer.read(cx).snapshot();
16550                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16551                            |(excerpt_id, snapshot, _)| {
16552                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16553                                    display_snapshot
16554                                        .buffer_snapshot()
16555                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16556                                } else {
16557                                    None
16558                                }
16559                            },
16560                        );
16561                        if let Some(offset) = offset {
16562                            let task_buffer_range =
16563                                location.target.range.to_point(&buffer_snapshot);
16564                            let context_buffer_range =
16565                                task_buffer_range.to_offset(&buffer_snapshot);
16566                            let context_range = BufferOffset(context_buffer_range.start)
16567                                ..BufferOffset(context_buffer_range.end);
16568
16569                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16570                                .or_insert_with(|| RunnableTasks {
16571                                    templates: Vec::new(),
16572                                    offset,
16573                                    column: task_buffer_range.start.column,
16574                                    extra_variables: HashMap::default(),
16575                                    context_range,
16576                                })
16577                                .templates
16578                                .push((kind, task.original_task().clone()));
16579                        }
16580
16581                        acc
16582                    })
16583            }) else {
16584                return;
16585            };
16586
16587            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16588                buffer.language_settings(cx).tasks.prefer_lsp
16589            }) else {
16590                return;
16591            };
16592
16593            let rows = Self::runnable_rows(
16594                project,
16595                display_snapshot,
16596                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16597                new_rows,
16598                cx.clone(),
16599            )
16600            .await;
16601            editor
16602                .update(cx, |editor, _| {
16603                    editor.clear_tasks();
16604                    for (key, mut value) in rows {
16605                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16606                            value.templates.extend(lsp_tasks.templates);
16607                        }
16608
16609                        editor.insert_tasks(key, value);
16610                    }
16611                    for (key, value) in lsp_tasks_by_rows {
16612                        editor.insert_tasks(key, value);
16613                    }
16614                })
16615                .ok();
16616        })
16617    }
16618    fn fetch_runnable_ranges(
16619        snapshot: &DisplaySnapshot,
16620        range: Range<Anchor>,
16621    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16622        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16623    }
16624
16625    fn runnable_rows(
16626        project: Entity<Project>,
16627        snapshot: DisplaySnapshot,
16628        prefer_lsp: bool,
16629        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16630        cx: AsyncWindowContext,
16631    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16632        cx.spawn(async move |cx| {
16633            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16634            for (run_range, mut runnable) in runnable_ranges {
16635                let Some(tasks) = cx
16636                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16637                    .ok()
16638                else {
16639                    continue;
16640                };
16641                let mut tasks = tasks.await;
16642
16643                if prefer_lsp {
16644                    tasks.retain(|(task_kind, _)| {
16645                        !matches!(task_kind, TaskSourceKind::Language { .. })
16646                    });
16647                }
16648                if tasks.is_empty() {
16649                    continue;
16650                }
16651
16652                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16653                let Some(row) = snapshot
16654                    .buffer_snapshot()
16655                    .buffer_line_for_row(MultiBufferRow(point.row))
16656                    .map(|(_, range)| range.start.row)
16657                else {
16658                    continue;
16659                };
16660
16661                let context_range =
16662                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16663                runnable_rows.push((
16664                    (runnable.buffer_id, row),
16665                    RunnableTasks {
16666                        templates: tasks,
16667                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16668                        context_range,
16669                        column: point.column,
16670                        extra_variables: runnable.extra_captures,
16671                    },
16672                ));
16673            }
16674            runnable_rows
16675        })
16676    }
16677
16678    fn templates_with_tags(
16679        project: &Entity<Project>,
16680        runnable: &mut Runnable,
16681        cx: &mut App,
16682    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16683        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16684            let (worktree_id, file) = project
16685                .buffer_for_id(runnable.buffer, cx)
16686                .and_then(|buffer| buffer.read(cx).file())
16687                .map(|file| (file.worktree_id(cx), file.clone()))
16688                .unzip();
16689
16690            (
16691                project.task_store().read(cx).task_inventory().cloned(),
16692                worktree_id,
16693                file,
16694            )
16695        });
16696
16697        let tags = mem::take(&mut runnable.tags);
16698        let language = runnable.language.clone();
16699        cx.spawn(async move |cx| {
16700            let mut templates_with_tags = Vec::new();
16701            if let Some(inventory) = inventory {
16702                for RunnableTag(tag) in tags {
16703                    let new_tasks = inventory.update(cx, |inventory, cx| {
16704                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16705                    });
16706                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16707                        move |(_, template)| {
16708                            template.tags.iter().any(|source_tag| source_tag == &tag)
16709                        },
16710                    ));
16711                }
16712            }
16713            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16714
16715            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16716                // Strongest source wins; if we have worktree tag binding, prefer that to
16717                // global and language bindings;
16718                // if we have a global binding, prefer that to language binding.
16719                let first_mismatch = templates_with_tags
16720                    .iter()
16721                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16722                if let Some(index) = first_mismatch {
16723                    templates_with_tags.truncate(index);
16724                }
16725            }
16726
16727            templates_with_tags
16728        })
16729    }
16730
16731    pub fn move_to_enclosing_bracket(
16732        &mut self,
16733        _: &MoveToEnclosingBracket,
16734        window: &mut Window,
16735        cx: &mut Context<Self>,
16736    ) {
16737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16738        self.change_selections(Default::default(), window, cx, |s| {
16739            s.move_offsets_with(|snapshot, selection| {
16740                let Some(enclosing_bracket_ranges) =
16741                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16742                else {
16743                    return;
16744                };
16745
16746                let mut best_length = usize::MAX;
16747                let mut best_inside = false;
16748                let mut best_in_bracket_range = false;
16749                let mut best_destination = None;
16750                for (open, close) in enclosing_bracket_ranges {
16751                    let close = close.to_inclusive();
16752                    let length = *close.end() - open.start;
16753                    let inside = selection.start >= open.end && selection.end <= *close.start();
16754                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16755                        || close.contains(&selection.head());
16756
16757                    // If best is next to a bracket and current isn't, skip
16758                    if !in_bracket_range && best_in_bracket_range {
16759                        continue;
16760                    }
16761
16762                    // Prefer smaller lengths unless best is inside and current isn't
16763                    if length > best_length && (best_inside || !inside) {
16764                        continue;
16765                    }
16766
16767                    best_length = length;
16768                    best_inside = inside;
16769                    best_in_bracket_range = in_bracket_range;
16770                    best_destination = Some(
16771                        if close.contains(&selection.start) && close.contains(&selection.end) {
16772                            if inside { open.end } else { open.start }
16773                        } else if inside {
16774                            *close.start()
16775                        } else {
16776                            *close.end()
16777                        },
16778                    );
16779                }
16780
16781                if let Some(destination) = best_destination {
16782                    selection.collapse_to(destination, SelectionGoal::None);
16783                }
16784            })
16785        });
16786    }
16787
16788    pub fn undo_selection(
16789        &mut self,
16790        _: &UndoSelection,
16791        window: &mut Window,
16792        cx: &mut Context<Self>,
16793    ) {
16794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16795        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16796            self.selection_history.mode = SelectionHistoryMode::Undoing;
16797            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16798                this.end_selection(window, cx);
16799                this.change_selections(
16800                    SelectionEffects::scroll(Autoscroll::newest()),
16801                    window,
16802                    cx,
16803                    |s| s.select_anchors(entry.selections.to_vec()),
16804                );
16805            });
16806            self.selection_history.mode = SelectionHistoryMode::Normal;
16807
16808            self.select_next_state = entry.select_next_state;
16809            self.select_prev_state = entry.select_prev_state;
16810            self.add_selections_state = entry.add_selections_state;
16811        }
16812    }
16813
16814    pub fn redo_selection(
16815        &mut self,
16816        _: &RedoSelection,
16817        window: &mut Window,
16818        cx: &mut Context<Self>,
16819    ) {
16820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16821        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16822            self.selection_history.mode = SelectionHistoryMode::Redoing;
16823            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16824                this.end_selection(window, cx);
16825                this.change_selections(
16826                    SelectionEffects::scroll(Autoscroll::newest()),
16827                    window,
16828                    cx,
16829                    |s| s.select_anchors(entry.selections.to_vec()),
16830                );
16831            });
16832            self.selection_history.mode = SelectionHistoryMode::Normal;
16833
16834            self.select_next_state = entry.select_next_state;
16835            self.select_prev_state = entry.select_prev_state;
16836            self.add_selections_state = entry.add_selections_state;
16837        }
16838    }
16839
16840    pub fn expand_excerpts(
16841        &mut self,
16842        action: &ExpandExcerpts,
16843        _: &mut Window,
16844        cx: &mut Context<Self>,
16845    ) {
16846        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16847    }
16848
16849    pub fn expand_excerpts_down(
16850        &mut self,
16851        action: &ExpandExcerptsDown,
16852        _: &mut Window,
16853        cx: &mut Context<Self>,
16854    ) {
16855        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16856    }
16857
16858    pub fn expand_excerpts_up(
16859        &mut self,
16860        action: &ExpandExcerptsUp,
16861        _: &mut Window,
16862        cx: &mut Context<Self>,
16863    ) {
16864        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16865    }
16866
16867    pub fn expand_excerpts_for_direction(
16868        &mut self,
16869        lines: u32,
16870        direction: ExpandExcerptDirection,
16871        cx: &mut Context<Self>,
16872    ) {
16873        let selections = self.selections.disjoint_anchors_arc();
16874
16875        let lines = if lines == 0 {
16876            EditorSettings::get_global(cx).expand_excerpt_lines
16877        } else {
16878            lines
16879        };
16880
16881        let snapshot = self.buffer.read(cx).snapshot(cx);
16882        let mut excerpt_ids = selections
16883            .iter()
16884            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16885            .collect::<Vec<_>>();
16886        excerpt_ids.sort();
16887        excerpt_ids.dedup();
16888
16889        if self.delegate_expand_excerpts {
16890            cx.emit(EditorEvent::ExpandExcerptsRequested {
16891                excerpt_ids,
16892                lines,
16893                direction,
16894            });
16895            return;
16896        }
16897
16898        self.buffer.update(cx, |buffer, cx| {
16899            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16900        })
16901    }
16902
16903    pub fn expand_excerpt(
16904        &mut self,
16905        excerpt: ExcerptId,
16906        direction: ExpandExcerptDirection,
16907        window: &mut Window,
16908        cx: &mut Context<Self>,
16909    ) {
16910        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16911
16912        if self.delegate_expand_excerpts {
16913            cx.emit(EditorEvent::ExpandExcerptsRequested {
16914                excerpt_ids: vec![excerpt],
16915                lines: lines_to_expand,
16916                direction,
16917            });
16918            return;
16919        }
16920
16921        let current_scroll_position = self.scroll_position(cx);
16922        let mut scroll = None;
16923
16924        if direction == ExpandExcerptDirection::Down {
16925            let multi_buffer = self.buffer.read(cx);
16926            let snapshot = multi_buffer.snapshot(cx);
16927            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16928                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16929                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16930            {
16931                let buffer_snapshot = buffer.read(cx).snapshot();
16932                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16933                let last_row = buffer_snapshot.max_point().row;
16934                let lines_below = last_row.saturating_sub(excerpt_end_row);
16935                if lines_below >= lines_to_expand {
16936                    scroll = Some(
16937                        current_scroll_position
16938                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16939                    );
16940                }
16941            }
16942        }
16943        if direction == ExpandExcerptDirection::Up
16944            && self
16945                .buffer
16946                .read(cx)
16947                .snapshot(cx)
16948                .excerpt_before(excerpt)
16949                .is_none()
16950        {
16951            scroll = Some(current_scroll_position);
16952        }
16953
16954        self.buffer.update(cx, |buffer, cx| {
16955            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16956        });
16957
16958        if let Some(new_scroll_position) = scroll {
16959            self.set_scroll_position(new_scroll_position, window, cx);
16960        }
16961    }
16962
16963    pub fn go_to_singleton_buffer_point(
16964        &mut self,
16965        point: Point,
16966        window: &mut Window,
16967        cx: &mut Context<Self>,
16968    ) {
16969        self.go_to_singleton_buffer_range(point..point, window, cx);
16970    }
16971
16972    pub fn go_to_singleton_buffer_range(
16973        &mut self,
16974        range: Range<Point>,
16975        window: &mut Window,
16976        cx: &mut Context<Self>,
16977    ) {
16978        let multibuffer = self.buffer().read(cx);
16979        let Some(buffer) = multibuffer.as_singleton() else {
16980            return;
16981        };
16982        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16983            return;
16984        };
16985        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16986            return;
16987        };
16988        self.change_selections(
16989            SelectionEffects::default().nav_history(true),
16990            window,
16991            cx,
16992            |s| s.select_anchor_ranges([start..end]),
16993        );
16994    }
16995
16996    pub fn go_to_diagnostic(
16997        &mut self,
16998        action: &GoToDiagnostic,
16999        window: &mut Window,
17000        cx: &mut Context<Self>,
17001    ) {
17002        if !self.diagnostics_enabled() {
17003            return;
17004        }
17005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17006        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17007    }
17008
17009    pub fn go_to_prev_diagnostic(
17010        &mut self,
17011        action: &GoToPreviousDiagnostic,
17012        window: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) {
17015        if !self.diagnostics_enabled() {
17016            return;
17017        }
17018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17019        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17020    }
17021
17022    pub fn go_to_diagnostic_impl(
17023        &mut self,
17024        direction: Direction,
17025        severity: GoToDiagnosticSeverityFilter,
17026        window: &mut Window,
17027        cx: &mut Context<Self>,
17028    ) {
17029        let buffer = self.buffer.read(cx).snapshot(cx);
17030        let selection = self
17031            .selections
17032            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17033
17034        let mut active_group_id = None;
17035        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17036            && active_group.active_range.start.to_offset(&buffer) == selection.start
17037        {
17038            active_group_id = Some(active_group.group_id);
17039        }
17040
17041        fn filtered<'a>(
17042            severity: GoToDiagnosticSeverityFilter,
17043            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17044        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17045            diagnostics
17046                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17047                .filter(|entry| entry.range.start != entry.range.end)
17048                .filter(|entry| !entry.diagnostic.is_unnecessary)
17049        }
17050
17051        let before = filtered(
17052            severity,
17053            buffer
17054                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17055                .filter(|entry| entry.range.start <= selection.start),
17056        );
17057        let after = filtered(
17058            severity,
17059            buffer
17060                .diagnostics_in_range(selection.start..buffer.len())
17061                .filter(|entry| entry.range.start >= selection.start),
17062        );
17063
17064        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17065        if direction == Direction::Prev {
17066            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17067            {
17068                for diagnostic in prev_diagnostics.into_iter().rev() {
17069                    if diagnostic.range.start != selection.start
17070                        || active_group_id
17071                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17072                    {
17073                        found = Some(diagnostic);
17074                        break 'outer;
17075                    }
17076                }
17077            }
17078        } else {
17079            for diagnostic in after.chain(before) {
17080                if diagnostic.range.start != selection.start
17081                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17082                {
17083                    found = Some(diagnostic);
17084                    break;
17085                }
17086            }
17087        }
17088        let Some(next_diagnostic) = found else {
17089            return;
17090        };
17091
17092        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17093        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17094            return;
17095        };
17096        let snapshot = self.snapshot(window, cx);
17097        if snapshot.intersects_fold(next_diagnostic.range.start) {
17098            self.unfold_ranges(
17099                std::slice::from_ref(&next_diagnostic.range),
17100                true,
17101                false,
17102                cx,
17103            );
17104        }
17105        self.change_selections(Default::default(), window, cx, |s| {
17106            s.select_ranges(vec![
17107                next_diagnostic.range.start..next_diagnostic.range.start,
17108            ])
17109        });
17110        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17111        self.refresh_edit_prediction(false, true, window, cx);
17112    }
17113
17114    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17116        let snapshot = self.snapshot(window, cx);
17117        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17118        self.go_to_hunk_before_or_after_position(
17119            &snapshot,
17120            selection.head(),
17121            Direction::Next,
17122            window,
17123            cx,
17124        );
17125    }
17126
17127    pub fn go_to_hunk_before_or_after_position(
17128        &mut self,
17129        snapshot: &EditorSnapshot,
17130        position: Point,
17131        direction: Direction,
17132        window: &mut Window,
17133        cx: &mut Context<Editor>,
17134    ) {
17135        let row = if direction == Direction::Next {
17136            self.hunk_after_position(snapshot, position)
17137                .map(|hunk| hunk.row_range.start)
17138        } else {
17139            self.hunk_before_position(snapshot, position)
17140        };
17141
17142        if let Some(row) = row {
17143            let destination = Point::new(row.0, 0);
17144            let autoscroll = Autoscroll::center();
17145
17146            self.unfold_ranges(&[destination..destination], false, false, cx);
17147            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17148                s.select_ranges([destination..destination]);
17149            });
17150        }
17151    }
17152
17153    fn hunk_after_position(
17154        &mut self,
17155        snapshot: &EditorSnapshot,
17156        position: Point,
17157    ) -> Option<MultiBufferDiffHunk> {
17158        snapshot
17159            .buffer_snapshot()
17160            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17161            .find(|hunk| hunk.row_range.start.0 > position.row)
17162            .or_else(|| {
17163                snapshot
17164                    .buffer_snapshot()
17165                    .diff_hunks_in_range(Point::zero()..position)
17166                    .find(|hunk| hunk.row_range.end.0 < position.row)
17167            })
17168    }
17169
17170    fn go_to_prev_hunk(
17171        &mut self,
17172        _: &GoToPreviousHunk,
17173        window: &mut Window,
17174        cx: &mut Context<Self>,
17175    ) {
17176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17177        let snapshot = self.snapshot(window, cx);
17178        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17179        self.go_to_hunk_before_or_after_position(
17180            &snapshot,
17181            selection.head(),
17182            Direction::Prev,
17183            window,
17184            cx,
17185        );
17186    }
17187
17188    fn hunk_before_position(
17189        &mut self,
17190        snapshot: &EditorSnapshot,
17191        position: Point,
17192    ) -> Option<MultiBufferRow> {
17193        snapshot
17194            .buffer_snapshot()
17195            .diff_hunk_before(position)
17196            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17197    }
17198
17199    fn go_to_next_change(
17200        &mut self,
17201        _: &GoToNextChange,
17202        window: &mut Window,
17203        cx: &mut Context<Self>,
17204    ) {
17205        if let Some(selections) = self
17206            .change_list
17207            .next_change(1, Direction::Next)
17208            .map(|s| s.to_vec())
17209        {
17210            self.change_selections(Default::default(), window, cx, |s| {
17211                let map = s.display_snapshot();
17212                s.select_display_ranges(selections.iter().map(|a| {
17213                    let point = a.to_display_point(&map);
17214                    point..point
17215                }))
17216            })
17217        }
17218    }
17219
17220    fn go_to_previous_change(
17221        &mut self,
17222        _: &GoToPreviousChange,
17223        window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        if let Some(selections) = self
17227            .change_list
17228            .next_change(1, Direction::Prev)
17229            .map(|s| s.to_vec())
17230        {
17231            self.change_selections(Default::default(), window, cx, |s| {
17232                let map = s.display_snapshot();
17233                s.select_display_ranges(selections.iter().map(|a| {
17234                    let point = a.to_display_point(&map);
17235                    point..point
17236                }))
17237            })
17238        }
17239    }
17240
17241    pub fn go_to_next_document_highlight(
17242        &mut self,
17243        _: &GoToNextDocumentHighlight,
17244        window: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) {
17247        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17248    }
17249
17250    pub fn go_to_prev_document_highlight(
17251        &mut self,
17252        _: &GoToPreviousDocumentHighlight,
17253        window: &mut Window,
17254        cx: &mut Context<Self>,
17255    ) {
17256        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17257    }
17258
17259    pub fn go_to_document_highlight_before_or_after_position(
17260        &mut self,
17261        direction: Direction,
17262        window: &mut Window,
17263        cx: &mut Context<Editor>,
17264    ) {
17265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17266        let snapshot = self.snapshot(window, cx);
17267        let buffer = &snapshot.buffer_snapshot();
17268        let position = self
17269            .selections
17270            .newest::<Point>(&snapshot.display_snapshot)
17271            .head();
17272        let anchor_position = buffer.anchor_after(position);
17273
17274        // Get all document highlights (both read and write)
17275        let mut all_highlights = Vec::new();
17276
17277        if let Some((_, read_highlights)) = self
17278            .background_highlights
17279            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17280        {
17281            all_highlights.extend(read_highlights.iter());
17282        }
17283
17284        if let Some((_, write_highlights)) = self
17285            .background_highlights
17286            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17287        {
17288            all_highlights.extend(write_highlights.iter());
17289        }
17290
17291        if all_highlights.is_empty() {
17292            return;
17293        }
17294
17295        // Sort highlights by position
17296        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17297
17298        let target_highlight = match direction {
17299            Direction::Next => {
17300                // Find the first highlight after the current position
17301                all_highlights
17302                    .iter()
17303                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17304            }
17305            Direction::Prev => {
17306                // Find the last highlight before the current position
17307                all_highlights
17308                    .iter()
17309                    .rev()
17310                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17311            }
17312        };
17313
17314        if let Some(highlight) = target_highlight {
17315            let destination = highlight.start.to_point(buffer);
17316            let autoscroll = Autoscroll::center();
17317
17318            self.unfold_ranges(&[destination..destination], false, false, cx);
17319            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17320                s.select_ranges([destination..destination]);
17321            });
17322        }
17323    }
17324
17325    fn go_to_line<T: 'static>(
17326        &mut self,
17327        position: Anchor,
17328        highlight_color: Option<Hsla>,
17329        window: &mut Window,
17330        cx: &mut Context<Self>,
17331    ) {
17332        let snapshot = self.snapshot(window, cx).display_snapshot;
17333        let position = position.to_point(&snapshot.buffer_snapshot());
17334        let start = snapshot
17335            .buffer_snapshot()
17336            .clip_point(Point::new(position.row, 0), Bias::Left);
17337        let end = start + Point::new(1, 0);
17338        let start = snapshot.buffer_snapshot().anchor_before(start);
17339        let end = snapshot.buffer_snapshot().anchor_before(end);
17340
17341        self.highlight_rows::<T>(
17342            start..end,
17343            highlight_color
17344                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17345            Default::default(),
17346            cx,
17347        );
17348
17349        if self.buffer.read(cx).is_singleton() {
17350            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17351        }
17352    }
17353
17354    pub fn go_to_definition(
17355        &mut self,
17356        _: &GoToDefinition,
17357        window: &mut Window,
17358        cx: &mut Context<Self>,
17359    ) -> Task<Result<Navigated>> {
17360        let definition =
17361            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17362        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17363        cx.spawn_in(window, async move |editor, cx| {
17364            if definition.await? == Navigated::Yes {
17365                return Ok(Navigated::Yes);
17366            }
17367            match fallback_strategy {
17368                GoToDefinitionFallback::None => Ok(Navigated::No),
17369                GoToDefinitionFallback::FindAllReferences => {
17370                    match editor.update_in(cx, |editor, window, cx| {
17371                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17372                    })? {
17373                        Some(references) => references.await,
17374                        None => Ok(Navigated::No),
17375                    }
17376                }
17377            }
17378        })
17379    }
17380
17381    pub fn go_to_declaration(
17382        &mut self,
17383        _: &GoToDeclaration,
17384        window: &mut Window,
17385        cx: &mut Context<Self>,
17386    ) -> Task<Result<Navigated>> {
17387        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17388    }
17389
17390    pub fn go_to_declaration_split(
17391        &mut self,
17392        _: &GoToDeclaration,
17393        window: &mut Window,
17394        cx: &mut Context<Self>,
17395    ) -> Task<Result<Navigated>> {
17396        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17397    }
17398
17399    pub fn go_to_implementation(
17400        &mut self,
17401        _: &GoToImplementation,
17402        window: &mut Window,
17403        cx: &mut Context<Self>,
17404    ) -> Task<Result<Navigated>> {
17405        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17406    }
17407
17408    pub fn go_to_implementation_split(
17409        &mut self,
17410        _: &GoToImplementationSplit,
17411        window: &mut Window,
17412        cx: &mut Context<Self>,
17413    ) -> Task<Result<Navigated>> {
17414        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17415    }
17416
17417    pub fn go_to_type_definition(
17418        &mut self,
17419        _: &GoToTypeDefinition,
17420        window: &mut Window,
17421        cx: &mut Context<Self>,
17422    ) -> Task<Result<Navigated>> {
17423        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17424    }
17425
17426    pub fn go_to_definition_split(
17427        &mut self,
17428        _: &GoToDefinitionSplit,
17429        window: &mut Window,
17430        cx: &mut Context<Self>,
17431    ) -> Task<Result<Navigated>> {
17432        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17433    }
17434
17435    pub fn go_to_type_definition_split(
17436        &mut self,
17437        _: &GoToTypeDefinitionSplit,
17438        window: &mut Window,
17439        cx: &mut Context<Self>,
17440    ) -> Task<Result<Navigated>> {
17441        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17442    }
17443
17444    fn go_to_definition_of_kind(
17445        &mut self,
17446        kind: GotoDefinitionKind,
17447        split: bool,
17448        window: &mut Window,
17449        cx: &mut Context<Self>,
17450    ) -> Task<Result<Navigated>> {
17451        let Some(provider) = self.semantics_provider.clone() else {
17452            return Task::ready(Ok(Navigated::No));
17453        };
17454        let head = self
17455            .selections
17456            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17457            .head();
17458        let buffer = self.buffer.read(cx);
17459        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17460            return Task::ready(Ok(Navigated::No));
17461        };
17462        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17463            return Task::ready(Ok(Navigated::No));
17464        };
17465
17466        cx.spawn_in(window, async move |editor, cx| {
17467            let Some(definitions) = definitions.await? else {
17468                return Ok(Navigated::No);
17469            };
17470            let navigated = editor
17471                .update_in(cx, |editor, window, cx| {
17472                    editor.navigate_to_hover_links(
17473                        Some(kind),
17474                        definitions
17475                            .into_iter()
17476                            .filter(|location| {
17477                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17478                            })
17479                            .map(HoverLink::Text)
17480                            .collect::<Vec<_>>(),
17481                        split,
17482                        window,
17483                        cx,
17484                    )
17485                })?
17486                .await?;
17487            anyhow::Ok(navigated)
17488        })
17489    }
17490
17491    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17492        let selection = self.selections.newest_anchor();
17493        let head = selection.head();
17494        let tail = selection.tail();
17495
17496        let Some((buffer, start_position)) =
17497            self.buffer.read(cx).text_anchor_for_position(head, cx)
17498        else {
17499            return;
17500        };
17501
17502        let end_position = if head != tail {
17503            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17504                return;
17505            };
17506            Some(pos)
17507        } else {
17508            None
17509        };
17510
17511        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17512            let url = if let Some(end_pos) = end_position {
17513                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17514            } else {
17515                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17516            };
17517
17518            if let Some(url) = url {
17519                cx.update(|window, cx| {
17520                    if parse_zed_link(&url, cx).is_some() {
17521                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17522                    } else {
17523                        cx.open_url(&url);
17524                    }
17525                })?;
17526            }
17527
17528            anyhow::Ok(())
17529        });
17530
17531        url_finder.detach();
17532    }
17533
17534    pub fn open_selected_filename(
17535        &mut self,
17536        _: &OpenSelectedFilename,
17537        window: &mut Window,
17538        cx: &mut Context<Self>,
17539    ) {
17540        let Some(workspace) = self.workspace() else {
17541            return;
17542        };
17543
17544        let position = self.selections.newest_anchor().head();
17545
17546        let Some((buffer, buffer_position)) =
17547            self.buffer.read(cx).text_anchor_for_position(position, cx)
17548        else {
17549            return;
17550        };
17551
17552        let project = self.project.clone();
17553
17554        cx.spawn_in(window, async move |_, cx| {
17555            let result = find_file(&buffer, project, buffer_position, cx).await;
17556
17557            if let Some((_, path)) = result {
17558                workspace
17559                    .update_in(cx, |workspace, window, cx| {
17560                        workspace.open_resolved_path(path, window, cx)
17561                    })?
17562                    .await?;
17563            }
17564            anyhow::Ok(())
17565        })
17566        .detach();
17567    }
17568
17569    pub(crate) fn navigate_to_hover_links(
17570        &mut self,
17571        kind: Option<GotoDefinitionKind>,
17572        definitions: Vec<HoverLink>,
17573        split: bool,
17574        window: &mut Window,
17575        cx: &mut Context<Editor>,
17576    ) -> Task<Result<Navigated>> {
17577        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17578        let mut first_url_or_file = None;
17579        let definitions: Vec<_> = definitions
17580            .into_iter()
17581            .filter_map(|def| match def {
17582                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17583                HoverLink::InlayHint(lsp_location, server_id) => {
17584                    let computation =
17585                        self.compute_target_location(lsp_location, server_id, window, cx);
17586                    Some(cx.background_spawn(computation))
17587                }
17588                HoverLink::Url(url) => {
17589                    first_url_or_file = Some(Either::Left(url));
17590                    None
17591                }
17592                HoverLink::File(path) => {
17593                    first_url_or_file = Some(Either::Right(path));
17594                    None
17595                }
17596            })
17597            .collect();
17598
17599        let workspace = self.workspace();
17600
17601        cx.spawn_in(window, async move |editor, cx| {
17602            let locations: Vec<Location> = future::join_all(definitions)
17603                .await
17604                .into_iter()
17605                .filter_map(|location| location.transpose())
17606                .collect::<Result<_>>()
17607                .context("location tasks")?;
17608            let mut locations = cx.update(|_, cx| {
17609                locations
17610                    .into_iter()
17611                    .map(|location| {
17612                        let buffer = location.buffer.read(cx);
17613                        (location.buffer, location.range.to_point(buffer))
17614                    })
17615                    .into_group_map()
17616            })?;
17617            let mut num_locations = 0;
17618            for ranges in locations.values_mut() {
17619                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17620                ranges.dedup();
17621                num_locations += ranges.len();
17622            }
17623
17624            if num_locations > 1 {
17625                let tab_kind = match kind {
17626                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17627                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17628                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17629                    Some(GotoDefinitionKind::Type) => "Types",
17630                };
17631                let title = editor
17632                    .update_in(cx, |_, _, cx| {
17633                        let target = locations
17634                            .iter()
17635                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17636                            .map(|(buffer, location)| {
17637                                buffer
17638                                    .read(cx)
17639                                    .text_for_range(location.clone())
17640                                    .collect::<String>()
17641                            })
17642                            .filter(|text| !text.contains('\n'))
17643                            .unique()
17644                            .take(3)
17645                            .join(", ");
17646                        if target.is_empty() {
17647                            tab_kind.to_owned()
17648                        } else {
17649                            format!("{tab_kind} for {target}")
17650                        }
17651                    })
17652                    .context("buffer title")?;
17653
17654                let Some(workspace) = workspace else {
17655                    return Ok(Navigated::No);
17656                };
17657
17658                let opened = workspace
17659                    .update_in(cx, |workspace, window, cx| {
17660                        let allow_preview = PreviewTabsSettings::get_global(cx)
17661                            .enable_preview_multibuffer_from_code_navigation;
17662                        Self::open_locations_in_multibuffer(
17663                            workspace,
17664                            locations,
17665                            title,
17666                            split,
17667                            allow_preview,
17668                            MultibufferSelectionMode::First,
17669                            window,
17670                            cx,
17671                        )
17672                    })
17673                    .is_ok();
17674
17675                anyhow::Ok(Navigated::from_bool(opened))
17676            } else if num_locations == 0 {
17677                // If there is one url or file, open it directly
17678                match first_url_or_file {
17679                    Some(Either::Left(url)) => {
17680                        cx.update(|window, cx| {
17681                            if parse_zed_link(&url, cx).is_some() {
17682                                window
17683                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17684                            } else {
17685                                cx.open_url(&url);
17686                            }
17687                        })?;
17688                        Ok(Navigated::Yes)
17689                    }
17690                    Some(Either::Right(path)) => {
17691                        // TODO(andrew): respect preview tab settings
17692                        //               `enable_keep_preview_on_code_navigation` and
17693                        //               `enable_preview_file_from_code_navigation`
17694                        let Some(workspace) = workspace else {
17695                            return Ok(Navigated::No);
17696                        };
17697                        workspace
17698                            .update_in(cx, |workspace, window, cx| {
17699                                workspace.open_resolved_path(path, window, cx)
17700                            })?
17701                            .await?;
17702                        Ok(Navigated::Yes)
17703                    }
17704                    None => Ok(Navigated::No),
17705                }
17706            } else {
17707                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17708                let target_range = target_ranges.first().unwrap().clone();
17709
17710                editor.update_in(cx, |editor, window, cx| {
17711                    let range = target_range.to_point(target_buffer.read(cx));
17712                    let range = editor.range_for_match(&range);
17713                    let range = collapse_multiline_range(range);
17714
17715                    if !split
17716                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17717                    {
17718                        editor.go_to_singleton_buffer_range(range, window, cx);
17719                    } else {
17720                        let Some(workspace) = workspace else {
17721                            return Navigated::No;
17722                        };
17723                        let pane = workspace.read(cx).active_pane().clone();
17724                        window.defer(cx, move |window, cx| {
17725                            let target_editor: Entity<Self> =
17726                                workspace.update(cx, |workspace, cx| {
17727                                    let pane = if split {
17728                                        workspace.adjacent_pane(window, cx)
17729                                    } else {
17730                                        workspace.active_pane().clone()
17731                                    };
17732
17733                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17734                                    let keep_old_preview = preview_tabs_settings
17735                                        .enable_keep_preview_on_code_navigation;
17736                                    let allow_new_preview = preview_tabs_settings
17737                                        .enable_preview_file_from_code_navigation;
17738
17739                                    workspace.open_project_item(
17740                                        pane,
17741                                        target_buffer.clone(),
17742                                        true,
17743                                        true,
17744                                        keep_old_preview,
17745                                        allow_new_preview,
17746                                        window,
17747                                        cx,
17748                                    )
17749                                });
17750                            target_editor.update(cx, |target_editor, cx| {
17751                                // When selecting a definition in a different buffer, disable the nav history
17752                                // to avoid creating a history entry at the previous cursor location.
17753                                pane.update(cx, |pane, _| pane.disable_history());
17754                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17755                                pane.update(cx, |pane, _| pane.enable_history());
17756                            });
17757                        });
17758                    }
17759                    Navigated::Yes
17760                })
17761            }
17762        })
17763    }
17764
17765    fn compute_target_location(
17766        &self,
17767        lsp_location: lsp::Location,
17768        server_id: LanguageServerId,
17769        window: &mut Window,
17770        cx: &mut Context<Self>,
17771    ) -> Task<anyhow::Result<Option<Location>>> {
17772        let Some(project) = self.project.clone() else {
17773            return Task::ready(Ok(None));
17774        };
17775
17776        cx.spawn_in(window, async move |editor, cx| {
17777            let location_task = editor.update(cx, |_, cx| {
17778                project.update(cx, |project, cx| {
17779                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17780                })
17781            })?;
17782            let location = Some({
17783                let target_buffer_handle = location_task.await.context("open local buffer")?;
17784                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17785                    let target_start = target_buffer
17786                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17787                    let target_end = target_buffer
17788                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17789                    target_buffer.anchor_after(target_start)
17790                        ..target_buffer.anchor_before(target_end)
17791                });
17792                Location {
17793                    buffer: target_buffer_handle,
17794                    range,
17795                }
17796            });
17797            Ok(location)
17798        })
17799    }
17800
17801    fn go_to_next_reference(
17802        &mut self,
17803        _: &GoToNextReference,
17804        window: &mut Window,
17805        cx: &mut Context<Self>,
17806    ) {
17807        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17808        if let Some(task) = task {
17809            task.detach();
17810        };
17811    }
17812
17813    fn go_to_prev_reference(
17814        &mut self,
17815        _: &GoToPreviousReference,
17816        window: &mut Window,
17817        cx: &mut Context<Self>,
17818    ) {
17819        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17820        if let Some(task) = task {
17821            task.detach();
17822        };
17823    }
17824
17825    pub fn go_to_reference_before_or_after_position(
17826        &mut self,
17827        direction: Direction,
17828        count: usize,
17829        window: &mut Window,
17830        cx: &mut Context<Self>,
17831    ) -> Option<Task<Result<()>>> {
17832        let selection = self.selections.newest_anchor();
17833        let head = selection.head();
17834
17835        let multi_buffer = self.buffer.read(cx);
17836
17837        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17838        let workspace = self.workspace()?;
17839        let project = workspace.read(cx).project().clone();
17840        let references =
17841            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17842        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17843            let Some(locations) = references.await? else {
17844                return Ok(());
17845            };
17846
17847            if locations.is_empty() {
17848                // totally normal - the cursor may be on something which is not
17849                // a symbol (e.g. a keyword)
17850                log::info!("no references found under cursor");
17851                return Ok(());
17852            }
17853
17854            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17855
17856            let (locations, current_location_index) =
17857                multi_buffer.update(cx, |multi_buffer, cx| {
17858                    let mut locations = locations
17859                        .into_iter()
17860                        .filter_map(|loc| {
17861                            let start = multi_buffer.buffer_anchor_to_anchor(
17862                                &loc.buffer,
17863                                loc.range.start,
17864                                cx,
17865                            )?;
17866                            let end = multi_buffer.buffer_anchor_to_anchor(
17867                                &loc.buffer,
17868                                loc.range.end,
17869                                cx,
17870                            )?;
17871                            Some(start..end)
17872                        })
17873                        .collect::<Vec<_>>();
17874
17875                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17876                    // There is an O(n) implementation, but given this list will be
17877                    // small (usually <100 items), the extra O(log(n)) factor isn't
17878                    // worth the (surprisingly large amount of) extra complexity.
17879                    locations
17880                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17881
17882                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17883
17884                    let current_location_index = locations.iter().position(|loc| {
17885                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17886                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17887                    });
17888
17889                    (locations, current_location_index)
17890                });
17891
17892            let Some(current_location_index) = current_location_index else {
17893                // This indicates something has gone wrong, because we already
17894                // handle the "no references" case above
17895                log::error!(
17896                    "failed to find current reference under cursor. Total references: {}",
17897                    locations.len()
17898                );
17899                return Ok(());
17900            };
17901
17902            let destination_location_index = match direction {
17903                Direction::Next => (current_location_index + count) % locations.len(),
17904                Direction::Prev => {
17905                    (current_location_index + locations.len() - count % locations.len())
17906                        % locations.len()
17907                }
17908            };
17909
17910            // TODO(cameron): is this needed?
17911            // the thinking is to avoid "jumping to the current location" (avoid
17912            // polluting "jumplist" in vim terms)
17913            if current_location_index == destination_location_index {
17914                return Ok(());
17915            }
17916
17917            let Range { start, end } = locations[destination_location_index];
17918
17919            editor.update_in(cx, |editor, window, cx| {
17920                let effects = SelectionEffects::default();
17921
17922                editor.unfold_ranges(&[start..end], false, false, cx);
17923                editor.change_selections(effects, window, cx, |s| {
17924                    s.select_ranges([start..start]);
17925                });
17926            })?;
17927
17928            Ok(())
17929        }))
17930    }
17931
17932    pub fn find_all_references(
17933        &mut self,
17934        action: &FindAllReferences,
17935        window: &mut Window,
17936        cx: &mut Context<Self>,
17937    ) -> Option<Task<Result<Navigated>>> {
17938        let always_open_multibuffer = action.always_open_multibuffer;
17939        let selection = self.selections.newest_anchor();
17940        let multi_buffer = self.buffer.read(cx);
17941        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17942        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17943        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17944        let head = selection_offset.head();
17945
17946        let head_anchor = multi_buffer_snapshot.anchor_at(
17947            head,
17948            if head < selection_offset.tail() {
17949                Bias::Right
17950            } else {
17951                Bias::Left
17952            },
17953        );
17954
17955        match self
17956            .find_all_references_task_sources
17957            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17958        {
17959            Ok(_) => {
17960                log::info!(
17961                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17962                );
17963                return None;
17964            }
17965            Err(i) => {
17966                self.find_all_references_task_sources.insert(i, head_anchor);
17967            }
17968        }
17969
17970        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17971        let workspace = self.workspace()?;
17972        let project = workspace.read(cx).project().clone();
17973        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17974        Some(cx.spawn_in(window, async move |editor, cx| {
17975            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17976                if let Ok(i) = editor
17977                    .find_all_references_task_sources
17978                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17979                {
17980                    editor.find_all_references_task_sources.remove(i);
17981                }
17982            });
17983
17984            let Some(locations) = references.await? else {
17985                return anyhow::Ok(Navigated::No);
17986            };
17987            let mut locations = cx.update(|_, cx| {
17988                locations
17989                    .into_iter()
17990                    .map(|location| {
17991                        let buffer = location.buffer.read(cx);
17992                        (location.buffer, location.range.to_point(buffer))
17993                    })
17994                    // if special-casing the single-match case, remove ranges
17995                    // that intersect current selection
17996                    .filter(|(location_buffer, location)| {
17997                        if always_open_multibuffer || &buffer != location_buffer {
17998                            return true;
17999                        }
18000
18001                        !location.contains_inclusive(&selection_point.range())
18002                    })
18003                    .into_group_map()
18004            })?;
18005            if locations.is_empty() {
18006                return anyhow::Ok(Navigated::No);
18007            }
18008            for ranges in locations.values_mut() {
18009                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18010                ranges.dedup();
18011            }
18012            let mut num_locations = 0;
18013            for ranges in locations.values_mut() {
18014                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18015                ranges.dedup();
18016                num_locations += ranges.len();
18017            }
18018
18019            if num_locations == 1 && !always_open_multibuffer {
18020                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18021                let target_range = target_ranges.first().unwrap().clone();
18022
18023                return editor.update_in(cx, |editor, window, cx| {
18024                    let range = target_range.to_point(target_buffer.read(cx));
18025                    let range = editor.range_for_match(&range);
18026                    let range = range.start..range.start;
18027
18028                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18029                        editor.go_to_singleton_buffer_range(range, window, cx);
18030                    } else {
18031                        let pane = workspace.read(cx).active_pane().clone();
18032                        window.defer(cx, move |window, cx| {
18033                            let target_editor: Entity<Self> =
18034                                workspace.update(cx, |workspace, cx| {
18035                                    let pane = workspace.active_pane().clone();
18036
18037                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18038                                    let keep_old_preview = preview_tabs_settings
18039                                        .enable_keep_preview_on_code_navigation;
18040                                    let allow_new_preview = preview_tabs_settings
18041                                        .enable_preview_file_from_code_navigation;
18042
18043                                    workspace.open_project_item(
18044                                        pane,
18045                                        target_buffer.clone(),
18046                                        true,
18047                                        true,
18048                                        keep_old_preview,
18049                                        allow_new_preview,
18050                                        window,
18051                                        cx,
18052                                    )
18053                                });
18054                            target_editor.update(cx, |target_editor, cx| {
18055                                // When selecting a definition in a different buffer, disable the nav history
18056                                // to avoid creating a history entry at the previous cursor location.
18057                                pane.update(cx, |pane, _| pane.disable_history());
18058                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18059                                pane.update(cx, |pane, _| pane.enable_history());
18060                            });
18061                        });
18062                    }
18063                    Navigated::No
18064                });
18065            }
18066
18067            workspace.update_in(cx, |workspace, window, cx| {
18068                let target = locations
18069                    .iter()
18070                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18071                    .map(|(buffer, location)| {
18072                        buffer
18073                            .read(cx)
18074                            .text_for_range(location.clone())
18075                            .collect::<String>()
18076                    })
18077                    .filter(|text| !text.contains('\n'))
18078                    .unique()
18079                    .take(3)
18080                    .join(", ");
18081                let title = if target.is_empty() {
18082                    "References".to_owned()
18083                } else {
18084                    format!("References to {target}")
18085                };
18086                let allow_preview = PreviewTabsSettings::get_global(cx)
18087                    .enable_preview_multibuffer_from_code_navigation;
18088                Self::open_locations_in_multibuffer(
18089                    workspace,
18090                    locations,
18091                    title,
18092                    false,
18093                    allow_preview,
18094                    MultibufferSelectionMode::First,
18095                    window,
18096                    cx,
18097                );
18098                Navigated::Yes
18099            })
18100        }))
18101    }
18102
18103    /// Opens a multibuffer with the given project locations in it.
18104    pub fn open_locations_in_multibuffer(
18105        workspace: &mut Workspace,
18106        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18107        title: String,
18108        split: bool,
18109        allow_preview: bool,
18110        multibuffer_selection_mode: MultibufferSelectionMode,
18111        window: &mut Window,
18112        cx: &mut Context<Workspace>,
18113    ) {
18114        if locations.is_empty() {
18115            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18116            return;
18117        }
18118
18119        let capability = workspace.project().read(cx).capability();
18120        let mut ranges = <Vec<Range<Anchor>>>::new();
18121
18122        // a key to find existing multibuffer editors with the same set of locations
18123        // to prevent us from opening more and more multibuffer tabs for searches and the like
18124        let mut key = (title.clone(), vec![]);
18125        let excerpt_buffer = cx.new(|cx| {
18126            let key = &mut key.1;
18127            let mut multibuffer = MultiBuffer::new(capability);
18128            for (buffer, mut ranges_for_buffer) in locations {
18129                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18130                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18131                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18132                    PathKey::for_buffer(&buffer, cx),
18133                    buffer.clone(),
18134                    ranges_for_buffer,
18135                    multibuffer_context_lines(cx),
18136                    cx,
18137                );
18138                ranges.extend(new_ranges)
18139            }
18140
18141            multibuffer.with_title(title)
18142        });
18143        let existing = workspace.active_pane().update(cx, |pane, cx| {
18144            pane.items()
18145                .filter_map(|item| item.downcast::<Editor>())
18146                .find(|editor| {
18147                    editor
18148                        .read(cx)
18149                        .lookup_key
18150                        .as_ref()
18151                        .and_then(|it| {
18152                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18153                        })
18154                        .is_some_and(|it| *it == key)
18155                })
18156        });
18157        let was_existing = existing.is_some();
18158        let editor = existing.unwrap_or_else(|| {
18159            cx.new(|cx| {
18160                let mut editor = Editor::for_multibuffer(
18161                    excerpt_buffer,
18162                    Some(workspace.project().clone()),
18163                    window,
18164                    cx,
18165                );
18166                editor.lookup_key = Some(Box::new(key));
18167                editor
18168            })
18169        });
18170        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18171            MultibufferSelectionMode::First => {
18172                if let Some(first_range) = ranges.first() {
18173                    editor.change_selections(
18174                        SelectionEffects::no_scroll(),
18175                        window,
18176                        cx,
18177                        |selections| {
18178                            selections.clear_disjoint();
18179                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18180                        },
18181                    );
18182                }
18183                editor.highlight_background::<Self>(
18184                    &ranges,
18185                    |_, theme| theme.colors().editor_highlighted_line_background,
18186                    cx,
18187                );
18188            }
18189            MultibufferSelectionMode::All => {
18190                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18191                    selections.clear_disjoint();
18192                    selections.select_anchor_ranges(ranges);
18193                });
18194            }
18195        });
18196
18197        let item = Box::new(editor);
18198
18199        let pane = if split {
18200            workspace.adjacent_pane(window, cx)
18201        } else {
18202            workspace.active_pane().clone()
18203        };
18204        let activate_pane = split;
18205
18206        let mut destination_index = None;
18207        pane.update(cx, |pane, cx| {
18208            if allow_preview && !was_existing {
18209                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18210            }
18211            if was_existing && !allow_preview {
18212                pane.unpreview_item_if_preview(item.item_id());
18213            }
18214            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18215        });
18216    }
18217
18218    pub fn rename(
18219        &mut self,
18220        _: &Rename,
18221        window: &mut Window,
18222        cx: &mut Context<Self>,
18223    ) -> Option<Task<Result<()>>> {
18224        use language::ToOffset as _;
18225
18226        let provider = self.semantics_provider.clone()?;
18227        let selection = self.selections.newest_anchor().clone();
18228        let (cursor_buffer, cursor_buffer_position) = self
18229            .buffer
18230            .read(cx)
18231            .text_anchor_for_position(selection.head(), cx)?;
18232        let (tail_buffer, cursor_buffer_position_end) = self
18233            .buffer
18234            .read(cx)
18235            .text_anchor_for_position(selection.tail(), cx)?;
18236        if tail_buffer != cursor_buffer {
18237            return None;
18238        }
18239
18240        let snapshot = cursor_buffer.read(cx).snapshot();
18241        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18242        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18243        let prepare_rename = provider
18244            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18245            .unwrap_or_else(|| Task::ready(Ok(None)));
18246        drop(snapshot);
18247
18248        Some(cx.spawn_in(window, async move |this, cx| {
18249            let rename_range = if let Some(range) = prepare_rename.await? {
18250                Some(range)
18251            } else {
18252                this.update(cx, |this, cx| {
18253                    let buffer = this.buffer.read(cx).snapshot(cx);
18254                    let mut buffer_highlights = this
18255                        .document_highlights_for_position(selection.head(), &buffer)
18256                        .filter(|highlight| {
18257                            highlight.start.excerpt_id == selection.head().excerpt_id
18258                                && highlight.end.excerpt_id == selection.head().excerpt_id
18259                        });
18260                    buffer_highlights
18261                        .next()
18262                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18263                })?
18264            };
18265            if let Some(rename_range) = rename_range {
18266                this.update_in(cx, |this, window, cx| {
18267                    let snapshot = cursor_buffer.read(cx).snapshot();
18268                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18269                    let cursor_offset_in_rename_range =
18270                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18271                    let cursor_offset_in_rename_range_end =
18272                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18273
18274                    this.take_rename(false, window, cx);
18275                    let buffer = this.buffer.read(cx).read(cx);
18276                    let cursor_offset = selection.head().to_offset(&buffer);
18277                    let rename_start =
18278                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18279                    let rename_end = rename_start + rename_buffer_range.len();
18280                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18281                    let mut old_highlight_id = None;
18282                    let old_name: Arc<str> = buffer
18283                        .chunks(rename_start..rename_end, true)
18284                        .map(|chunk| {
18285                            if old_highlight_id.is_none() {
18286                                old_highlight_id = chunk.syntax_highlight_id;
18287                            }
18288                            chunk.text
18289                        })
18290                        .collect::<String>()
18291                        .into();
18292
18293                    drop(buffer);
18294
18295                    // Position the selection in the rename editor so that it matches the current selection.
18296                    this.show_local_selections = false;
18297                    let rename_editor = cx.new(|cx| {
18298                        let mut editor = Editor::single_line(window, cx);
18299                        editor.buffer.update(cx, |buffer, cx| {
18300                            buffer.edit(
18301                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18302                                None,
18303                                cx,
18304                            )
18305                        });
18306                        let cursor_offset_in_rename_range =
18307                            MultiBufferOffset(cursor_offset_in_rename_range);
18308                        let cursor_offset_in_rename_range_end =
18309                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18310                        let rename_selection_range = match cursor_offset_in_rename_range
18311                            .cmp(&cursor_offset_in_rename_range_end)
18312                        {
18313                            Ordering::Equal => {
18314                                editor.select_all(&SelectAll, window, cx);
18315                                return editor;
18316                            }
18317                            Ordering::Less => {
18318                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18319                            }
18320                            Ordering::Greater => {
18321                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18322                            }
18323                        };
18324                        if rename_selection_range.end.0 > old_name.len() {
18325                            editor.select_all(&SelectAll, window, cx);
18326                        } else {
18327                            editor.change_selections(Default::default(), window, cx, |s| {
18328                                s.select_ranges([rename_selection_range]);
18329                            });
18330                        }
18331                        editor
18332                    });
18333                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18334                        if e == &EditorEvent::Focused {
18335                            cx.emit(EditorEvent::FocusedIn)
18336                        }
18337                    })
18338                    .detach();
18339
18340                    let write_highlights =
18341                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18342                    let read_highlights =
18343                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18344                    let ranges = write_highlights
18345                        .iter()
18346                        .flat_map(|(_, ranges)| ranges.iter())
18347                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18348                        .cloned()
18349                        .collect();
18350
18351                    this.highlight_text::<Rename>(
18352                        ranges,
18353                        HighlightStyle {
18354                            fade_out: Some(0.6),
18355                            ..Default::default()
18356                        },
18357                        cx,
18358                    );
18359                    let rename_focus_handle = rename_editor.focus_handle(cx);
18360                    window.focus(&rename_focus_handle, cx);
18361                    let block_id = this.insert_blocks(
18362                        [BlockProperties {
18363                            style: BlockStyle::Flex,
18364                            placement: BlockPlacement::Below(range.start),
18365                            height: Some(1),
18366                            render: Arc::new({
18367                                let rename_editor = rename_editor.clone();
18368                                move |cx: &mut BlockContext| {
18369                                    let mut text_style = cx.editor_style.text.clone();
18370                                    if let Some(highlight_style) = old_highlight_id
18371                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18372                                    {
18373                                        text_style = text_style.highlight(highlight_style);
18374                                    }
18375                                    div()
18376                                        .block_mouse_except_scroll()
18377                                        .pl(cx.anchor_x)
18378                                        .child(EditorElement::new(
18379                                            &rename_editor,
18380                                            EditorStyle {
18381                                                background: cx.theme().system().transparent,
18382                                                local_player: cx.editor_style.local_player,
18383                                                text: text_style,
18384                                                scrollbar_width: cx.editor_style.scrollbar_width,
18385                                                syntax: cx.editor_style.syntax.clone(),
18386                                                status: cx.editor_style.status.clone(),
18387                                                inlay_hints_style: HighlightStyle {
18388                                                    font_weight: Some(FontWeight::BOLD),
18389                                                    ..make_inlay_hints_style(cx.app)
18390                                                },
18391                                                edit_prediction_styles: make_suggestion_styles(
18392                                                    cx.app,
18393                                                ),
18394                                                ..EditorStyle::default()
18395                                            },
18396                                        ))
18397                                        .into_any_element()
18398                                }
18399                            }),
18400                            priority: 0,
18401                        }],
18402                        Some(Autoscroll::fit()),
18403                        cx,
18404                    )[0];
18405                    this.pending_rename = Some(RenameState {
18406                        range,
18407                        old_name,
18408                        editor: rename_editor,
18409                        block_id,
18410                    });
18411                })?;
18412            }
18413
18414            Ok(())
18415        }))
18416    }
18417
18418    pub fn confirm_rename(
18419        &mut self,
18420        _: &ConfirmRename,
18421        window: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) -> Option<Task<Result<()>>> {
18424        let rename = self.take_rename(false, window, cx)?;
18425        let workspace = self.workspace()?.downgrade();
18426        let (buffer, start) = self
18427            .buffer
18428            .read(cx)
18429            .text_anchor_for_position(rename.range.start, cx)?;
18430        let (end_buffer, _) = self
18431            .buffer
18432            .read(cx)
18433            .text_anchor_for_position(rename.range.end, cx)?;
18434        if buffer != end_buffer {
18435            return None;
18436        }
18437
18438        let old_name = rename.old_name;
18439        let new_name = rename.editor.read(cx).text(cx);
18440
18441        let rename = self.semantics_provider.as_ref()?.perform_rename(
18442            &buffer,
18443            start,
18444            new_name.clone(),
18445            cx,
18446        )?;
18447
18448        Some(cx.spawn_in(window, async move |editor, cx| {
18449            let project_transaction = rename.await?;
18450            Self::open_project_transaction(
18451                &editor,
18452                workspace,
18453                project_transaction,
18454                format!("Rename: {}{}", old_name, new_name),
18455                cx,
18456            )
18457            .await?;
18458
18459            editor.update(cx, |editor, cx| {
18460                editor.refresh_document_highlights(cx);
18461            })?;
18462            Ok(())
18463        }))
18464    }
18465
18466    fn take_rename(
18467        &mut self,
18468        moving_cursor: bool,
18469        window: &mut Window,
18470        cx: &mut Context<Self>,
18471    ) -> Option<RenameState> {
18472        let rename = self.pending_rename.take()?;
18473        if rename.editor.focus_handle(cx).is_focused(window) {
18474            window.focus(&self.focus_handle, cx);
18475        }
18476
18477        self.remove_blocks(
18478            [rename.block_id].into_iter().collect(),
18479            Some(Autoscroll::fit()),
18480            cx,
18481        );
18482        self.clear_highlights::<Rename>(cx);
18483        self.show_local_selections = true;
18484
18485        if moving_cursor {
18486            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18487                editor
18488                    .selections
18489                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18490                    .head()
18491            });
18492
18493            // Update the selection to match the position of the selection inside
18494            // the rename editor.
18495            let snapshot = self.buffer.read(cx).read(cx);
18496            let rename_range = rename.range.to_offset(&snapshot);
18497            let cursor_in_editor = snapshot
18498                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18499                .min(rename_range.end);
18500            drop(snapshot);
18501
18502            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18503                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18504            });
18505        } else {
18506            self.refresh_document_highlights(cx);
18507        }
18508
18509        Some(rename)
18510    }
18511
18512    pub fn pending_rename(&self) -> Option<&RenameState> {
18513        self.pending_rename.as_ref()
18514    }
18515
18516    fn format(
18517        &mut self,
18518        _: &Format,
18519        window: &mut Window,
18520        cx: &mut Context<Self>,
18521    ) -> Option<Task<Result<()>>> {
18522        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18523
18524        let project = match &self.project {
18525            Some(project) => project.clone(),
18526            None => return None,
18527        };
18528
18529        Some(self.perform_format(
18530            project,
18531            FormatTrigger::Manual,
18532            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18533            window,
18534            cx,
18535        ))
18536    }
18537
18538    fn format_selections(
18539        &mut self,
18540        _: &FormatSelections,
18541        window: &mut Window,
18542        cx: &mut Context<Self>,
18543    ) -> Option<Task<Result<()>>> {
18544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18545
18546        let project = match &self.project {
18547            Some(project) => project.clone(),
18548            None => return None,
18549        };
18550
18551        let ranges = self
18552            .selections
18553            .all_adjusted(&self.display_snapshot(cx))
18554            .into_iter()
18555            .map(|selection| selection.range())
18556            .collect_vec();
18557
18558        Some(self.perform_format(
18559            project,
18560            FormatTrigger::Manual,
18561            FormatTarget::Ranges(ranges),
18562            window,
18563            cx,
18564        ))
18565    }
18566
18567    fn perform_format(
18568        &mut self,
18569        project: Entity<Project>,
18570        trigger: FormatTrigger,
18571        target: FormatTarget,
18572        window: &mut Window,
18573        cx: &mut Context<Self>,
18574    ) -> Task<Result<()>> {
18575        let buffer = self.buffer.clone();
18576        let (buffers, target) = match target {
18577            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18578            FormatTarget::Ranges(selection_ranges) => {
18579                let multi_buffer = buffer.read(cx);
18580                let snapshot = multi_buffer.read(cx);
18581                let mut buffers = HashSet::default();
18582                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18583                    BTreeMap::new();
18584                for selection_range in selection_ranges {
18585                    for (buffer, buffer_range, _) in
18586                        snapshot.range_to_buffer_ranges(selection_range)
18587                    {
18588                        let buffer_id = buffer.remote_id();
18589                        let start = buffer.anchor_before(buffer_range.start);
18590                        let end = buffer.anchor_after(buffer_range.end);
18591                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18592                        buffer_id_to_ranges
18593                            .entry(buffer_id)
18594                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18595                            .or_insert_with(|| vec![start..end]);
18596                    }
18597                }
18598                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18599            }
18600        };
18601
18602        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18603        let selections_prev = transaction_id_prev
18604            .and_then(|transaction_id_prev| {
18605                // default to selections as they were after the last edit, if we have them,
18606                // instead of how they are now.
18607                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18608                // will take you back to where you made the last edit, instead of staying where you scrolled
18609                self.selection_history
18610                    .transaction(transaction_id_prev)
18611                    .map(|t| t.0.clone())
18612            })
18613            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18614
18615        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18616        let format = project.update(cx, |project, cx| {
18617            project.format(buffers, target, true, trigger, cx)
18618        });
18619
18620        cx.spawn_in(window, async move |editor, cx| {
18621            let transaction = futures::select_biased! {
18622                transaction = format.log_err().fuse() => transaction,
18623                () = timeout => {
18624                    log::warn!("timed out waiting for formatting");
18625                    None
18626                }
18627            };
18628
18629            buffer.update(cx, |buffer, cx| {
18630                if let Some(transaction) = transaction
18631                    && !buffer.is_singleton()
18632                {
18633                    buffer.push_transaction(&transaction.0, cx);
18634                }
18635                cx.notify();
18636            });
18637
18638            if let Some(transaction_id_now) =
18639                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18640            {
18641                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18642                if has_new_transaction {
18643                    editor
18644                        .update(cx, |editor, _| {
18645                            editor
18646                                .selection_history
18647                                .insert_transaction(transaction_id_now, selections_prev);
18648                        })
18649                        .ok();
18650                }
18651            }
18652
18653            Ok(())
18654        })
18655    }
18656
18657    fn organize_imports(
18658        &mut self,
18659        _: &OrganizeImports,
18660        window: &mut Window,
18661        cx: &mut Context<Self>,
18662    ) -> Option<Task<Result<()>>> {
18663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18664        let project = match &self.project {
18665            Some(project) => project.clone(),
18666            None => return None,
18667        };
18668        Some(self.perform_code_action_kind(
18669            project,
18670            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18671            window,
18672            cx,
18673        ))
18674    }
18675
18676    fn perform_code_action_kind(
18677        &mut self,
18678        project: Entity<Project>,
18679        kind: CodeActionKind,
18680        window: &mut Window,
18681        cx: &mut Context<Self>,
18682    ) -> Task<Result<()>> {
18683        let buffer = self.buffer.clone();
18684        let buffers = buffer.read(cx).all_buffers();
18685        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18686        let apply_action = project.update(cx, |project, cx| {
18687            project.apply_code_action_kind(buffers, kind, true, cx)
18688        });
18689        cx.spawn_in(window, async move |_, cx| {
18690            let transaction = futures::select_biased! {
18691                () = timeout => {
18692                    log::warn!("timed out waiting for executing code action");
18693                    None
18694                }
18695                transaction = apply_action.log_err().fuse() => transaction,
18696            };
18697            buffer.update(cx, |buffer, cx| {
18698                // check if we need this
18699                if let Some(transaction) = transaction
18700                    && !buffer.is_singleton()
18701                {
18702                    buffer.push_transaction(&transaction.0, cx);
18703                }
18704                cx.notify();
18705            });
18706            Ok(())
18707        })
18708    }
18709
18710    pub fn restart_language_server(
18711        &mut self,
18712        _: &RestartLanguageServer,
18713        _: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) {
18716        if let Some(project) = self.project.clone() {
18717            self.buffer.update(cx, |multi_buffer, cx| {
18718                project.update(cx, |project, cx| {
18719                    project.restart_language_servers_for_buffers(
18720                        multi_buffer.all_buffers().into_iter().collect(),
18721                        HashSet::default(),
18722                        cx,
18723                    );
18724                });
18725            })
18726        }
18727    }
18728
18729    pub fn stop_language_server(
18730        &mut self,
18731        _: &StopLanguageServer,
18732        _: &mut Window,
18733        cx: &mut Context<Self>,
18734    ) {
18735        if let Some(project) = self.project.clone() {
18736            self.buffer.update(cx, |multi_buffer, cx| {
18737                project.update(cx, |project, cx| {
18738                    project.stop_language_servers_for_buffers(
18739                        multi_buffer.all_buffers().into_iter().collect(),
18740                        HashSet::default(),
18741                        cx,
18742                    );
18743                });
18744            });
18745            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18746        }
18747    }
18748
18749    fn cancel_language_server_work(
18750        workspace: &mut Workspace,
18751        _: &actions::CancelLanguageServerWork,
18752        _: &mut Window,
18753        cx: &mut Context<Workspace>,
18754    ) {
18755        let project = workspace.project();
18756        let buffers = workspace
18757            .active_item(cx)
18758            .and_then(|item| item.act_as::<Editor>(cx))
18759            .map_or(HashSet::default(), |editor| {
18760                editor.read(cx).buffer.read(cx).all_buffers()
18761            });
18762        project.update(cx, |project, cx| {
18763            project.cancel_language_server_work_for_buffers(buffers, cx);
18764        });
18765    }
18766
18767    fn show_character_palette(
18768        &mut self,
18769        _: &ShowCharacterPalette,
18770        window: &mut Window,
18771        _: &mut Context<Self>,
18772    ) {
18773        window.show_character_palette();
18774    }
18775
18776    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18777        if !self.diagnostics_enabled() {
18778            return;
18779        }
18780
18781        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18782            let buffer = self.buffer.read(cx).snapshot(cx);
18783            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18784            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18785            let is_valid = buffer
18786                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18787                .any(|entry| {
18788                    entry.diagnostic.is_primary
18789                        && !entry.range.is_empty()
18790                        && entry.range.start == primary_range_start
18791                        && entry.diagnostic.message == active_diagnostics.active_message
18792                });
18793
18794            if !is_valid {
18795                self.dismiss_diagnostics(cx);
18796            }
18797        }
18798    }
18799
18800    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18801        match &self.active_diagnostics {
18802            ActiveDiagnostic::Group(group) => Some(group),
18803            _ => None,
18804        }
18805    }
18806
18807    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18808        if !self.diagnostics_enabled() {
18809            return;
18810        }
18811        self.dismiss_diagnostics(cx);
18812        self.active_diagnostics = ActiveDiagnostic::All;
18813    }
18814
18815    fn activate_diagnostics(
18816        &mut self,
18817        buffer_id: BufferId,
18818        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18819        window: &mut Window,
18820        cx: &mut Context<Self>,
18821    ) {
18822        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18823            return;
18824        }
18825        self.dismiss_diagnostics(cx);
18826        let snapshot = self.snapshot(window, cx);
18827        let buffer = self.buffer.read(cx).snapshot(cx);
18828        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18829            return;
18830        };
18831
18832        let diagnostic_group = buffer
18833            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18834            .collect::<Vec<_>>();
18835
18836        let language_registry = self
18837            .project()
18838            .map(|project| project.read(cx).languages().clone());
18839
18840        let blocks = renderer.render_group(
18841            diagnostic_group,
18842            buffer_id,
18843            snapshot,
18844            cx.weak_entity(),
18845            language_registry,
18846            cx,
18847        );
18848
18849        let blocks = self.display_map.update(cx, |display_map, cx| {
18850            display_map.insert_blocks(blocks, cx).into_iter().collect()
18851        });
18852        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18853            active_range: buffer.anchor_before(diagnostic.range.start)
18854                ..buffer.anchor_after(diagnostic.range.end),
18855            active_message: diagnostic.diagnostic.message.clone(),
18856            group_id: diagnostic.diagnostic.group_id,
18857            blocks,
18858        });
18859        cx.notify();
18860    }
18861
18862    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18863        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18864            return;
18865        };
18866
18867        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18868        if let ActiveDiagnostic::Group(group) = prev {
18869            self.display_map.update(cx, |display_map, cx| {
18870                display_map.remove_blocks(group.blocks, cx);
18871            });
18872            cx.notify();
18873        }
18874    }
18875
18876    /// Disable inline diagnostics rendering for this editor.
18877    pub fn disable_inline_diagnostics(&mut self) {
18878        self.inline_diagnostics_enabled = false;
18879        self.inline_diagnostics_update = Task::ready(());
18880        self.inline_diagnostics.clear();
18881    }
18882
18883    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18884        self.diagnostics_enabled = false;
18885        self.dismiss_diagnostics(cx);
18886        self.inline_diagnostics_update = Task::ready(());
18887        self.inline_diagnostics.clear();
18888    }
18889
18890    pub fn disable_word_completions(&mut self) {
18891        self.word_completions_enabled = false;
18892    }
18893
18894    pub fn diagnostics_enabled(&self) -> bool {
18895        self.diagnostics_enabled && self.mode.is_full()
18896    }
18897
18898    pub fn inline_diagnostics_enabled(&self) -> bool {
18899        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18900    }
18901
18902    pub fn show_inline_diagnostics(&self) -> bool {
18903        self.show_inline_diagnostics
18904    }
18905
18906    pub fn toggle_inline_diagnostics(
18907        &mut self,
18908        _: &ToggleInlineDiagnostics,
18909        window: &mut Window,
18910        cx: &mut Context<Editor>,
18911    ) {
18912        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18913        self.refresh_inline_diagnostics(false, window, cx);
18914    }
18915
18916    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18917        self.diagnostics_max_severity = severity;
18918        self.display_map.update(cx, |display_map, _| {
18919            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18920        });
18921    }
18922
18923    pub fn toggle_diagnostics(
18924        &mut self,
18925        _: &ToggleDiagnostics,
18926        window: &mut Window,
18927        cx: &mut Context<Editor>,
18928    ) {
18929        if !self.diagnostics_enabled() {
18930            return;
18931        }
18932
18933        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18934            EditorSettings::get_global(cx)
18935                .diagnostics_max_severity
18936                .filter(|severity| severity != &DiagnosticSeverity::Off)
18937                .unwrap_or(DiagnosticSeverity::Hint)
18938        } else {
18939            DiagnosticSeverity::Off
18940        };
18941        self.set_max_diagnostics_severity(new_severity, cx);
18942        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18943            self.active_diagnostics = ActiveDiagnostic::None;
18944            self.inline_diagnostics_update = Task::ready(());
18945            self.inline_diagnostics.clear();
18946        } else {
18947            self.refresh_inline_diagnostics(false, window, cx);
18948        }
18949
18950        cx.notify();
18951    }
18952
18953    pub fn toggle_minimap(
18954        &mut self,
18955        _: &ToggleMinimap,
18956        window: &mut Window,
18957        cx: &mut Context<Editor>,
18958    ) {
18959        if self.supports_minimap(cx) {
18960            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18961        }
18962    }
18963
18964    fn refresh_inline_diagnostics(
18965        &mut self,
18966        debounce: bool,
18967        window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        let max_severity = ProjectSettings::get_global(cx)
18971            .diagnostics
18972            .inline
18973            .max_severity
18974            .unwrap_or(self.diagnostics_max_severity);
18975
18976        if !self.inline_diagnostics_enabled()
18977            || !self.diagnostics_enabled()
18978            || !self.show_inline_diagnostics
18979            || max_severity == DiagnosticSeverity::Off
18980        {
18981            self.inline_diagnostics_update = Task::ready(());
18982            self.inline_diagnostics.clear();
18983            return;
18984        }
18985
18986        let debounce_ms = ProjectSettings::get_global(cx)
18987            .diagnostics
18988            .inline
18989            .update_debounce_ms;
18990        let debounce = if debounce && debounce_ms > 0 {
18991            Some(Duration::from_millis(debounce_ms))
18992        } else {
18993            None
18994        };
18995        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18996            if let Some(debounce) = debounce {
18997                cx.background_executor().timer(debounce).await;
18998            }
18999            let Some(snapshot) = editor.upgrade().map(|editor| {
19000                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19001            }) else {
19002                return;
19003            };
19004
19005            let new_inline_diagnostics = cx
19006                .background_spawn(async move {
19007                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19008                    for diagnostic_entry in
19009                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19010                    {
19011                        let message = diagnostic_entry
19012                            .diagnostic
19013                            .message
19014                            .split_once('\n')
19015                            .map(|(line, _)| line)
19016                            .map(SharedString::new)
19017                            .unwrap_or_else(|| {
19018                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19019                            });
19020                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19021                        let (Ok(i) | Err(i)) = inline_diagnostics
19022                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19023                        inline_diagnostics.insert(
19024                            i,
19025                            (
19026                                start_anchor,
19027                                InlineDiagnostic {
19028                                    message,
19029                                    group_id: diagnostic_entry.diagnostic.group_id,
19030                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19031                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19032                                    severity: diagnostic_entry.diagnostic.severity,
19033                                },
19034                            ),
19035                        );
19036                    }
19037                    inline_diagnostics
19038                })
19039                .await;
19040
19041            editor
19042                .update(cx, |editor, cx| {
19043                    editor.inline_diagnostics = new_inline_diagnostics;
19044                    cx.notify();
19045                })
19046                .ok();
19047        });
19048    }
19049
19050    fn pull_diagnostics(
19051        &mut self,
19052        buffer_id: Option<BufferId>,
19053        window: &Window,
19054        cx: &mut Context<Self>,
19055    ) -> Option<()> {
19056        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
19057            return None;
19058        }
19059        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19060            .diagnostics
19061            .lsp_pull_diagnostics;
19062        if !pull_diagnostics_settings.enabled {
19063            return None;
19064        }
19065        let project = self.project()?.downgrade();
19066
19067        let mut edited_buffer_ids = HashSet::default();
19068        let mut edited_worktree_ids = HashSet::default();
19069        let edited_buffers = match buffer_id {
19070            Some(buffer_id) => {
19071                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19072                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
19073                edited_buffer_ids.insert(buffer.read(cx).remote_id());
19074                edited_worktree_ids.insert(worktree_id);
19075                vec![buffer]
19076            }
19077            None => self
19078                .buffer()
19079                .read(cx)
19080                .all_buffers()
19081                .into_iter()
19082                .filter(|buffer| {
19083                    let buffer = buffer.read(cx);
19084                    match buffer.file().map(|f| f.worktree_id(cx)) {
19085                        Some(worktree_id) => {
19086                            edited_buffer_ids.insert(buffer.remote_id());
19087                            edited_worktree_ids.insert(worktree_id);
19088                            true
19089                        }
19090                        None => false,
19091                    }
19092                })
19093                .collect::<Vec<_>>(),
19094        };
19095
19096        if edited_buffers.is_empty() {
19097            self.pull_diagnostics_task = Task::ready(());
19098            self.pull_diagnostics_background_task = Task::ready(());
19099            return None;
19100        }
19101
19102        let mut already_used_buffers = HashSet::default();
19103        let related_open_buffers = self
19104            .workspace
19105            .as_ref()
19106            .and_then(|(workspace, _)| workspace.upgrade())
19107            .into_iter()
19108            .flat_map(|workspace| workspace.read(cx).panes())
19109            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
19110            .filter(|editor| editor != &cx.entity())
19111            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
19112            .filter(|buffer| {
19113                let buffer = buffer.read(cx);
19114                let buffer_id = buffer.remote_id();
19115                if already_used_buffers.insert(buffer_id) {
19116                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
19117                        return !edited_buffer_ids.contains(&buffer_id)
19118                            && edited_worktree_ids.contains(&worktree_id);
19119                    }
19120                }
19121                false
19122            })
19123            .collect::<Vec<_>>();
19124
19125        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19126        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
19127            if buffers.is_empty() {
19128                return Task::ready(());
19129            }
19130            let project_weak = project.clone();
19131            cx.spawn_in(window, async move |_, cx| {
19132                cx.background_executor().timer(delay).await;
19133
19134                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
19135                    buffers
19136                        .into_iter()
19137                        .filter_map(|buffer| {
19138                            project_weak
19139                                .update(cx, |project, cx| {
19140                                    project.lsp_store().update(cx, |lsp_store, cx| {
19141                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19142                                    })
19143                                })
19144                                .ok()
19145                        })
19146                        .collect::<FuturesUnordered<_>>()
19147                }) else {
19148                    return;
19149                };
19150
19151                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
19152                    if let Err(e) = pull_task {
19153                        log::error!("Failed to update project diagnostics: {e:#}");
19154                    }
19155                }
19156            })
19157        };
19158
19159        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
19160        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
19161
19162        Some(())
19163    }
19164
19165    pub fn set_selections_from_remote(
19166        &mut self,
19167        selections: Vec<Selection<Anchor>>,
19168        pending_selection: Option<Selection<Anchor>>,
19169        window: &mut Window,
19170        cx: &mut Context<Self>,
19171    ) {
19172        let old_cursor_position = self.selections.newest_anchor().head();
19173        self.selections
19174            .change_with(&self.display_snapshot(cx), |s| {
19175                s.select_anchors(selections);
19176                if let Some(pending_selection) = pending_selection {
19177                    s.set_pending(pending_selection, SelectMode::Character);
19178                } else {
19179                    s.clear_pending();
19180                }
19181            });
19182        self.selections_did_change(
19183            false,
19184            &old_cursor_position,
19185            SelectionEffects::default(),
19186            window,
19187            cx,
19188        );
19189    }
19190
19191    pub fn transact(
19192        &mut self,
19193        window: &mut Window,
19194        cx: &mut Context<Self>,
19195        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19196    ) -> Option<TransactionId> {
19197        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19198            this.start_transaction_at(Instant::now(), window, cx);
19199            update(this, window, cx);
19200            this.end_transaction_at(Instant::now(), cx)
19201        })
19202    }
19203
19204    pub fn start_transaction_at(
19205        &mut self,
19206        now: Instant,
19207        window: &mut Window,
19208        cx: &mut Context<Self>,
19209    ) -> Option<TransactionId> {
19210        self.end_selection(window, cx);
19211        if let Some(tx_id) = self
19212            .buffer
19213            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19214        {
19215            self.selection_history
19216                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19217            cx.emit(EditorEvent::TransactionBegun {
19218                transaction_id: tx_id,
19219            });
19220            Some(tx_id)
19221        } else {
19222            None
19223        }
19224    }
19225
19226    pub fn end_transaction_at(
19227        &mut self,
19228        now: Instant,
19229        cx: &mut Context<Self>,
19230    ) -> Option<TransactionId> {
19231        if let Some(transaction_id) = self
19232            .buffer
19233            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19234        {
19235            if let Some((_, end_selections)) =
19236                self.selection_history.transaction_mut(transaction_id)
19237            {
19238                *end_selections = Some(self.selections.disjoint_anchors_arc());
19239            } else {
19240                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19241            }
19242
19243            cx.emit(EditorEvent::Edited { transaction_id });
19244            Some(transaction_id)
19245        } else {
19246            None
19247        }
19248    }
19249
19250    pub fn modify_transaction_selection_history(
19251        &mut self,
19252        transaction_id: TransactionId,
19253        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19254    ) -> bool {
19255        self.selection_history
19256            .transaction_mut(transaction_id)
19257            .map(modify)
19258            .is_some()
19259    }
19260
19261    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19262        if self.selection_mark_mode {
19263            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19264                s.move_with(|_, sel| {
19265                    sel.collapse_to(sel.head(), SelectionGoal::None);
19266                });
19267            })
19268        }
19269        self.selection_mark_mode = true;
19270        cx.notify();
19271    }
19272
19273    pub fn swap_selection_ends(
19274        &mut self,
19275        _: &actions::SwapSelectionEnds,
19276        window: &mut Window,
19277        cx: &mut Context<Self>,
19278    ) {
19279        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19280            s.move_with(|_, sel| {
19281                if sel.start != sel.end {
19282                    sel.reversed = !sel.reversed
19283                }
19284            });
19285        });
19286        self.request_autoscroll(Autoscroll::newest(), cx);
19287        cx.notify();
19288    }
19289
19290    pub fn toggle_focus(
19291        workspace: &mut Workspace,
19292        _: &actions::ToggleFocus,
19293        window: &mut Window,
19294        cx: &mut Context<Workspace>,
19295    ) {
19296        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19297            return;
19298        };
19299        workspace.activate_item(&item, true, true, window, cx);
19300    }
19301
19302    pub fn toggle_fold(
19303        &mut self,
19304        _: &actions::ToggleFold,
19305        window: &mut Window,
19306        cx: &mut Context<Self>,
19307    ) {
19308        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19309            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19310            let selection = self.selections.newest::<Point>(&display_map);
19311
19312            let range = if selection.is_empty() {
19313                let point = selection.head().to_display_point(&display_map);
19314                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19315                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19316                    .to_point(&display_map);
19317                start..end
19318            } else {
19319                selection.range()
19320            };
19321            if display_map.folds_in_range(range).next().is_some() {
19322                self.unfold_lines(&Default::default(), window, cx)
19323            } else {
19324                self.fold(&Default::default(), window, cx)
19325            }
19326        } else {
19327            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19328            let buffer_ids: HashSet<_> = self
19329                .selections
19330                .disjoint_anchor_ranges()
19331                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19332                .collect();
19333
19334            let should_unfold = buffer_ids
19335                .iter()
19336                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19337
19338            for buffer_id in buffer_ids {
19339                if should_unfold {
19340                    self.unfold_buffer(buffer_id, cx);
19341                } else {
19342                    self.fold_buffer(buffer_id, cx);
19343                }
19344            }
19345        }
19346    }
19347
19348    pub fn toggle_fold_recursive(
19349        &mut self,
19350        _: &actions::ToggleFoldRecursive,
19351        window: &mut Window,
19352        cx: &mut Context<Self>,
19353    ) {
19354        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19355
19356        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19357        let range = if selection.is_empty() {
19358            let point = selection.head().to_display_point(&display_map);
19359            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19360            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19361                .to_point(&display_map);
19362            start..end
19363        } else {
19364            selection.range()
19365        };
19366        if display_map.folds_in_range(range).next().is_some() {
19367            self.unfold_recursive(&Default::default(), window, cx)
19368        } else {
19369            self.fold_recursive(&Default::default(), window, cx)
19370        }
19371    }
19372
19373    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19374        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19375            let mut to_fold = Vec::new();
19376            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19377            let selections = self.selections.all_adjusted(&display_map);
19378
19379            for selection in selections {
19380                let range = selection.range().sorted();
19381                let buffer_start_row = range.start.row;
19382
19383                if range.start.row != range.end.row {
19384                    let mut found = false;
19385                    let mut row = range.start.row;
19386                    while row <= range.end.row {
19387                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19388                        {
19389                            found = true;
19390                            row = crease.range().end.row + 1;
19391                            to_fold.push(crease);
19392                        } else {
19393                            row += 1
19394                        }
19395                    }
19396                    if found {
19397                        continue;
19398                    }
19399                }
19400
19401                for row in (0..=range.start.row).rev() {
19402                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19403                        && crease.range().end.row >= buffer_start_row
19404                    {
19405                        to_fold.push(crease);
19406                        if row <= range.start.row {
19407                            break;
19408                        }
19409                    }
19410                }
19411            }
19412
19413            self.fold_creases(to_fold, true, window, cx);
19414        } else {
19415            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19416            let buffer_ids = self
19417                .selections
19418                .disjoint_anchor_ranges()
19419                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19420                .collect::<HashSet<_>>();
19421            for buffer_id in buffer_ids {
19422                self.fold_buffer(buffer_id, cx);
19423            }
19424        }
19425    }
19426
19427    pub fn toggle_fold_all(
19428        &mut self,
19429        _: &actions::ToggleFoldAll,
19430        window: &mut Window,
19431        cx: &mut Context<Self>,
19432    ) {
19433        let has_folds = if self.buffer.read(cx).is_singleton() {
19434            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19435            let has_folds = display_map
19436                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19437                .next()
19438                .is_some();
19439            has_folds
19440        } else {
19441            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19442            let has_folds = buffer_ids
19443                .iter()
19444                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19445            has_folds
19446        };
19447
19448        if has_folds {
19449            self.unfold_all(&actions::UnfoldAll, window, cx);
19450        } else {
19451            self.fold_all(&actions::FoldAll, window, cx);
19452        }
19453    }
19454
19455    fn fold_at_level(
19456        &mut self,
19457        fold_at: &FoldAtLevel,
19458        window: &mut Window,
19459        cx: &mut Context<Self>,
19460    ) {
19461        if !self.buffer.read(cx).is_singleton() {
19462            return;
19463        }
19464
19465        let fold_at_level = fold_at.0;
19466        let snapshot = self.buffer.read(cx).snapshot(cx);
19467        let mut to_fold = Vec::new();
19468        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19469
19470        let row_ranges_to_keep: Vec<Range<u32>> = self
19471            .selections
19472            .all::<Point>(&self.display_snapshot(cx))
19473            .into_iter()
19474            .map(|sel| sel.start.row..sel.end.row)
19475            .collect();
19476
19477        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19478            while start_row < end_row {
19479                match self
19480                    .snapshot(window, cx)
19481                    .crease_for_buffer_row(MultiBufferRow(start_row))
19482                {
19483                    Some(crease) => {
19484                        let nested_start_row = crease.range().start.row + 1;
19485                        let nested_end_row = crease.range().end.row;
19486
19487                        if current_level < fold_at_level {
19488                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19489                        } else if current_level == fold_at_level {
19490                            // Fold iff there is no selection completely contained within the fold region
19491                            if !row_ranges_to_keep.iter().any(|selection| {
19492                                selection.end >= nested_start_row
19493                                    && selection.start <= nested_end_row
19494                            }) {
19495                                to_fold.push(crease);
19496                            }
19497                        }
19498
19499                        start_row = nested_end_row + 1;
19500                    }
19501                    None => start_row += 1,
19502                }
19503            }
19504        }
19505
19506        self.fold_creases(to_fold, true, window, cx);
19507    }
19508
19509    pub fn fold_at_level_1(
19510        &mut self,
19511        _: &actions::FoldAtLevel1,
19512        window: &mut Window,
19513        cx: &mut Context<Self>,
19514    ) {
19515        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19516    }
19517
19518    pub fn fold_at_level_2(
19519        &mut self,
19520        _: &actions::FoldAtLevel2,
19521        window: &mut Window,
19522        cx: &mut Context<Self>,
19523    ) {
19524        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19525    }
19526
19527    pub fn fold_at_level_3(
19528        &mut self,
19529        _: &actions::FoldAtLevel3,
19530        window: &mut Window,
19531        cx: &mut Context<Self>,
19532    ) {
19533        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19534    }
19535
19536    pub fn fold_at_level_4(
19537        &mut self,
19538        _: &actions::FoldAtLevel4,
19539        window: &mut Window,
19540        cx: &mut Context<Self>,
19541    ) {
19542        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19543    }
19544
19545    pub fn fold_at_level_5(
19546        &mut self,
19547        _: &actions::FoldAtLevel5,
19548        window: &mut Window,
19549        cx: &mut Context<Self>,
19550    ) {
19551        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19552    }
19553
19554    pub fn fold_at_level_6(
19555        &mut self,
19556        _: &actions::FoldAtLevel6,
19557        window: &mut Window,
19558        cx: &mut Context<Self>,
19559    ) {
19560        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19561    }
19562
19563    pub fn fold_at_level_7(
19564        &mut self,
19565        _: &actions::FoldAtLevel7,
19566        window: &mut Window,
19567        cx: &mut Context<Self>,
19568    ) {
19569        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19570    }
19571
19572    pub fn fold_at_level_8(
19573        &mut self,
19574        _: &actions::FoldAtLevel8,
19575        window: &mut Window,
19576        cx: &mut Context<Self>,
19577    ) {
19578        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19579    }
19580
19581    pub fn fold_at_level_9(
19582        &mut self,
19583        _: &actions::FoldAtLevel9,
19584        window: &mut Window,
19585        cx: &mut Context<Self>,
19586    ) {
19587        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19588    }
19589
19590    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19591        if self.buffer.read(cx).is_singleton() {
19592            let mut fold_ranges = Vec::new();
19593            let snapshot = self.buffer.read(cx).snapshot(cx);
19594
19595            for row in 0..snapshot.max_row().0 {
19596                if let Some(foldable_range) = self
19597                    .snapshot(window, cx)
19598                    .crease_for_buffer_row(MultiBufferRow(row))
19599                {
19600                    fold_ranges.push(foldable_range);
19601                }
19602            }
19603
19604            self.fold_creases(fold_ranges, true, window, cx);
19605        } else {
19606            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19607                editor
19608                    .update_in(cx, |editor, _, cx| {
19609                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19610                            editor.fold_buffer(buffer_id, cx);
19611                        }
19612                    })
19613                    .ok();
19614            });
19615        }
19616        cx.emit(SearchEvent::ResultsCollapsedChanged(
19617            CollapseDirection::Collapsed,
19618        ));
19619    }
19620
19621    pub fn fold_function_bodies(
19622        &mut self,
19623        _: &actions::FoldFunctionBodies,
19624        window: &mut Window,
19625        cx: &mut Context<Self>,
19626    ) {
19627        let snapshot = self.buffer.read(cx).snapshot(cx);
19628
19629        let ranges = snapshot
19630            .text_object_ranges(
19631                MultiBufferOffset(0)..snapshot.len(),
19632                TreeSitterOptions::default(),
19633            )
19634            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19635            .collect::<Vec<_>>();
19636
19637        let creases = ranges
19638            .into_iter()
19639            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19640            .collect();
19641
19642        self.fold_creases(creases, true, window, cx);
19643    }
19644
19645    pub fn fold_recursive(
19646        &mut self,
19647        _: &actions::FoldRecursive,
19648        window: &mut Window,
19649        cx: &mut Context<Self>,
19650    ) {
19651        let mut to_fold = Vec::new();
19652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19653        let selections = self.selections.all_adjusted(&display_map);
19654
19655        for selection in selections {
19656            let range = selection.range().sorted();
19657            let buffer_start_row = range.start.row;
19658
19659            if range.start.row != range.end.row {
19660                let mut found = false;
19661                for row in range.start.row..=range.end.row {
19662                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19663                        found = true;
19664                        to_fold.push(crease);
19665                    }
19666                }
19667                if found {
19668                    continue;
19669                }
19670            }
19671
19672            for row in (0..=range.start.row).rev() {
19673                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19674                    if crease.range().end.row >= buffer_start_row {
19675                        to_fold.push(crease);
19676                    } else {
19677                        break;
19678                    }
19679                }
19680            }
19681        }
19682
19683        self.fold_creases(to_fold, true, window, cx);
19684    }
19685
19686    pub fn fold_at(
19687        &mut self,
19688        buffer_row: MultiBufferRow,
19689        window: &mut Window,
19690        cx: &mut Context<Self>,
19691    ) {
19692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19693
19694        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19695            let autoscroll = self
19696                .selections
19697                .all::<Point>(&display_map)
19698                .iter()
19699                .any(|selection| crease.range().overlaps(&selection.range()));
19700
19701            self.fold_creases(vec![crease], autoscroll, window, cx);
19702        }
19703    }
19704
19705    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19706        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19707            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19708            let buffer = display_map.buffer_snapshot();
19709            let selections = self.selections.all::<Point>(&display_map);
19710            let ranges = selections
19711                .iter()
19712                .map(|s| {
19713                    let range = s.display_range(&display_map).sorted();
19714                    let mut start = range.start.to_point(&display_map);
19715                    let mut end = range.end.to_point(&display_map);
19716                    start.column = 0;
19717                    end.column = buffer.line_len(MultiBufferRow(end.row));
19718                    start..end
19719                })
19720                .collect::<Vec<_>>();
19721
19722            self.unfold_ranges(&ranges, true, true, cx);
19723        } else {
19724            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19725            let buffer_ids = self
19726                .selections
19727                .disjoint_anchor_ranges()
19728                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19729                .collect::<HashSet<_>>();
19730            for buffer_id in buffer_ids {
19731                self.unfold_buffer(buffer_id, cx);
19732            }
19733        }
19734    }
19735
19736    pub fn unfold_recursive(
19737        &mut self,
19738        _: &UnfoldRecursive,
19739        _window: &mut Window,
19740        cx: &mut Context<Self>,
19741    ) {
19742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19743        let selections = self.selections.all::<Point>(&display_map);
19744        let ranges = selections
19745            .iter()
19746            .map(|s| {
19747                let mut range = s.display_range(&display_map).sorted();
19748                *range.start.column_mut() = 0;
19749                *range.end.column_mut() = display_map.line_len(range.end.row());
19750                let start = range.start.to_point(&display_map);
19751                let end = range.end.to_point(&display_map);
19752                start..end
19753            })
19754            .collect::<Vec<_>>();
19755
19756        self.unfold_ranges(&ranges, true, true, cx);
19757    }
19758
19759    pub fn unfold_at(
19760        &mut self,
19761        buffer_row: MultiBufferRow,
19762        _window: &mut Window,
19763        cx: &mut Context<Self>,
19764    ) {
19765        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19766
19767        let intersection_range = Point::new(buffer_row.0, 0)
19768            ..Point::new(
19769                buffer_row.0,
19770                display_map.buffer_snapshot().line_len(buffer_row),
19771            );
19772
19773        let autoscroll = self
19774            .selections
19775            .all::<Point>(&display_map)
19776            .iter()
19777            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19778
19779        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19780    }
19781
19782    pub fn unfold_all(
19783        &mut self,
19784        _: &actions::UnfoldAll,
19785        _window: &mut Window,
19786        cx: &mut Context<Self>,
19787    ) {
19788        if self.buffer.read(cx).is_singleton() {
19789            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19790            self.unfold_ranges(
19791                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19792                true,
19793                true,
19794                cx,
19795            );
19796        } else {
19797            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19798                editor
19799                    .update(cx, |editor, cx| {
19800                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19801                            editor.unfold_buffer(buffer_id, cx);
19802                        }
19803                    })
19804                    .ok();
19805            });
19806        }
19807        cx.emit(SearchEvent::ResultsCollapsedChanged(
19808            CollapseDirection::Expanded,
19809        ));
19810    }
19811
19812    pub fn fold_selected_ranges(
19813        &mut self,
19814        _: &FoldSelectedRanges,
19815        window: &mut Window,
19816        cx: &mut Context<Self>,
19817    ) {
19818        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19819        let selections = self.selections.all_adjusted(&display_map);
19820        let ranges = selections
19821            .into_iter()
19822            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19823            .collect::<Vec<_>>();
19824        self.fold_creases(ranges, true, window, cx);
19825    }
19826
19827    pub fn fold_ranges<T: ToOffset + Clone>(
19828        &mut self,
19829        ranges: Vec<Range<T>>,
19830        auto_scroll: bool,
19831        window: &mut Window,
19832        cx: &mut Context<Self>,
19833    ) {
19834        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19835        let ranges = ranges
19836            .into_iter()
19837            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19838            .collect::<Vec<_>>();
19839        self.fold_creases(ranges, auto_scroll, window, cx);
19840    }
19841
19842    pub fn fold_creases<T: ToOffset + Clone>(
19843        &mut self,
19844        creases: Vec<Crease<T>>,
19845        auto_scroll: bool,
19846        _window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        if creases.is_empty() {
19850            return;
19851        }
19852
19853        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19854
19855        if auto_scroll {
19856            self.request_autoscroll(Autoscroll::fit(), cx);
19857        }
19858
19859        cx.notify();
19860
19861        self.scrollbar_marker_state.dirty = true;
19862        self.folds_did_change(cx);
19863    }
19864
19865    /// Removes any folds whose ranges intersect any of the given ranges.
19866    pub fn unfold_ranges<T: ToOffset + Clone>(
19867        &mut self,
19868        ranges: &[Range<T>],
19869        inclusive: bool,
19870        auto_scroll: bool,
19871        cx: &mut Context<Self>,
19872    ) {
19873        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19874            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19875        });
19876        self.folds_did_change(cx);
19877    }
19878
19879    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19880        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19881            return;
19882        }
19883
19884        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19885        self.display_map.update(cx, |display_map, cx| {
19886            display_map.fold_buffers([buffer_id], cx)
19887        });
19888
19889        let snapshot = self.display_snapshot(cx);
19890        self.selections.change_with(&snapshot, |selections| {
19891            selections.remove_selections_from_buffer(buffer_id);
19892        });
19893
19894        cx.emit(EditorEvent::BufferFoldToggled {
19895            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19896            folded: true,
19897        });
19898        cx.notify();
19899    }
19900
19901    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19902        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19903            return;
19904        }
19905        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19906        self.display_map.update(cx, |display_map, cx| {
19907            display_map.unfold_buffers([buffer_id], cx);
19908        });
19909        cx.emit(EditorEvent::BufferFoldToggled {
19910            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19911            folded: false,
19912        });
19913        cx.notify();
19914    }
19915
19916    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19917        self.display_map.read(cx).is_buffer_folded(buffer)
19918    }
19919
19920    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19921        self.display_map.read(cx).folded_buffers()
19922    }
19923
19924    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19925        self.display_map.update(cx, |display_map, cx| {
19926            display_map.disable_header_for_buffer(buffer_id, cx);
19927        });
19928        cx.notify();
19929    }
19930
19931    /// Removes any folds with the given ranges.
19932    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19933        &mut self,
19934        ranges: &[Range<T>],
19935        type_id: TypeId,
19936        auto_scroll: bool,
19937        cx: &mut Context<Self>,
19938    ) {
19939        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19940            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19941        });
19942        self.folds_did_change(cx);
19943    }
19944
19945    fn remove_folds_with<T: ToOffset + Clone>(
19946        &mut self,
19947        ranges: &[Range<T>],
19948        auto_scroll: bool,
19949        cx: &mut Context<Self>,
19950        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19951    ) {
19952        if ranges.is_empty() {
19953            return;
19954        }
19955
19956        let mut buffers_affected = HashSet::default();
19957        let multi_buffer = self.buffer().read(cx);
19958        for range in ranges {
19959            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19960                buffers_affected.insert(buffer.read(cx).remote_id());
19961            };
19962        }
19963
19964        self.display_map.update(cx, update);
19965
19966        if auto_scroll {
19967            self.request_autoscroll(Autoscroll::fit(), cx);
19968        }
19969
19970        cx.notify();
19971        self.scrollbar_marker_state.dirty = true;
19972        self.active_indent_guides_state.dirty = true;
19973    }
19974
19975    pub fn update_renderer_widths(
19976        &mut self,
19977        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19978        cx: &mut Context<Self>,
19979    ) -> bool {
19980        self.display_map
19981            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19982    }
19983
19984    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19985        self.display_map.read(cx).fold_placeholder.clone()
19986    }
19987
19988    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19989        self.buffer.update(cx, |buffer, cx| {
19990            buffer.set_all_diff_hunks_expanded(cx);
19991        });
19992    }
19993
19994    pub fn expand_all_diff_hunks(
19995        &mut self,
19996        _: &ExpandAllDiffHunks,
19997        _window: &mut Window,
19998        cx: &mut Context<Self>,
19999    ) {
20000        self.buffer.update(cx, |buffer, cx| {
20001            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20002        });
20003    }
20004
20005    pub fn collapse_all_diff_hunks(
20006        &mut self,
20007        _: &CollapseAllDiffHunks,
20008        _window: &mut Window,
20009        cx: &mut Context<Self>,
20010    ) {
20011        self.buffer.update(cx, |buffer, cx| {
20012            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20013        });
20014    }
20015
20016    pub fn toggle_selected_diff_hunks(
20017        &mut self,
20018        _: &ToggleSelectedDiffHunks,
20019        _window: &mut Window,
20020        cx: &mut Context<Self>,
20021    ) {
20022        let ranges: Vec<_> = self
20023            .selections
20024            .disjoint_anchors()
20025            .iter()
20026            .map(|s| s.range())
20027            .collect();
20028        self.toggle_diff_hunks_in_ranges(ranges, cx);
20029    }
20030
20031    pub fn diff_hunks_in_ranges<'a>(
20032        &'a self,
20033        ranges: &'a [Range<Anchor>],
20034        buffer: &'a MultiBufferSnapshot,
20035    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20036        ranges.iter().flat_map(move |range| {
20037            let end_excerpt_id = range.end.excerpt_id;
20038            let range = range.to_point(buffer);
20039            let mut peek_end = range.end;
20040            if range.end.row < buffer.max_row().0 {
20041                peek_end = Point::new(range.end.row + 1, 0);
20042            }
20043            buffer
20044                .diff_hunks_in_range(range.start..peek_end)
20045                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20046        })
20047    }
20048
20049    pub fn has_stageable_diff_hunks_in_ranges(
20050        &self,
20051        ranges: &[Range<Anchor>],
20052        snapshot: &MultiBufferSnapshot,
20053    ) -> bool {
20054        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20055        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20056    }
20057
20058    pub fn toggle_staged_selected_diff_hunks(
20059        &mut self,
20060        _: &::git::ToggleStaged,
20061        _: &mut Window,
20062        cx: &mut Context<Self>,
20063    ) {
20064        let snapshot = self.buffer.read(cx).snapshot(cx);
20065        let ranges: Vec<_> = self
20066            .selections
20067            .disjoint_anchors()
20068            .iter()
20069            .map(|s| s.range())
20070            .collect();
20071        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20072        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20073    }
20074
20075    pub fn set_render_diff_hunk_controls(
20076        &mut self,
20077        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20078        cx: &mut Context<Self>,
20079    ) {
20080        self.render_diff_hunk_controls = render_diff_hunk_controls;
20081        cx.notify();
20082    }
20083
20084    pub fn stage_and_next(
20085        &mut self,
20086        _: &::git::StageAndNext,
20087        window: &mut Window,
20088        cx: &mut Context<Self>,
20089    ) {
20090        self.do_stage_or_unstage_and_next(true, window, cx);
20091    }
20092
20093    pub fn unstage_and_next(
20094        &mut self,
20095        _: &::git::UnstageAndNext,
20096        window: &mut Window,
20097        cx: &mut Context<Self>,
20098    ) {
20099        self.do_stage_or_unstage_and_next(false, window, cx);
20100    }
20101
20102    pub fn stage_or_unstage_diff_hunks(
20103        &mut self,
20104        stage: bool,
20105        ranges: Vec<Range<Anchor>>,
20106        cx: &mut Context<Self>,
20107    ) {
20108        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20109        cx.spawn(async move |this, cx| {
20110            task.await?;
20111            this.update(cx, |this, cx| {
20112                let snapshot = this.buffer.read(cx).snapshot(cx);
20113                let chunk_by = this
20114                    .diff_hunks_in_ranges(&ranges, &snapshot)
20115                    .chunk_by(|hunk| hunk.buffer_id);
20116                for (buffer_id, hunks) in &chunk_by {
20117                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20118                }
20119            })
20120        })
20121        .detach_and_log_err(cx);
20122    }
20123
20124    fn save_buffers_for_ranges_if_needed(
20125        &mut self,
20126        ranges: &[Range<Anchor>],
20127        cx: &mut Context<Editor>,
20128    ) -> Task<Result<()>> {
20129        let multibuffer = self.buffer.read(cx);
20130        let snapshot = multibuffer.read(cx);
20131        let buffer_ids: HashSet<_> = ranges
20132            .iter()
20133            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20134            .collect();
20135        drop(snapshot);
20136
20137        let mut buffers = HashSet::default();
20138        for buffer_id in buffer_ids {
20139            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20140                let buffer = buffer_entity.read(cx);
20141                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20142                {
20143                    buffers.insert(buffer_entity);
20144                }
20145            }
20146        }
20147
20148        if let Some(project) = &self.project {
20149            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20150        } else {
20151            Task::ready(Ok(()))
20152        }
20153    }
20154
20155    fn do_stage_or_unstage_and_next(
20156        &mut self,
20157        stage: bool,
20158        window: &mut Window,
20159        cx: &mut Context<Self>,
20160    ) {
20161        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20162
20163        if ranges.iter().any(|range| range.start != range.end) {
20164            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20165            return;
20166        }
20167
20168        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20169        let snapshot = self.snapshot(window, cx);
20170        let position = self
20171            .selections
20172            .newest::<Point>(&snapshot.display_snapshot)
20173            .head();
20174        let mut row = snapshot
20175            .buffer_snapshot()
20176            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20177            .find(|hunk| hunk.row_range.start.0 > position.row)
20178            .map(|hunk| hunk.row_range.start);
20179
20180        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20181        // Outside of the project diff editor, wrap around to the beginning.
20182        if !all_diff_hunks_expanded {
20183            row = row.or_else(|| {
20184                snapshot
20185                    .buffer_snapshot()
20186                    .diff_hunks_in_range(Point::zero()..position)
20187                    .find(|hunk| hunk.row_range.end.0 < position.row)
20188                    .map(|hunk| hunk.row_range.start)
20189            });
20190        }
20191
20192        if let Some(row) = row {
20193            let destination = Point::new(row.0, 0);
20194            let autoscroll = Autoscroll::center();
20195
20196            self.unfold_ranges(&[destination..destination], false, false, cx);
20197            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20198                s.select_ranges([destination..destination]);
20199            });
20200        }
20201    }
20202
20203    fn do_stage_or_unstage(
20204        &self,
20205        stage: bool,
20206        buffer_id: BufferId,
20207        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20208        cx: &mut App,
20209    ) -> Option<()> {
20210        let project = self.project()?;
20211        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20212        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20213        let buffer_snapshot = buffer.read(cx).snapshot();
20214        let file_exists = buffer_snapshot
20215            .file()
20216            .is_some_and(|file| file.disk_state().exists());
20217        diff.update(cx, |diff, cx| {
20218            diff.stage_or_unstage_hunks(
20219                stage,
20220                &hunks
20221                    .map(|hunk| buffer_diff::DiffHunk {
20222                        buffer_range: hunk.buffer_range,
20223                        // We don't need to pass in word diffs here because they're only used for rendering and
20224                        // this function changes internal state
20225                        base_word_diffs: Vec::default(),
20226                        buffer_word_diffs: Vec::default(),
20227                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20228                            ..hunk.diff_base_byte_range.end.0,
20229                        secondary_status: hunk.status.secondary,
20230                        range: Point::zero()..Point::zero(), // unused
20231                    })
20232                    .collect::<Vec<_>>(),
20233                &buffer_snapshot,
20234                file_exists,
20235                cx,
20236            )
20237        });
20238        None
20239    }
20240
20241    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20242        let ranges: Vec<_> = self
20243            .selections
20244            .disjoint_anchors()
20245            .iter()
20246            .map(|s| s.range())
20247            .collect();
20248        self.buffer
20249            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20250    }
20251
20252    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20253        self.buffer.update(cx, |buffer, cx| {
20254            let ranges = vec![Anchor::min()..Anchor::max()];
20255            if !buffer.all_diff_hunks_expanded()
20256                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20257            {
20258                buffer.collapse_diff_hunks(ranges, cx);
20259                true
20260            } else {
20261                false
20262            }
20263        })
20264    }
20265
20266    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20267        if self.buffer.read(cx).all_diff_hunks_expanded() {
20268            return true;
20269        }
20270        let ranges = vec![Anchor::min()..Anchor::max()];
20271        self.buffer
20272            .read(cx)
20273            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20274    }
20275
20276    fn toggle_diff_hunks_in_ranges(
20277        &mut self,
20278        ranges: Vec<Range<Anchor>>,
20279        cx: &mut Context<Editor>,
20280    ) {
20281        self.buffer.update(cx, |buffer, cx| {
20282            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20283            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20284        })
20285    }
20286
20287    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20288        self.buffer.update(cx, |buffer, cx| {
20289            let snapshot = buffer.snapshot(cx);
20290            let excerpt_id = range.end.excerpt_id;
20291            let point_range = range.to_point(&snapshot);
20292            let expand = !buffer.single_hunk_is_expanded(range, cx);
20293            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20294        })
20295    }
20296
20297    pub(crate) fn apply_all_diff_hunks(
20298        &mut self,
20299        _: &ApplyAllDiffHunks,
20300        window: &mut Window,
20301        cx: &mut Context<Self>,
20302    ) {
20303        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20304
20305        let buffers = self.buffer.read(cx).all_buffers();
20306        for branch_buffer in buffers {
20307            branch_buffer.update(cx, |branch_buffer, cx| {
20308                branch_buffer.merge_into_base(Vec::new(), cx);
20309            });
20310        }
20311
20312        if let Some(project) = self.project.clone() {
20313            self.save(
20314                SaveOptions {
20315                    format: true,
20316                    autosave: false,
20317                },
20318                project,
20319                window,
20320                cx,
20321            )
20322            .detach_and_log_err(cx);
20323        }
20324    }
20325
20326    pub(crate) fn apply_selected_diff_hunks(
20327        &mut self,
20328        _: &ApplyDiffHunk,
20329        window: &mut Window,
20330        cx: &mut Context<Self>,
20331    ) {
20332        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20333        let snapshot = self.snapshot(window, cx);
20334        let hunks = snapshot.hunks_for_ranges(
20335            self.selections
20336                .all(&snapshot.display_snapshot)
20337                .into_iter()
20338                .map(|selection| selection.range()),
20339        );
20340        let mut ranges_by_buffer = HashMap::default();
20341        self.transact(window, cx, |editor, _window, cx| {
20342            for hunk in hunks {
20343                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20344                    ranges_by_buffer
20345                        .entry(buffer.clone())
20346                        .or_insert_with(Vec::new)
20347                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20348                }
20349            }
20350
20351            for (buffer, ranges) in ranges_by_buffer {
20352                buffer.update(cx, |buffer, cx| {
20353                    buffer.merge_into_base(ranges, cx);
20354                });
20355            }
20356        });
20357
20358        if let Some(project) = self.project.clone() {
20359            self.save(
20360                SaveOptions {
20361                    format: true,
20362                    autosave: false,
20363                },
20364                project,
20365                window,
20366                cx,
20367            )
20368            .detach_and_log_err(cx);
20369        }
20370    }
20371
20372    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20373        if hovered != self.gutter_hovered {
20374            self.gutter_hovered = hovered;
20375            cx.notify();
20376        }
20377    }
20378
20379    pub fn insert_blocks(
20380        &mut self,
20381        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20382        autoscroll: Option<Autoscroll>,
20383        cx: &mut Context<Self>,
20384    ) -> Vec<CustomBlockId> {
20385        let blocks = self
20386            .display_map
20387            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20388        if let Some(autoscroll) = autoscroll {
20389            self.request_autoscroll(autoscroll, cx);
20390        }
20391        cx.notify();
20392        blocks
20393    }
20394
20395    pub fn resize_blocks(
20396        &mut self,
20397        heights: HashMap<CustomBlockId, u32>,
20398        autoscroll: Option<Autoscroll>,
20399        cx: &mut Context<Self>,
20400    ) {
20401        self.display_map
20402            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20403        if let Some(autoscroll) = autoscroll {
20404            self.request_autoscroll(autoscroll, cx);
20405        }
20406        cx.notify();
20407    }
20408
20409    pub fn replace_blocks(
20410        &mut self,
20411        renderers: HashMap<CustomBlockId, RenderBlock>,
20412        autoscroll: Option<Autoscroll>,
20413        cx: &mut Context<Self>,
20414    ) {
20415        self.display_map
20416            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20417        if let Some(autoscroll) = autoscroll {
20418            self.request_autoscroll(autoscroll, cx);
20419        }
20420        cx.notify();
20421    }
20422
20423    pub fn remove_blocks(
20424        &mut self,
20425        block_ids: HashSet<CustomBlockId>,
20426        autoscroll: Option<Autoscroll>,
20427        cx: &mut Context<Self>,
20428    ) {
20429        self.display_map.update(cx, |display_map, cx| {
20430            display_map.remove_blocks(block_ids, cx)
20431        });
20432        if let Some(autoscroll) = autoscroll {
20433            self.request_autoscroll(autoscroll, cx);
20434        }
20435        cx.notify();
20436    }
20437
20438    pub fn row_for_block(
20439        &self,
20440        block_id: CustomBlockId,
20441        cx: &mut Context<Self>,
20442    ) -> Option<DisplayRow> {
20443        self.display_map
20444            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20445    }
20446
20447    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20448        self.focused_block = Some(focused_block);
20449    }
20450
20451    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20452        self.focused_block.take()
20453    }
20454
20455    pub fn insert_creases(
20456        &mut self,
20457        creases: impl IntoIterator<Item = Crease<Anchor>>,
20458        cx: &mut Context<Self>,
20459    ) -> Vec<CreaseId> {
20460        self.display_map
20461            .update(cx, |map, cx| map.insert_creases(creases, cx))
20462    }
20463
20464    pub fn remove_creases(
20465        &mut self,
20466        ids: impl IntoIterator<Item = CreaseId>,
20467        cx: &mut Context<Self>,
20468    ) -> Vec<(CreaseId, Range<Anchor>)> {
20469        self.display_map
20470            .update(cx, |map, cx| map.remove_creases(ids, cx))
20471    }
20472
20473    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20474        self.display_map
20475            .update(cx, |map, cx| map.snapshot(cx))
20476            .longest_row()
20477    }
20478
20479    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20480        self.display_map
20481            .update(cx, |map, cx| map.snapshot(cx))
20482            .max_point()
20483    }
20484
20485    pub fn text(&self, cx: &App) -> String {
20486        self.buffer.read(cx).read(cx).text()
20487    }
20488
20489    pub fn is_empty(&self, cx: &App) -> bool {
20490        self.buffer.read(cx).read(cx).is_empty()
20491    }
20492
20493    pub fn text_option(&self, cx: &App) -> Option<String> {
20494        let text = self.text(cx);
20495        let text = text.trim();
20496
20497        if text.is_empty() {
20498            return None;
20499        }
20500
20501        Some(text.to_string())
20502    }
20503
20504    pub fn set_text(
20505        &mut self,
20506        text: impl Into<Arc<str>>,
20507        window: &mut Window,
20508        cx: &mut Context<Self>,
20509    ) {
20510        self.transact(window, cx, |this, _, cx| {
20511            this.buffer
20512                .read(cx)
20513                .as_singleton()
20514                .expect("you can only call set_text on editors for singleton buffers")
20515                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20516        });
20517    }
20518
20519    pub fn display_text(&self, cx: &mut App) -> String {
20520        self.display_map
20521            .update(cx, |map, cx| map.snapshot(cx))
20522            .text()
20523    }
20524
20525    fn create_minimap(
20526        &self,
20527        minimap_settings: MinimapSettings,
20528        window: &mut Window,
20529        cx: &mut Context<Self>,
20530    ) -> Option<Entity<Self>> {
20531        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20532            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20533    }
20534
20535    fn initialize_new_minimap(
20536        &self,
20537        minimap_settings: MinimapSettings,
20538        window: &mut Window,
20539        cx: &mut Context<Self>,
20540    ) -> Entity<Self> {
20541        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20542        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20543
20544        let mut minimap = Editor::new_internal(
20545            EditorMode::Minimap {
20546                parent: cx.weak_entity(),
20547            },
20548            self.buffer.clone(),
20549            None,
20550            Some(self.display_map.clone()),
20551            window,
20552            cx,
20553        );
20554        minimap.scroll_manager.clone_state(&self.scroll_manager);
20555        minimap.set_text_style_refinement(TextStyleRefinement {
20556            font_size: Some(MINIMAP_FONT_SIZE),
20557            font_weight: Some(MINIMAP_FONT_WEIGHT),
20558            font_family: Some(MINIMAP_FONT_FAMILY),
20559            ..Default::default()
20560        });
20561        minimap.update_minimap_configuration(minimap_settings, cx);
20562        cx.new(|_| minimap)
20563    }
20564
20565    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20566        let current_line_highlight = minimap_settings
20567            .current_line_highlight
20568            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20569        self.set_current_line_highlight(Some(current_line_highlight));
20570    }
20571
20572    pub fn minimap(&self) -> Option<&Entity<Self>> {
20573        self.minimap
20574            .as_ref()
20575            .filter(|_| self.minimap_visibility.visible())
20576    }
20577
20578    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20579        let mut wrap_guides = smallvec![];
20580
20581        if self.show_wrap_guides == Some(false) {
20582            return wrap_guides;
20583        }
20584
20585        let settings = self.buffer.read(cx).language_settings(cx);
20586        if settings.show_wrap_guides {
20587            match self.soft_wrap_mode(cx) {
20588                SoftWrap::Column(soft_wrap) => {
20589                    wrap_guides.push((soft_wrap as usize, true));
20590                }
20591                SoftWrap::Bounded(soft_wrap) => {
20592                    wrap_guides.push((soft_wrap as usize, true));
20593                }
20594                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20595            }
20596            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20597        }
20598
20599        wrap_guides
20600    }
20601
20602    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20603        let settings = self.buffer.read(cx).language_settings(cx);
20604        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20605        match mode {
20606            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20607                SoftWrap::None
20608            }
20609            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20610            language_settings::SoftWrap::PreferredLineLength => {
20611                SoftWrap::Column(settings.preferred_line_length)
20612            }
20613            language_settings::SoftWrap::Bounded => {
20614                SoftWrap::Bounded(settings.preferred_line_length)
20615            }
20616        }
20617    }
20618
20619    pub fn set_soft_wrap_mode(
20620        &mut self,
20621        mode: language_settings::SoftWrap,
20622
20623        cx: &mut Context<Self>,
20624    ) {
20625        self.soft_wrap_mode_override = Some(mode);
20626        cx.notify();
20627    }
20628
20629    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20630        self.hard_wrap = hard_wrap;
20631        cx.notify();
20632    }
20633
20634    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20635        self.text_style_refinement = Some(style);
20636    }
20637
20638    /// called by the Element so we know what style we were most recently rendered with.
20639    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20640        // We intentionally do not inform the display map about the minimap style
20641        // so that wrapping is not recalculated and stays consistent for the editor
20642        // and its linked minimap.
20643        if !self.mode.is_minimap() {
20644            let font = style.text.font();
20645            let font_size = style.text.font_size.to_pixels(window.rem_size());
20646            let display_map = self
20647                .placeholder_display_map
20648                .as_ref()
20649                .filter(|_| self.is_empty(cx))
20650                .unwrap_or(&self.display_map);
20651
20652            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20653        }
20654        self.style = Some(style);
20655    }
20656
20657    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20658        if self.style.is_none() {
20659            self.style = Some(self.create_style(cx));
20660        }
20661        self.style.as_ref().unwrap()
20662    }
20663
20664    // Called by the element. This method is not designed to be called outside of the editor
20665    // element's layout code because it does not notify when rewrapping is computed synchronously.
20666    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20667        if self.is_empty(cx) {
20668            self.placeholder_display_map
20669                .as_ref()
20670                .map_or(false, |display_map| {
20671                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20672                })
20673        } else {
20674            self.display_map
20675                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20676        }
20677    }
20678
20679    pub fn set_soft_wrap(&mut self) {
20680        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20681    }
20682
20683    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20684        if self.soft_wrap_mode_override.is_some() {
20685            self.soft_wrap_mode_override.take();
20686        } else {
20687            let soft_wrap = match self.soft_wrap_mode(cx) {
20688                SoftWrap::GitDiff => return,
20689                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20690                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20691                    language_settings::SoftWrap::None
20692                }
20693            };
20694            self.soft_wrap_mode_override = Some(soft_wrap);
20695        }
20696        cx.notify();
20697    }
20698
20699    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20700        let Some(workspace) = self.workspace() else {
20701            return;
20702        };
20703        let fs = workspace.read(cx).app_state().fs.clone();
20704        let current_show = TabBarSettings::get_global(cx).show;
20705        update_settings_file(fs, cx, move |setting, _| {
20706            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20707        });
20708    }
20709
20710    pub fn toggle_indent_guides(
20711        &mut self,
20712        _: &ToggleIndentGuides,
20713        _: &mut Window,
20714        cx: &mut Context<Self>,
20715    ) {
20716        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20717            self.buffer
20718                .read(cx)
20719                .language_settings(cx)
20720                .indent_guides
20721                .enabled
20722        });
20723        self.show_indent_guides = Some(!currently_enabled);
20724        cx.notify();
20725    }
20726
20727    fn should_show_indent_guides(&self) -> Option<bool> {
20728        self.show_indent_guides
20729    }
20730
20731    pub fn disable_indent_guides_for_buffer(
20732        &mut self,
20733        buffer_id: BufferId,
20734        cx: &mut Context<Self>,
20735    ) {
20736        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20737        cx.notify();
20738    }
20739
20740    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20741        self.buffers_with_disabled_indent_guides
20742            .contains(&buffer_id)
20743    }
20744
20745    pub fn toggle_line_numbers(
20746        &mut self,
20747        _: &ToggleLineNumbers,
20748        _: &mut Window,
20749        cx: &mut Context<Self>,
20750    ) {
20751        let mut editor_settings = EditorSettings::get_global(cx).clone();
20752        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20753        EditorSettings::override_global(editor_settings, cx);
20754    }
20755
20756    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20757        if let Some(show_line_numbers) = self.show_line_numbers {
20758            return show_line_numbers;
20759        }
20760        EditorSettings::get_global(cx).gutter.line_numbers
20761    }
20762
20763    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20764        match (
20765            self.use_relative_line_numbers,
20766            EditorSettings::get_global(cx).relative_line_numbers,
20767        ) {
20768            (None, setting) => setting,
20769            (Some(false), _) => RelativeLineNumbers::Disabled,
20770            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20771            (Some(true), _) => RelativeLineNumbers::Enabled,
20772        }
20773    }
20774
20775    pub fn toggle_relative_line_numbers(
20776        &mut self,
20777        _: &ToggleRelativeLineNumbers,
20778        _: &mut Window,
20779        cx: &mut Context<Self>,
20780    ) {
20781        let is_relative = self.relative_line_numbers(cx);
20782        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20783    }
20784
20785    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20786        self.use_relative_line_numbers = is_relative;
20787        cx.notify();
20788    }
20789
20790    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20791        self.show_gutter = show_gutter;
20792        cx.notify();
20793    }
20794
20795    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20796        self.show_scrollbars = ScrollbarAxes {
20797            horizontal: show,
20798            vertical: show,
20799        };
20800        cx.notify();
20801    }
20802
20803    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20804        self.show_scrollbars.vertical = show;
20805        cx.notify();
20806    }
20807
20808    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20809        self.show_scrollbars.horizontal = show;
20810        cx.notify();
20811    }
20812
20813    pub fn set_minimap_visibility(
20814        &mut self,
20815        minimap_visibility: MinimapVisibility,
20816        window: &mut Window,
20817        cx: &mut Context<Self>,
20818    ) {
20819        if self.minimap_visibility != minimap_visibility {
20820            if minimap_visibility.visible() && self.minimap.is_none() {
20821                let minimap_settings = EditorSettings::get_global(cx).minimap;
20822                self.minimap =
20823                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20824            }
20825            self.minimap_visibility = minimap_visibility;
20826            cx.notify();
20827        }
20828    }
20829
20830    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20831        self.set_show_scrollbars(false, cx);
20832        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20833    }
20834
20835    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20836        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20837    }
20838
20839    /// Normally the text in full mode and auto height editors is padded on the
20840    /// left side by roughly half a character width for improved hit testing.
20841    ///
20842    /// Use this method to disable this for cases where this is not wanted (e.g.
20843    /// if you want to align the editor text with some other text above or below)
20844    /// or if you want to add this padding to single-line editors.
20845    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20846        self.offset_content = offset_content;
20847        cx.notify();
20848    }
20849
20850    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20851        self.show_line_numbers = Some(show_line_numbers);
20852        cx.notify();
20853    }
20854
20855    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20856        self.disable_expand_excerpt_buttons = true;
20857        cx.notify();
20858    }
20859
20860    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
20861        self.delegate_expand_excerpts = delegate;
20862    }
20863
20864    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20865        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20866        cx.notify();
20867    }
20868
20869    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20870        self.show_code_actions = Some(show_code_actions);
20871        cx.notify();
20872    }
20873
20874    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20875        self.show_runnables = Some(show_runnables);
20876        cx.notify();
20877    }
20878
20879    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20880        self.show_breakpoints = Some(show_breakpoints);
20881        cx.notify();
20882    }
20883
20884    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
20885        self.show_diff_review_button = show;
20886        cx.notify();
20887    }
20888
20889    pub fn show_diff_review_button(&self) -> bool {
20890        self.show_diff_review_button
20891    }
20892
20893    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20894        if self.display_map.read(cx).masked != masked {
20895            self.display_map.update(cx, |map, _| map.masked = masked);
20896        }
20897        cx.notify()
20898    }
20899
20900    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20901        self.show_wrap_guides = Some(show_wrap_guides);
20902        cx.notify();
20903    }
20904
20905    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20906        self.show_indent_guides = Some(show_indent_guides);
20907        cx.notify();
20908    }
20909
20910    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20911        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20912            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20913                && let Some(dir) = file.abs_path(cx).parent()
20914            {
20915                return Some(dir.to_owned());
20916            }
20917        }
20918
20919        None
20920    }
20921
20922    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20923        self.active_excerpt(cx)?
20924            .1
20925            .read(cx)
20926            .file()
20927            .and_then(|f| f.as_local())
20928    }
20929
20930    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20931        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20932            let buffer = buffer.read(cx);
20933            if let Some(project_path) = buffer.project_path(cx) {
20934                let project = self.project()?.read(cx);
20935                project.absolute_path(&project_path, cx)
20936            } else {
20937                buffer
20938                    .file()
20939                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20940            }
20941        })
20942    }
20943
20944    pub fn reveal_in_finder(
20945        &mut self,
20946        _: &RevealInFileManager,
20947        _window: &mut Window,
20948        cx: &mut Context<Self>,
20949    ) {
20950        if let Some(target) = self.target_file(cx) {
20951            cx.reveal_path(&target.abs_path(cx));
20952        }
20953    }
20954
20955    pub fn copy_path(
20956        &mut self,
20957        _: &zed_actions::workspace::CopyPath,
20958        _window: &mut Window,
20959        cx: &mut Context<Self>,
20960    ) {
20961        if let Some(path) = self.target_file_abs_path(cx)
20962            && let Some(path) = path.to_str()
20963        {
20964            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20965        } else {
20966            cx.propagate();
20967        }
20968    }
20969
20970    pub fn copy_relative_path(
20971        &mut self,
20972        _: &zed_actions::workspace::CopyRelativePath,
20973        _window: &mut Window,
20974        cx: &mut Context<Self>,
20975    ) {
20976        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20977            let project = self.project()?.read(cx);
20978            let path = buffer.read(cx).file()?.path();
20979            let path = path.display(project.path_style(cx));
20980            Some(path)
20981        }) {
20982            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20983        } else {
20984            cx.propagate();
20985        }
20986    }
20987
20988    /// Returns the project path for the editor's buffer, if any buffer is
20989    /// opened in the editor.
20990    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20991        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20992            buffer.read(cx).project_path(cx)
20993        } else {
20994            None
20995        }
20996    }
20997
20998    // Returns true if the editor handled a go-to-line request
20999    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
21000        maybe!({
21001            let breakpoint_store = self.breakpoint_store.as_ref()?;
21002
21003            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
21004            else {
21005                self.clear_row_highlights::<ActiveDebugLine>();
21006                return None;
21007            };
21008
21009            let position = active_stack_frame.position;
21010            let buffer_id = position.buffer_id?;
21011            let snapshot = self
21012                .project
21013                .as_ref()?
21014                .read(cx)
21015                .buffer_for_id(buffer_id, cx)?
21016                .read(cx)
21017                .snapshot();
21018
21019            let mut handled = false;
21020            for (id, ExcerptRange { context, .. }) in
21021                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
21022            {
21023                if context.start.cmp(&position, &snapshot).is_ge()
21024                    || context.end.cmp(&position, &snapshot).is_lt()
21025                {
21026                    continue;
21027                }
21028                let snapshot = self.buffer.read(cx).snapshot(cx);
21029                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
21030
21031                handled = true;
21032                self.clear_row_highlights::<ActiveDebugLine>();
21033
21034                self.go_to_line::<ActiveDebugLine>(
21035                    multibuffer_anchor,
21036                    Some(cx.theme().colors().editor_debugger_active_line_background),
21037                    window,
21038                    cx,
21039                );
21040
21041                cx.notify();
21042            }
21043
21044            handled.then_some(())
21045        })
21046        .is_some()
21047    }
21048
21049    pub fn copy_file_name_without_extension(
21050        &mut self,
21051        _: &CopyFileNameWithoutExtension,
21052        _: &mut Window,
21053        cx: &mut Context<Self>,
21054    ) {
21055        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21056            let file = buffer.read(cx).file()?;
21057            file.path().file_stem()
21058        }) {
21059            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
21060        }
21061    }
21062
21063    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
21064        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21065            let file = buffer.read(cx).file()?;
21066            Some(file.file_name(cx))
21067        }) {
21068            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
21069        }
21070    }
21071
21072    pub fn toggle_git_blame(
21073        &mut self,
21074        _: &::git::Blame,
21075        window: &mut Window,
21076        cx: &mut Context<Self>,
21077    ) {
21078        self.show_git_blame_gutter = !self.show_git_blame_gutter;
21079
21080        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
21081            self.start_git_blame(true, window, cx);
21082        }
21083
21084        cx.notify();
21085    }
21086
21087    pub fn toggle_git_blame_inline(
21088        &mut self,
21089        _: &ToggleGitBlameInline,
21090        window: &mut Window,
21091        cx: &mut Context<Self>,
21092    ) {
21093        self.toggle_git_blame_inline_internal(true, window, cx);
21094        cx.notify();
21095    }
21096
21097    pub fn open_git_blame_commit(
21098        &mut self,
21099        _: &OpenGitBlameCommit,
21100        window: &mut Window,
21101        cx: &mut Context<Self>,
21102    ) {
21103        self.open_git_blame_commit_internal(window, cx);
21104    }
21105
21106    fn open_git_blame_commit_internal(
21107        &mut self,
21108        window: &mut Window,
21109        cx: &mut Context<Self>,
21110    ) -> Option<()> {
21111        let blame = self.blame.as_ref()?;
21112        let snapshot = self.snapshot(window, cx);
21113        let cursor = self
21114            .selections
21115            .newest::<Point>(&snapshot.display_snapshot)
21116            .head();
21117        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
21118        let (_, blame_entry) = blame
21119            .update(cx, |blame, cx| {
21120                blame
21121                    .blame_for_rows(
21122                        &[RowInfo {
21123                            buffer_id: Some(buffer.remote_id()),
21124                            buffer_row: Some(point.row),
21125                            ..Default::default()
21126                        }],
21127                        cx,
21128                    )
21129                    .next()
21130            })
21131            .flatten()?;
21132        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21133        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
21134        let workspace = self.workspace()?.downgrade();
21135        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
21136        None
21137    }
21138
21139    pub fn git_blame_inline_enabled(&self) -> bool {
21140        self.git_blame_inline_enabled
21141    }
21142
21143    pub fn toggle_selection_menu(
21144        &mut self,
21145        _: &ToggleSelectionMenu,
21146        _: &mut Window,
21147        cx: &mut Context<Self>,
21148    ) {
21149        self.show_selection_menu = self
21150            .show_selection_menu
21151            .map(|show_selections_menu| !show_selections_menu)
21152            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
21153
21154        cx.notify();
21155    }
21156
21157    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
21158        self.show_selection_menu
21159            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
21160    }
21161
21162    fn start_git_blame(
21163        &mut self,
21164        user_triggered: bool,
21165        window: &mut Window,
21166        cx: &mut Context<Self>,
21167    ) {
21168        if let Some(project) = self.project() {
21169            if let Some(buffer) = self.buffer().read(cx).as_singleton()
21170                && buffer.read(cx).file().is_none()
21171            {
21172                return;
21173            }
21174
21175            let focused = self.focus_handle(cx).contains_focused(window, cx);
21176
21177            let project = project.clone();
21178            let blame = cx
21179                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
21180            self.blame_subscription =
21181                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
21182            self.blame = Some(blame);
21183        }
21184    }
21185
21186    fn toggle_git_blame_inline_internal(
21187        &mut self,
21188        user_triggered: bool,
21189        window: &mut Window,
21190        cx: &mut Context<Self>,
21191    ) {
21192        if self.git_blame_inline_enabled {
21193            self.git_blame_inline_enabled = false;
21194            self.show_git_blame_inline = false;
21195            self.show_git_blame_inline_delay_task.take();
21196        } else {
21197            self.git_blame_inline_enabled = true;
21198            self.start_git_blame_inline(user_triggered, window, cx);
21199        }
21200
21201        cx.notify();
21202    }
21203
21204    fn start_git_blame_inline(
21205        &mut self,
21206        user_triggered: bool,
21207        window: &mut Window,
21208        cx: &mut Context<Self>,
21209    ) {
21210        self.start_git_blame(user_triggered, window, cx);
21211
21212        if ProjectSettings::get_global(cx)
21213            .git
21214            .inline_blame_delay()
21215            .is_some()
21216        {
21217            self.start_inline_blame_timer(window, cx);
21218        } else {
21219            self.show_git_blame_inline = true
21220        }
21221    }
21222
21223    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21224        self.blame.as_ref()
21225    }
21226
21227    pub fn show_git_blame_gutter(&self) -> bool {
21228        self.show_git_blame_gutter
21229    }
21230
21231    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21232        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21233    }
21234
21235    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21236        self.show_git_blame_inline
21237            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21238            && !self.newest_selection_head_on_empty_line(cx)
21239            && self.has_blame_entries(cx)
21240    }
21241
21242    fn has_blame_entries(&self, cx: &App) -> bool {
21243        self.blame()
21244            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21245    }
21246
21247    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21248        let cursor_anchor = self.selections.newest_anchor().head();
21249
21250        let snapshot = self.buffer.read(cx).snapshot(cx);
21251        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21252
21253        snapshot.line_len(buffer_row) == 0
21254    }
21255
21256    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21257        let buffer_and_selection = maybe!({
21258            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21259            let selection_range = selection.range();
21260
21261            let multi_buffer = self.buffer().read(cx);
21262            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21263            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21264
21265            let (buffer, range, _) = if selection.reversed {
21266                buffer_ranges.first()
21267            } else {
21268                buffer_ranges.last()
21269            }?;
21270
21271            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21272            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21273
21274            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21275                let selection = start_row_in_buffer..end_row_in_buffer;
21276
21277                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21278            };
21279
21280            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21281
21282            Some((
21283                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21284                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, Bias::Left, buffer)
21285                    ..buffer_diff_snapshot.row_to_base_text_row(
21286                        end_row_in_buffer,
21287                        Bias::Left,
21288                        buffer,
21289                    ),
21290            ))
21291        });
21292
21293        let Some((buffer, selection)) = buffer_and_selection else {
21294            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21295        };
21296
21297        let Some(project) = self.project() else {
21298            return Task::ready(Err(anyhow!("editor does not have project")));
21299        };
21300
21301        project.update(cx, |project, cx| {
21302            project.get_permalink_to_line(&buffer, selection, cx)
21303        })
21304    }
21305
21306    pub fn copy_permalink_to_line(
21307        &mut self,
21308        _: &CopyPermalinkToLine,
21309        window: &mut Window,
21310        cx: &mut Context<Self>,
21311    ) {
21312        let permalink_task = self.get_permalink_to_line(cx);
21313        let workspace = self.workspace();
21314
21315        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21316            Ok(permalink) => {
21317                cx.update(|_, cx| {
21318                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21319                })
21320                .ok();
21321            }
21322            Err(err) => {
21323                let message = format!("Failed to copy permalink: {err}");
21324
21325                anyhow::Result::<()>::Err(err).log_err();
21326
21327                if let Some(workspace) = workspace {
21328                    workspace
21329                        .update_in(cx, |workspace, _, cx| {
21330                            struct CopyPermalinkToLine;
21331
21332                            workspace.show_toast(
21333                                Toast::new(
21334                                    NotificationId::unique::<CopyPermalinkToLine>(),
21335                                    message,
21336                                ),
21337                                cx,
21338                            )
21339                        })
21340                        .ok();
21341                }
21342            }
21343        })
21344        .detach();
21345    }
21346
21347    pub fn copy_file_location(
21348        &mut self,
21349        _: &CopyFileLocation,
21350        _: &mut Window,
21351        cx: &mut Context<Self>,
21352    ) {
21353        let selection = self
21354            .selections
21355            .newest::<Point>(&self.display_snapshot(cx))
21356            .start
21357            .row
21358            + 1;
21359        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21360            let project = self.project()?.read(cx);
21361            let file = buffer.read(cx).file()?;
21362            let path = file.path().display(project.path_style(cx));
21363
21364            Some(format!("{path}:{selection}"))
21365        }) {
21366            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21367        }
21368    }
21369
21370    pub fn open_permalink_to_line(
21371        &mut self,
21372        _: &OpenPermalinkToLine,
21373        window: &mut Window,
21374        cx: &mut Context<Self>,
21375    ) {
21376        let permalink_task = self.get_permalink_to_line(cx);
21377        let workspace = self.workspace();
21378
21379        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21380            Ok(permalink) => {
21381                cx.update(|_, cx| {
21382                    cx.open_url(permalink.as_ref());
21383                })
21384                .ok();
21385            }
21386            Err(err) => {
21387                let message = format!("Failed to open permalink: {err}");
21388
21389                anyhow::Result::<()>::Err(err).log_err();
21390
21391                if let Some(workspace) = workspace {
21392                    workspace.update(cx, |workspace, cx| {
21393                        struct OpenPermalinkToLine;
21394
21395                        workspace.show_toast(
21396                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
21397                            cx,
21398                        )
21399                    });
21400                }
21401            }
21402        })
21403        .detach();
21404    }
21405
21406    pub fn insert_uuid_v4(
21407        &mut self,
21408        _: &InsertUuidV4,
21409        window: &mut Window,
21410        cx: &mut Context<Self>,
21411    ) {
21412        self.insert_uuid(UuidVersion::V4, window, cx);
21413    }
21414
21415    pub fn insert_uuid_v7(
21416        &mut self,
21417        _: &InsertUuidV7,
21418        window: &mut Window,
21419        cx: &mut Context<Self>,
21420    ) {
21421        self.insert_uuid(UuidVersion::V7, window, cx);
21422    }
21423
21424    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21425        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21426        self.transact(window, cx, |this, window, cx| {
21427            let edits = this
21428                .selections
21429                .all::<Point>(&this.display_snapshot(cx))
21430                .into_iter()
21431                .map(|selection| {
21432                    let uuid = match version {
21433                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21434                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21435                    };
21436
21437                    (selection.range(), uuid.to_string())
21438                });
21439            this.edit(edits, cx);
21440            this.refresh_edit_prediction(true, false, window, cx);
21441        });
21442    }
21443
21444    pub fn open_selections_in_multibuffer(
21445        &mut self,
21446        _: &OpenSelectionsInMultibuffer,
21447        window: &mut Window,
21448        cx: &mut Context<Self>,
21449    ) {
21450        let multibuffer = self.buffer.read(cx);
21451
21452        let Some(buffer) = multibuffer.as_singleton() else {
21453            return;
21454        };
21455
21456        let Some(workspace) = self.workspace() else {
21457            return;
21458        };
21459
21460        let title = multibuffer.title(cx).to_string();
21461
21462        let locations = self
21463            .selections
21464            .all_anchors(&self.display_snapshot(cx))
21465            .iter()
21466            .map(|selection| {
21467                (
21468                    buffer.clone(),
21469                    (selection.start.text_anchor..selection.end.text_anchor)
21470                        .to_point(buffer.read(cx)),
21471                )
21472            })
21473            .into_group_map();
21474
21475        cx.spawn_in(window, async move |_, cx| {
21476            workspace.update_in(cx, |workspace, window, cx| {
21477                Self::open_locations_in_multibuffer(
21478                    workspace,
21479                    locations,
21480                    format!("Selections for '{title}'"),
21481                    false,
21482                    false,
21483                    MultibufferSelectionMode::All,
21484                    window,
21485                    cx,
21486                );
21487            })
21488        })
21489        .detach();
21490    }
21491
21492    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21493    /// last highlight added will be used.
21494    ///
21495    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21496    pub fn highlight_rows<T: 'static>(
21497        &mut self,
21498        range: Range<Anchor>,
21499        color: Hsla,
21500        options: RowHighlightOptions,
21501        cx: &mut Context<Self>,
21502    ) {
21503        let snapshot = self.buffer().read(cx).snapshot(cx);
21504        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21505        let ix = row_highlights.binary_search_by(|highlight| {
21506            Ordering::Equal
21507                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21508                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21509        });
21510
21511        if let Err(mut ix) = ix {
21512            let index = post_inc(&mut self.highlight_order);
21513
21514            // If this range intersects with the preceding highlight, then merge it with
21515            // the preceding highlight. Otherwise insert a new highlight.
21516            let mut merged = false;
21517            if ix > 0 {
21518                let prev_highlight = &mut row_highlights[ix - 1];
21519                if prev_highlight
21520                    .range
21521                    .end
21522                    .cmp(&range.start, &snapshot)
21523                    .is_ge()
21524                {
21525                    ix -= 1;
21526                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21527                        prev_highlight.range.end = range.end;
21528                    }
21529                    merged = true;
21530                    prev_highlight.index = index;
21531                    prev_highlight.color = color;
21532                    prev_highlight.options = options;
21533                }
21534            }
21535
21536            if !merged {
21537                row_highlights.insert(
21538                    ix,
21539                    RowHighlight {
21540                        range,
21541                        index,
21542                        color,
21543                        options,
21544                        type_id: TypeId::of::<T>(),
21545                    },
21546                );
21547            }
21548
21549            // If any of the following highlights intersect with this one, merge them.
21550            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21551                let highlight = &row_highlights[ix];
21552                if next_highlight
21553                    .range
21554                    .start
21555                    .cmp(&highlight.range.end, &snapshot)
21556                    .is_le()
21557                {
21558                    if next_highlight
21559                        .range
21560                        .end
21561                        .cmp(&highlight.range.end, &snapshot)
21562                        .is_gt()
21563                    {
21564                        row_highlights[ix].range.end = next_highlight.range.end;
21565                    }
21566                    row_highlights.remove(ix + 1);
21567                } else {
21568                    break;
21569                }
21570            }
21571        }
21572    }
21573
21574    /// Remove any highlighted row ranges of the given type that intersect the
21575    /// given ranges.
21576    pub fn remove_highlighted_rows<T: 'static>(
21577        &mut self,
21578        ranges_to_remove: Vec<Range<Anchor>>,
21579        cx: &mut Context<Self>,
21580    ) {
21581        let snapshot = self.buffer().read(cx).snapshot(cx);
21582        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21583        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21584        row_highlights.retain(|highlight| {
21585            while let Some(range_to_remove) = ranges_to_remove.peek() {
21586                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21587                    Ordering::Less | Ordering::Equal => {
21588                        ranges_to_remove.next();
21589                    }
21590                    Ordering::Greater => {
21591                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21592                            Ordering::Less | Ordering::Equal => {
21593                                return false;
21594                            }
21595                            Ordering::Greater => break,
21596                        }
21597                    }
21598                }
21599            }
21600
21601            true
21602        })
21603    }
21604
21605    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21606    pub fn clear_row_highlights<T: 'static>(&mut self) {
21607        self.highlighted_rows.remove(&TypeId::of::<T>());
21608    }
21609
21610    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21611    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21612        self.highlighted_rows
21613            .get(&TypeId::of::<T>())
21614            .map_or(&[] as &[_], |vec| vec.as_slice())
21615            .iter()
21616            .map(|highlight| (highlight.range.clone(), highlight.color))
21617    }
21618
21619    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21620    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21621    /// Allows to ignore certain kinds of highlights.
21622    pub fn highlighted_display_rows(
21623        &self,
21624        window: &mut Window,
21625        cx: &mut App,
21626    ) -> BTreeMap<DisplayRow, LineHighlight> {
21627        let snapshot = self.snapshot(window, cx);
21628        let mut used_highlight_orders = HashMap::default();
21629        self.highlighted_rows
21630            .iter()
21631            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21632            .fold(
21633                BTreeMap::<DisplayRow, LineHighlight>::new(),
21634                |mut unique_rows, highlight| {
21635                    let start = highlight.range.start.to_display_point(&snapshot);
21636                    let end = highlight.range.end.to_display_point(&snapshot);
21637                    let start_row = start.row().0;
21638                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21639                    {
21640                        end.row().0.saturating_sub(1)
21641                    } else {
21642                        end.row().0
21643                    };
21644                    for row in start_row..=end_row {
21645                        let used_index =
21646                            used_highlight_orders.entry(row).or_insert(highlight.index);
21647                        if highlight.index >= *used_index {
21648                            *used_index = highlight.index;
21649                            unique_rows.insert(
21650                                DisplayRow(row),
21651                                LineHighlight {
21652                                    include_gutter: highlight.options.include_gutter,
21653                                    border: None,
21654                                    background: highlight.color.into(),
21655                                    type_id: Some(highlight.type_id),
21656                                },
21657                            );
21658                        }
21659                    }
21660                    unique_rows
21661                },
21662            )
21663    }
21664
21665    pub fn highlighted_display_row_for_autoscroll(
21666        &self,
21667        snapshot: &DisplaySnapshot,
21668    ) -> Option<DisplayRow> {
21669        self.highlighted_rows
21670            .values()
21671            .flat_map(|highlighted_rows| highlighted_rows.iter())
21672            .filter_map(|highlight| {
21673                if highlight.options.autoscroll {
21674                    Some(highlight.range.start.to_display_point(snapshot).row())
21675                } else {
21676                    None
21677                }
21678            })
21679            .min()
21680    }
21681
21682    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21683        self.highlight_background::<SearchWithinRange>(
21684            ranges,
21685            |_, colors| colors.colors().editor_document_highlight_read_background,
21686            cx,
21687        )
21688    }
21689
21690    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21691        self.breadcrumb_header = Some(new_header);
21692    }
21693
21694    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21695        self.clear_background_highlights::<SearchWithinRange>(cx);
21696    }
21697
21698    pub fn highlight_background<T: 'static>(
21699        &mut self,
21700        ranges: &[Range<Anchor>],
21701        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21702        cx: &mut Context<Self>,
21703    ) {
21704        self.background_highlights.insert(
21705            HighlightKey::Type(TypeId::of::<T>()),
21706            (Arc::new(color_fetcher), Arc::from(ranges)),
21707        );
21708        self.scrollbar_marker_state.dirty = true;
21709        cx.notify();
21710    }
21711
21712    pub fn highlight_background_key<T: 'static>(
21713        &mut self,
21714        key: usize,
21715        ranges: &[Range<Anchor>],
21716        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21717        cx: &mut Context<Self>,
21718    ) {
21719        self.background_highlights.insert(
21720            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21721            (Arc::new(color_fetcher), Arc::from(ranges)),
21722        );
21723        self.scrollbar_marker_state.dirty = true;
21724        cx.notify();
21725    }
21726
21727    pub fn clear_background_highlights<T: 'static>(
21728        &mut self,
21729        cx: &mut Context<Self>,
21730    ) -> Option<BackgroundHighlight> {
21731        let text_highlights = self
21732            .background_highlights
21733            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21734        if !text_highlights.1.is_empty() {
21735            self.scrollbar_marker_state.dirty = true;
21736            cx.notify();
21737        }
21738        Some(text_highlights)
21739    }
21740
21741    pub fn highlight_gutter<T: 'static>(
21742        &mut self,
21743        ranges: impl Into<Vec<Range<Anchor>>>,
21744        color_fetcher: fn(&App) -> Hsla,
21745        cx: &mut Context<Self>,
21746    ) {
21747        self.gutter_highlights
21748            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21749        cx.notify();
21750    }
21751
21752    pub fn clear_gutter_highlights<T: 'static>(
21753        &mut self,
21754        cx: &mut Context<Self>,
21755    ) -> Option<GutterHighlight> {
21756        cx.notify();
21757        self.gutter_highlights.remove(&TypeId::of::<T>())
21758    }
21759
21760    pub fn insert_gutter_highlight<T: 'static>(
21761        &mut self,
21762        range: Range<Anchor>,
21763        color_fetcher: fn(&App) -> Hsla,
21764        cx: &mut Context<Self>,
21765    ) {
21766        let snapshot = self.buffer().read(cx).snapshot(cx);
21767        let mut highlights = self
21768            .gutter_highlights
21769            .remove(&TypeId::of::<T>())
21770            .map(|(_, highlights)| highlights)
21771            .unwrap_or_default();
21772        let ix = highlights.binary_search_by(|highlight| {
21773            Ordering::Equal
21774                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21775                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21776        });
21777        if let Err(ix) = ix {
21778            highlights.insert(ix, range);
21779        }
21780        self.gutter_highlights
21781            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21782    }
21783
21784    pub fn remove_gutter_highlights<T: 'static>(
21785        &mut self,
21786        ranges_to_remove: Vec<Range<Anchor>>,
21787        cx: &mut Context<Self>,
21788    ) {
21789        let snapshot = self.buffer().read(cx).snapshot(cx);
21790        let Some((color_fetcher, mut gutter_highlights)) =
21791            self.gutter_highlights.remove(&TypeId::of::<T>())
21792        else {
21793            return;
21794        };
21795        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21796        gutter_highlights.retain(|highlight| {
21797            while let Some(range_to_remove) = ranges_to_remove.peek() {
21798                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21799                    Ordering::Less | Ordering::Equal => {
21800                        ranges_to_remove.next();
21801                    }
21802                    Ordering::Greater => {
21803                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21804                            Ordering::Less | Ordering::Equal => {
21805                                return false;
21806                            }
21807                            Ordering::Greater => break,
21808                        }
21809                    }
21810                }
21811            }
21812
21813            true
21814        });
21815        self.gutter_highlights
21816            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21817    }
21818
21819    #[cfg(feature = "test-support")]
21820    pub fn all_text_highlights(
21821        &self,
21822        window: &mut Window,
21823        cx: &mut Context<Self>,
21824    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21825        let snapshot = self.snapshot(window, cx);
21826        self.display_map.update(cx, |display_map, _| {
21827            display_map
21828                .all_text_highlights()
21829                .map(|highlight| {
21830                    let (style, ranges) = highlight.as_ref();
21831                    (
21832                        *style,
21833                        ranges
21834                            .iter()
21835                            .map(|range| range.clone().to_display_points(&snapshot))
21836                            .collect(),
21837                    )
21838                })
21839                .collect()
21840        })
21841    }
21842
21843    #[cfg(feature = "test-support")]
21844    pub fn all_text_background_highlights(
21845        &self,
21846        window: &mut Window,
21847        cx: &mut Context<Self>,
21848    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21849        let snapshot = self.snapshot(window, cx);
21850        let buffer = &snapshot.buffer_snapshot();
21851        let start = buffer.anchor_before(MultiBufferOffset(0));
21852        let end = buffer.anchor_after(buffer.len());
21853        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21854    }
21855
21856    #[cfg(any(test, feature = "test-support"))]
21857    pub fn sorted_background_highlights_in_range(
21858        &self,
21859        search_range: Range<Anchor>,
21860        display_snapshot: &DisplaySnapshot,
21861        theme: &Theme,
21862    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21863        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21864        res.sort_by(|a, b| {
21865            a.0.start
21866                .cmp(&b.0.start)
21867                .then_with(|| a.0.end.cmp(&b.0.end))
21868                .then_with(|| a.1.cmp(&b.1))
21869        });
21870        res
21871    }
21872
21873    #[cfg(feature = "test-support")]
21874    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21875        let snapshot = self.buffer().read(cx).snapshot(cx);
21876
21877        let highlights = self
21878            .background_highlights
21879            .get(&HighlightKey::Type(TypeId::of::<
21880                items::BufferSearchHighlights,
21881            >()));
21882
21883        if let Some((_color, ranges)) = highlights {
21884            ranges
21885                .iter()
21886                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21887                .collect_vec()
21888        } else {
21889            vec![]
21890        }
21891    }
21892
21893    fn document_highlights_for_position<'a>(
21894        &'a self,
21895        position: Anchor,
21896        buffer: &'a MultiBufferSnapshot,
21897    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21898        let read_highlights = self
21899            .background_highlights
21900            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21901            .map(|h| &h.1);
21902        let write_highlights = self
21903            .background_highlights
21904            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21905            .map(|h| &h.1);
21906        let left_position = position.bias_left(buffer);
21907        let right_position = position.bias_right(buffer);
21908        read_highlights
21909            .into_iter()
21910            .chain(write_highlights)
21911            .flat_map(move |ranges| {
21912                let start_ix = match ranges.binary_search_by(|probe| {
21913                    let cmp = probe.end.cmp(&left_position, buffer);
21914                    if cmp.is_ge() {
21915                        Ordering::Greater
21916                    } else {
21917                        Ordering::Less
21918                    }
21919                }) {
21920                    Ok(i) | Err(i) => i,
21921                };
21922
21923                ranges[start_ix..]
21924                    .iter()
21925                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21926            })
21927    }
21928
21929    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21930        self.background_highlights
21931            .get(&HighlightKey::Type(TypeId::of::<T>()))
21932            .is_some_and(|(_, highlights)| !highlights.is_empty())
21933    }
21934
21935    /// Returns all background highlights for a given range.
21936    ///
21937    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21938    pub fn background_highlights_in_range(
21939        &self,
21940        search_range: Range<Anchor>,
21941        display_snapshot: &DisplaySnapshot,
21942        theme: &Theme,
21943    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21944        let mut results = Vec::new();
21945        for (color_fetcher, ranges) in self.background_highlights.values() {
21946            let start_ix = match ranges.binary_search_by(|probe| {
21947                let cmp = probe
21948                    .end
21949                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21950                if cmp.is_gt() {
21951                    Ordering::Greater
21952                } else {
21953                    Ordering::Less
21954                }
21955            }) {
21956                Ok(i) | Err(i) => i,
21957            };
21958            for (index, range) in ranges[start_ix..].iter().enumerate() {
21959                if range
21960                    .start
21961                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21962                    .is_ge()
21963                {
21964                    break;
21965                }
21966
21967                let color = color_fetcher(&(start_ix + index), theme);
21968                let start = range.start.to_display_point(display_snapshot);
21969                let end = range.end.to_display_point(display_snapshot);
21970                results.push((start..end, color))
21971            }
21972        }
21973        results
21974    }
21975
21976    pub fn gutter_highlights_in_range(
21977        &self,
21978        search_range: Range<Anchor>,
21979        display_snapshot: &DisplaySnapshot,
21980        cx: &App,
21981    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21982        let mut results = Vec::new();
21983        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21984            let color = color_fetcher(cx);
21985            let start_ix = match ranges.binary_search_by(|probe| {
21986                let cmp = probe
21987                    .end
21988                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21989                if cmp.is_gt() {
21990                    Ordering::Greater
21991                } else {
21992                    Ordering::Less
21993                }
21994            }) {
21995                Ok(i) | Err(i) => i,
21996            };
21997            for range in &ranges[start_ix..] {
21998                if range
21999                    .start
22000                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
22001                    .is_ge()
22002                {
22003                    break;
22004                }
22005
22006                let start = range.start.to_display_point(display_snapshot);
22007                let end = range.end.to_display_point(display_snapshot);
22008                results.push((start..end, color))
22009            }
22010        }
22011        results
22012    }
22013
22014    /// Get the text ranges corresponding to the redaction query
22015    pub fn redacted_ranges(
22016        &self,
22017        search_range: Range<Anchor>,
22018        display_snapshot: &DisplaySnapshot,
22019        cx: &App,
22020    ) -> Vec<Range<DisplayPoint>> {
22021        display_snapshot
22022            .buffer_snapshot()
22023            .redacted_ranges(search_range, |file| {
22024                if let Some(file) = file {
22025                    file.is_private()
22026                        && EditorSettings::get(
22027                            Some(SettingsLocation {
22028                                worktree_id: file.worktree_id(cx),
22029                                path: file.path().as_ref(),
22030                            }),
22031                            cx,
22032                        )
22033                        .redact_private_values
22034                } else {
22035                    false
22036                }
22037            })
22038            .map(|range| {
22039                range.start.to_display_point(display_snapshot)
22040                    ..range.end.to_display_point(display_snapshot)
22041            })
22042            .collect()
22043    }
22044
22045    pub fn highlight_text_key<T: 'static>(
22046        &mut self,
22047        key: usize,
22048        ranges: Vec<Range<Anchor>>,
22049        style: HighlightStyle,
22050        merge: bool,
22051        cx: &mut Context<Self>,
22052    ) {
22053        self.display_map.update(cx, |map, cx| {
22054            map.highlight_text(
22055                HighlightKey::TypePlus(TypeId::of::<T>(), key),
22056                ranges,
22057                style,
22058                merge,
22059                cx,
22060            );
22061        });
22062        cx.notify();
22063    }
22064
22065    pub fn highlight_text<T: 'static>(
22066        &mut self,
22067        ranges: Vec<Range<Anchor>>,
22068        style: HighlightStyle,
22069        cx: &mut Context<Self>,
22070    ) {
22071        self.display_map.update(cx, |map, cx| {
22072            map.highlight_text(
22073                HighlightKey::Type(TypeId::of::<T>()),
22074                ranges,
22075                style,
22076                false,
22077                cx,
22078            )
22079        });
22080        cx.notify();
22081    }
22082
22083    pub fn text_highlights<'a, T: 'static>(
22084        &'a self,
22085        cx: &'a App,
22086    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
22087        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
22088    }
22089
22090    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
22091        let cleared = self
22092            .display_map
22093            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
22094        if cleared {
22095            cx.notify();
22096        }
22097    }
22098
22099    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
22100        (self.read_only(cx) || self.blink_manager.read(cx).visible())
22101            && self.focus_handle.is_focused(window)
22102    }
22103
22104    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
22105        self.show_cursor_when_unfocused = is_enabled;
22106        cx.notify();
22107    }
22108
22109    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
22110        cx.notify();
22111    }
22112
22113    fn on_debug_session_event(
22114        &mut self,
22115        _session: Entity<Session>,
22116        event: &SessionEvent,
22117        cx: &mut Context<Self>,
22118    ) {
22119        if let SessionEvent::InvalidateInlineValue = event {
22120            self.refresh_inline_values(cx);
22121        }
22122    }
22123
22124    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
22125        let Some(project) = self.project.clone() else {
22126            return;
22127        };
22128
22129        if !self.inline_value_cache.enabled {
22130            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
22131            self.splice_inlays(&inlays, Vec::new(), cx);
22132            return;
22133        }
22134
22135        let current_execution_position = self
22136            .highlighted_rows
22137            .get(&TypeId::of::<ActiveDebugLine>())
22138            .and_then(|lines| lines.last().map(|line| line.range.end));
22139
22140        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
22141            let inline_values = editor
22142                .update(cx, |editor, cx| {
22143                    let Some(current_execution_position) = current_execution_position else {
22144                        return Some(Task::ready(Ok(Vec::new())));
22145                    };
22146
22147                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
22148                        let snapshot = buffer.snapshot(cx);
22149
22150                        let excerpt = snapshot.excerpt_containing(
22151                            current_execution_position..current_execution_position,
22152                        )?;
22153
22154                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
22155                    })?;
22156
22157                    let range =
22158                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
22159
22160                    project.inline_values(buffer, range, cx)
22161                })
22162                .ok()
22163                .flatten()?
22164                .await
22165                .context("refreshing debugger inlays")
22166                .log_err()?;
22167
22168            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
22169
22170            for (buffer_id, inline_value) in inline_values
22171                .into_iter()
22172                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
22173            {
22174                buffer_inline_values
22175                    .entry(buffer_id)
22176                    .or_default()
22177                    .push(inline_value);
22178            }
22179
22180            editor
22181                .update(cx, |editor, cx| {
22182                    let snapshot = editor.buffer.read(cx).snapshot(cx);
22183                    let mut new_inlays = Vec::default();
22184
22185                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
22186                        let buffer_id = buffer_snapshot.remote_id();
22187                        buffer_inline_values
22188                            .get(&buffer_id)
22189                            .into_iter()
22190                            .flatten()
22191                            .for_each(|hint| {
22192                                let inlay = Inlay::debugger(
22193                                    post_inc(&mut editor.next_inlay_id),
22194                                    Anchor::in_buffer(excerpt_id, hint.position),
22195                                    hint.text(),
22196                                );
22197                                if !inlay.text().chars().contains(&'\n') {
22198                                    new_inlays.push(inlay);
22199                                }
22200                            });
22201                    }
22202
22203                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22204                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22205
22206                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22207                })
22208                .ok()?;
22209            Some(())
22210        });
22211    }
22212
22213    fn on_buffer_event(
22214        &mut self,
22215        multibuffer: &Entity<MultiBuffer>,
22216        event: &multi_buffer::Event,
22217        window: &mut Window,
22218        cx: &mut Context<Self>,
22219    ) {
22220        match event {
22221            multi_buffer::Event::Edited { edited_buffer } => {
22222                self.scrollbar_marker_state.dirty = true;
22223                self.active_indent_guides_state.dirty = true;
22224                self.refresh_active_diagnostics(cx);
22225                self.refresh_code_actions(window, cx);
22226                self.refresh_single_line_folds(window, cx);
22227                self.refresh_matching_bracket_highlights(window, cx);
22228                if self.has_active_edit_prediction() {
22229                    self.update_visible_edit_prediction(window, cx);
22230                }
22231
22232                if let Some(buffer) = edited_buffer {
22233                    if buffer.read(cx).file().is_none() {
22234                        cx.emit(EditorEvent::TitleChanged);
22235                    }
22236
22237                    if self.project.is_some() {
22238                        let buffer_id = buffer.read(cx).remote_id();
22239                        self.register_buffer(buffer_id, cx);
22240                        self.update_lsp_data(Some(buffer_id), window, cx);
22241                        self.refresh_inlay_hints(
22242                            InlayHintRefreshReason::BufferEdited(buffer_id),
22243                            cx,
22244                        );
22245                    }
22246                }
22247
22248                cx.emit(EditorEvent::BufferEdited);
22249                cx.emit(SearchEvent::MatchesInvalidated);
22250
22251                let Some(project) = &self.project else { return };
22252                let (telemetry, is_via_ssh) = {
22253                    let project = project.read(cx);
22254                    let telemetry = project.client().telemetry().clone();
22255                    let is_via_ssh = project.is_via_remote_server();
22256                    (telemetry, is_via_ssh)
22257                };
22258                telemetry.log_edit_event("editor", is_via_ssh);
22259            }
22260            multi_buffer::Event::ExcerptsAdded {
22261                buffer,
22262                predecessor,
22263                excerpts,
22264            } => {
22265                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22266                let buffer_id = buffer.read(cx).remote_id();
22267                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22268                    && let Some(project) = &self.project
22269                {
22270                    update_uncommitted_diff_for_buffer(
22271                        cx.entity(),
22272                        project,
22273                        [buffer.clone()],
22274                        self.buffer.clone(),
22275                        cx,
22276                    )
22277                    .detach();
22278                }
22279                self.update_lsp_data(Some(buffer_id), window, cx);
22280                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22281                self.colorize_brackets(false, cx);
22282                self.refresh_selected_text_highlights(true, window, cx);
22283                cx.emit(EditorEvent::ExcerptsAdded {
22284                    buffer: buffer.clone(),
22285                    predecessor: *predecessor,
22286                    excerpts: excerpts.clone(),
22287                });
22288            }
22289            multi_buffer::Event::ExcerptsRemoved {
22290                ids,
22291                removed_buffer_ids,
22292            } => {
22293                if let Some(inlay_hints) = &mut self.inlay_hints {
22294                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22295                }
22296                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22297                for buffer_id in removed_buffer_ids {
22298                    self.registered_buffers.remove(buffer_id);
22299                }
22300                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22301                cx.emit(EditorEvent::ExcerptsRemoved {
22302                    ids: ids.clone(),
22303                    removed_buffer_ids: removed_buffer_ids.clone(),
22304                });
22305            }
22306            multi_buffer::Event::ExcerptsEdited {
22307                excerpt_ids,
22308                buffer_ids,
22309            } => {
22310                self.display_map.update(cx, |map, cx| {
22311                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22312                });
22313                cx.emit(EditorEvent::ExcerptsEdited {
22314                    ids: excerpt_ids.clone(),
22315                });
22316            }
22317            multi_buffer::Event::ExcerptsExpanded { ids } => {
22318                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22319                self.refresh_document_highlights(cx);
22320                for id in ids {
22321                    self.fetched_tree_sitter_chunks.remove(id);
22322                }
22323                self.colorize_brackets(false, cx);
22324                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22325            }
22326            multi_buffer::Event::Reparsed(buffer_id) => {
22327                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22328                self.refresh_selected_text_highlights(true, window, cx);
22329                self.colorize_brackets(true, cx);
22330                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22331
22332                cx.emit(EditorEvent::Reparsed(*buffer_id));
22333            }
22334            multi_buffer::Event::DiffHunksToggled => {
22335                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22336            }
22337            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22338                if !is_fresh_language {
22339                    self.registered_buffers.remove(&buffer_id);
22340                }
22341                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22342                cx.emit(EditorEvent::Reparsed(*buffer_id));
22343                cx.notify();
22344            }
22345            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22346            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22347            multi_buffer::Event::FileHandleChanged
22348            | multi_buffer::Event::Reloaded
22349            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22350            multi_buffer::Event::DiagnosticsUpdated => {
22351                self.update_diagnostics_state(window, cx);
22352            }
22353            _ => {}
22354        };
22355    }
22356
22357    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22358        if !self.diagnostics_enabled() {
22359            return;
22360        }
22361        self.refresh_active_diagnostics(cx);
22362        self.refresh_inline_diagnostics(true, window, cx);
22363        self.scrollbar_marker_state.dirty = true;
22364        cx.notify();
22365    }
22366
22367    pub fn start_temporary_diff_override(&mut self) {
22368        self.load_diff_task.take();
22369        self.temporary_diff_override = true;
22370    }
22371
22372    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22373        self.temporary_diff_override = false;
22374        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22375        self.buffer.update(cx, |buffer, cx| {
22376            buffer.set_all_diff_hunks_collapsed(cx);
22377        });
22378
22379        if let Some(project) = self.project.clone() {
22380            self.load_diff_task = Some(
22381                update_uncommitted_diff_for_buffer(
22382                    cx.entity(),
22383                    &project,
22384                    self.buffer.read(cx).all_buffers(),
22385                    self.buffer.clone(),
22386                    cx,
22387                )
22388                .shared(),
22389            );
22390        }
22391    }
22392
22393    fn on_display_map_changed(
22394        &mut self,
22395        _: Entity<DisplayMap>,
22396        _: &mut Window,
22397        cx: &mut Context<Self>,
22398    ) {
22399        cx.notify();
22400    }
22401
22402    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22403        if !self.mode.is_full() {
22404            return None;
22405        }
22406
22407        let theme_settings = theme::ThemeSettings::get_global(cx);
22408        let theme = cx.theme();
22409        let accent_colors = theme.accents().clone();
22410
22411        let accent_overrides = theme_settings
22412            .theme_overrides
22413            .get(theme.name.as_ref())
22414            .map(|theme_style| &theme_style.accents)
22415            .into_iter()
22416            .flatten()
22417            .chain(
22418                theme_settings
22419                    .experimental_theme_overrides
22420                    .as_ref()
22421                    .map(|overrides| &overrides.accents)
22422                    .into_iter()
22423                    .flatten(),
22424            )
22425            .flat_map(|accent| accent.0.clone())
22426            .collect();
22427
22428        Some(AccentData {
22429            colors: accent_colors,
22430            overrides: accent_overrides,
22431        })
22432    }
22433
22434    fn fetch_applicable_language_settings(
22435        &self,
22436        cx: &App,
22437    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22438        if !self.mode.is_full() {
22439            return HashMap::default();
22440        }
22441
22442        self.buffer().read(cx).all_buffers().into_iter().fold(
22443            HashMap::default(),
22444            |mut acc, buffer| {
22445                let buffer = buffer.read(cx);
22446                let language = buffer.language().map(|language| language.name());
22447                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22448                    let file = buffer.file();
22449                    v.insert(language_settings(language, file, cx).into_owned());
22450                }
22451                acc
22452            },
22453        )
22454    }
22455
22456    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22457        let new_language_settings = self.fetch_applicable_language_settings(cx);
22458        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22459        self.applicable_language_settings = new_language_settings;
22460
22461        let new_accents = self.fetch_accent_data(cx);
22462        let accents_changed = new_accents != self.accent_data;
22463        self.accent_data = new_accents;
22464
22465        if self.diagnostics_enabled() {
22466            let new_severity = EditorSettings::get_global(cx)
22467                .diagnostics_max_severity
22468                .unwrap_or(DiagnosticSeverity::Hint);
22469            self.set_max_diagnostics_severity(new_severity, cx);
22470        }
22471        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22472        self.update_edit_prediction_settings(cx);
22473        self.refresh_edit_prediction(true, false, window, cx);
22474        self.refresh_inline_values(cx);
22475        self.refresh_inlay_hints(
22476            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22477                self.selections.newest_anchor().head(),
22478                &self.buffer.read(cx).snapshot(cx),
22479                cx,
22480            )),
22481            cx,
22482        );
22483
22484        let old_cursor_shape = self.cursor_shape;
22485        let old_show_breadcrumbs = self.show_breadcrumbs;
22486
22487        {
22488            let editor_settings = EditorSettings::get_global(cx);
22489            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22490            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22491            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22492            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22493        }
22494
22495        if old_cursor_shape != self.cursor_shape {
22496            cx.emit(EditorEvent::CursorShapeChanged);
22497        }
22498
22499        if old_show_breadcrumbs != self.show_breadcrumbs {
22500            cx.emit(EditorEvent::BreadcrumbsChanged);
22501        }
22502
22503        let project_settings = ProjectSettings::get_global(cx);
22504        self.buffer_serialization = self
22505            .should_serialize_buffer()
22506            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22507
22508        if self.mode.is_full() {
22509            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22510            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22511            if self.show_inline_diagnostics != show_inline_diagnostics {
22512                self.show_inline_diagnostics = show_inline_diagnostics;
22513                self.refresh_inline_diagnostics(false, window, cx);
22514            }
22515
22516            if self.git_blame_inline_enabled != inline_blame_enabled {
22517                self.toggle_git_blame_inline_internal(false, window, cx);
22518            }
22519
22520            let minimap_settings = EditorSettings::get_global(cx).minimap;
22521            if self.minimap_visibility != MinimapVisibility::Disabled {
22522                if self.minimap_visibility.settings_visibility()
22523                    != minimap_settings.minimap_enabled()
22524                {
22525                    self.set_minimap_visibility(
22526                        MinimapVisibility::for_mode(self.mode(), cx),
22527                        window,
22528                        cx,
22529                    );
22530                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22531                    minimap_entity.update(cx, |minimap_editor, cx| {
22532                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22533                    })
22534                }
22535            }
22536
22537            if language_settings_changed || accents_changed {
22538                self.colorize_brackets(true, cx);
22539            }
22540
22541            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22542                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22543            }) {
22544                if !inlay_splice.is_empty() {
22545                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22546                }
22547                self.refresh_colors_for_visible_range(None, window, cx);
22548            }
22549        }
22550
22551        cx.notify();
22552    }
22553
22554    pub fn set_searchable(&mut self, searchable: bool) {
22555        self.searchable = searchable;
22556    }
22557
22558    pub fn searchable(&self) -> bool {
22559        self.searchable
22560    }
22561
22562    pub fn open_excerpts_in_split(
22563        &mut self,
22564        _: &OpenExcerptsSplit,
22565        window: &mut Window,
22566        cx: &mut Context<Self>,
22567    ) {
22568        self.open_excerpts_common(None, true, window, cx)
22569    }
22570
22571    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22572        self.open_excerpts_common(None, false, window, cx)
22573    }
22574
22575    fn open_excerpts_common(
22576        &mut self,
22577        jump_data: Option<JumpData>,
22578        split: bool,
22579        window: &mut Window,
22580        cx: &mut Context<Self>,
22581    ) {
22582        let Some(workspace) = self.workspace() else {
22583            cx.propagate();
22584            return;
22585        };
22586
22587        if self.buffer.read(cx).is_singleton() {
22588            cx.propagate();
22589            return;
22590        }
22591
22592        let mut new_selections_by_buffer = HashMap::default();
22593        match &jump_data {
22594            Some(JumpData::MultiBufferPoint {
22595                excerpt_id,
22596                position,
22597                anchor,
22598                line_offset_from_top,
22599            }) => {
22600                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22601                if let Some(buffer) = multi_buffer_snapshot
22602                    .buffer_id_for_excerpt(*excerpt_id)
22603                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22604                {
22605                    let buffer_snapshot = buffer.read(cx).snapshot();
22606                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22607                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22608                    } else {
22609                        buffer_snapshot.clip_point(*position, Bias::Left)
22610                    };
22611                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22612                    new_selections_by_buffer.insert(
22613                        buffer,
22614                        (
22615                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22616                            Some(*line_offset_from_top),
22617                        ),
22618                    );
22619                }
22620            }
22621            Some(JumpData::MultiBufferRow {
22622                row,
22623                line_offset_from_top,
22624            }) => {
22625                let point = MultiBufferPoint::new(row.0, 0);
22626                if let Some((buffer, buffer_point, _)) =
22627                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22628                {
22629                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22630                    new_selections_by_buffer
22631                        .entry(buffer)
22632                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22633                        .0
22634                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22635                }
22636            }
22637            None => {
22638                let selections = self
22639                    .selections
22640                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22641                let multi_buffer = self.buffer.read(cx);
22642                for selection in selections {
22643                    for (snapshot, range, _, anchor) in multi_buffer
22644                        .snapshot(cx)
22645                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22646                    {
22647                        if let Some(anchor) = anchor {
22648                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22649                            else {
22650                                continue;
22651                            };
22652                            let offset = text::ToOffset::to_offset(
22653                                &anchor.text_anchor,
22654                                &buffer_handle.read(cx).snapshot(),
22655                            );
22656                            let range = BufferOffset(offset)..BufferOffset(offset);
22657                            new_selections_by_buffer
22658                                .entry(buffer_handle)
22659                                .or_insert((Vec::new(), None))
22660                                .0
22661                                .push(range)
22662                        } else {
22663                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22664                            else {
22665                                continue;
22666                            };
22667                            new_selections_by_buffer
22668                                .entry(buffer_handle)
22669                                .or_insert((Vec::new(), None))
22670                                .0
22671                                .push(range)
22672                        }
22673                    }
22674                }
22675            }
22676        }
22677
22678        new_selections_by_buffer
22679            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
22680
22681        if new_selections_by_buffer.is_empty() {
22682            return;
22683        }
22684
22685        // We defer the pane interaction because we ourselves are a workspace item
22686        // and activating a new item causes the pane to call a method on us reentrantly,
22687        // which panics if we're on the stack.
22688        window.defer(cx, move |window, cx| {
22689            workspace.update(cx, |workspace, cx| {
22690                let pane = if split {
22691                    workspace.adjacent_pane(window, cx)
22692                } else {
22693                    workspace.active_pane().clone()
22694                };
22695
22696                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22697                    let buffer_read = buffer.read(cx);
22698                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22699                        (true, project::File::from_dyn(Some(file)).is_some())
22700                    } else {
22701                        (false, false)
22702                    };
22703
22704                    // If project file is none workspace.open_project_item will fail to open the excerpt
22705                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22706                    // so we check if there's a tab match in that case first
22707                    let editor = (!has_file || !is_project_file)
22708                        .then(|| {
22709                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22710                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22711                            // Instead, we try to activate the existing editor in the pane first.
22712                            let (editor, pane_item_index, pane_item_id) =
22713                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22714                                    let editor = item.downcast::<Editor>()?;
22715                                    let singleton_buffer =
22716                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22717                                    if singleton_buffer == buffer {
22718                                        Some((editor, i, item.item_id()))
22719                                    } else {
22720                                        None
22721                                    }
22722                                })?;
22723                            pane.update(cx, |pane, cx| {
22724                                pane.activate_item(pane_item_index, true, true, window, cx);
22725                                if !PreviewTabsSettings::get_global(cx)
22726                                    .enable_preview_from_multibuffer
22727                                {
22728                                    pane.unpreview_item_if_preview(pane_item_id);
22729                                }
22730                            });
22731                            Some(editor)
22732                        })
22733                        .flatten()
22734                        .unwrap_or_else(|| {
22735                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22736                                .enable_keep_preview_on_code_navigation;
22737                            let allow_new_preview =
22738                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22739                            workspace.open_project_item::<Self>(
22740                                pane.clone(),
22741                                buffer,
22742                                true,
22743                                true,
22744                                keep_old_preview,
22745                                allow_new_preview,
22746                                window,
22747                                cx,
22748                            )
22749                        });
22750
22751                    editor.update(cx, |editor, cx| {
22752                        if has_file && !is_project_file {
22753                            editor.set_read_only(true);
22754                        }
22755                        let autoscroll = match scroll_offset {
22756                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22757                            None => Autoscroll::newest(),
22758                        };
22759                        let nav_history = editor.nav_history.take();
22760                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22761                        let Some((&excerpt_id, _, buffer_snapshot)) =
22762                            multibuffer_snapshot.as_singleton()
22763                        else {
22764                            return;
22765                        };
22766                        editor.change_selections(
22767                            SelectionEffects::scroll(autoscroll),
22768                            window,
22769                            cx,
22770                            |s| {
22771                                s.select_ranges(ranges.into_iter().map(|range| {
22772                                    let range = buffer_snapshot.anchor_before(range.start)
22773                                        ..buffer_snapshot.anchor_after(range.end);
22774                                    multibuffer_snapshot
22775                                        .anchor_range_in_excerpt(excerpt_id, range)
22776                                        .unwrap()
22777                                }));
22778                            },
22779                        );
22780                        editor.nav_history = nav_history;
22781                    });
22782                }
22783            })
22784        });
22785    }
22786
22787    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22788        let snapshot = self.buffer.read(cx).read(cx);
22789        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22790        Some(
22791            ranges
22792                .iter()
22793                .map(move |range| {
22794                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22795                })
22796                .collect(),
22797        )
22798    }
22799
22800    fn selection_replacement_ranges(
22801        &self,
22802        range: Range<MultiBufferOffsetUtf16>,
22803        cx: &mut App,
22804    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22805        let selections = self
22806            .selections
22807            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22808        let newest_selection = selections
22809            .iter()
22810            .max_by_key(|selection| selection.id)
22811            .unwrap();
22812        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22813        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22814        let snapshot = self.buffer.read(cx).read(cx);
22815        selections
22816            .into_iter()
22817            .map(|mut selection| {
22818                selection.start.0.0 =
22819                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22820                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22821                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22822                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22823            })
22824            .collect()
22825    }
22826
22827    fn report_editor_event(
22828        &self,
22829        reported_event: ReportEditorEvent,
22830        file_extension: Option<String>,
22831        cx: &App,
22832    ) {
22833        if cfg!(any(test, feature = "test-support")) {
22834            return;
22835        }
22836
22837        let Some(project) = &self.project else { return };
22838
22839        // If None, we are in a file without an extension
22840        let file = self
22841            .buffer
22842            .read(cx)
22843            .as_singleton()
22844            .and_then(|b| b.read(cx).file());
22845        let file_extension = file_extension.or(file
22846            .as_ref()
22847            .and_then(|file| Path::new(file.file_name(cx)).extension())
22848            .and_then(|e| e.to_str())
22849            .map(|a| a.to_string()));
22850
22851        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22852            .map(|vim_mode| vim_mode.0)
22853            .unwrap_or(false);
22854
22855        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22856        let copilot_enabled = edit_predictions_provider
22857            == language::language_settings::EditPredictionProvider::Copilot;
22858        let copilot_enabled_for_language = self
22859            .buffer
22860            .read(cx)
22861            .language_settings(cx)
22862            .show_edit_predictions;
22863
22864        let project = project.read(cx);
22865        let event_type = reported_event.event_type();
22866
22867        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22868            telemetry::event!(
22869                event_type,
22870                type = if auto_saved {"autosave"} else {"manual"},
22871                file_extension,
22872                vim_mode,
22873                copilot_enabled,
22874                copilot_enabled_for_language,
22875                edit_predictions_provider,
22876                is_via_ssh = project.is_via_remote_server(),
22877            );
22878        } else {
22879            telemetry::event!(
22880                event_type,
22881                file_extension,
22882                vim_mode,
22883                copilot_enabled,
22884                copilot_enabled_for_language,
22885                edit_predictions_provider,
22886                is_via_ssh = project.is_via_remote_server(),
22887            );
22888        };
22889    }
22890
22891    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22892    /// with each line being an array of {text, highlight} objects.
22893    fn copy_highlight_json(
22894        &mut self,
22895        _: &CopyHighlightJson,
22896        window: &mut Window,
22897        cx: &mut Context<Self>,
22898    ) {
22899        #[derive(Serialize)]
22900        struct Chunk<'a> {
22901            text: String,
22902            highlight: Option<&'a str>,
22903        }
22904
22905        let snapshot = self.buffer.read(cx).snapshot(cx);
22906        let range = self
22907            .selected_text_range(false, window, cx)
22908            .and_then(|selection| {
22909                if selection.range.is_empty() {
22910                    None
22911                } else {
22912                    Some(
22913                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22914                            selection.range.start,
22915                        )))
22916                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22917                                selection.range.end,
22918                            ))),
22919                    )
22920                }
22921            })
22922            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22923
22924        let chunks = snapshot.chunks(range, true);
22925        let mut lines = Vec::new();
22926        let mut line: VecDeque<Chunk> = VecDeque::new();
22927
22928        let Some(style) = self.style.as_ref() else {
22929            return;
22930        };
22931
22932        for chunk in chunks {
22933            let highlight = chunk
22934                .syntax_highlight_id
22935                .and_then(|id| id.name(&style.syntax));
22936            let mut chunk_lines = chunk.text.split('\n').peekable();
22937            while let Some(text) = chunk_lines.next() {
22938                let mut merged_with_last_token = false;
22939                if let Some(last_token) = line.back_mut()
22940                    && last_token.highlight == highlight
22941                {
22942                    last_token.text.push_str(text);
22943                    merged_with_last_token = true;
22944                }
22945
22946                if !merged_with_last_token {
22947                    line.push_back(Chunk {
22948                        text: text.into(),
22949                        highlight,
22950                    });
22951                }
22952
22953                if chunk_lines.peek().is_some() {
22954                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22955                        line.pop_front();
22956                    }
22957                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22958                        line.pop_back();
22959                    }
22960
22961                    lines.push(mem::take(&mut line));
22962                }
22963            }
22964        }
22965
22966        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22967            return;
22968        };
22969        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22970    }
22971
22972    pub fn open_context_menu(
22973        &mut self,
22974        _: &OpenContextMenu,
22975        window: &mut Window,
22976        cx: &mut Context<Self>,
22977    ) {
22978        self.request_autoscroll(Autoscroll::newest(), cx);
22979        let position = self
22980            .selections
22981            .newest_display(&self.display_snapshot(cx))
22982            .start;
22983        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22984    }
22985
22986    pub fn replay_insert_event(
22987        &mut self,
22988        text: &str,
22989        relative_utf16_range: Option<Range<isize>>,
22990        window: &mut Window,
22991        cx: &mut Context<Self>,
22992    ) {
22993        if !self.input_enabled {
22994            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22995            return;
22996        }
22997        if let Some(relative_utf16_range) = relative_utf16_range {
22998            let selections = self
22999                .selections
23000                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
23001            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23002                let new_ranges = selections.into_iter().map(|range| {
23003                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
23004                        range
23005                            .head()
23006                            .0
23007                            .0
23008                            .saturating_add_signed(relative_utf16_range.start),
23009                    ));
23010                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
23011                        range
23012                            .head()
23013                            .0
23014                            .0
23015                            .saturating_add_signed(relative_utf16_range.end),
23016                    ));
23017                    start..end
23018                });
23019                s.select_ranges(new_ranges);
23020            });
23021        }
23022
23023        self.handle_input(text, window, cx);
23024    }
23025
23026    pub fn is_focused(&self, window: &Window) -> bool {
23027        self.focus_handle.is_focused(window)
23028    }
23029
23030    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23031        cx.emit(EditorEvent::Focused);
23032
23033        if let Some(descendant) = self
23034            .last_focused_descendant
23035            .take()
23036            .and_then(|descendant| descendant.upgrade())
23037        {
23038            window.focus(&descendant, cx);
23039        } else {
23040            if let Some(blame) = self.blame.as_ref() {
23041                blame.update(cx, GitBlame::focus)
23042            }
23043
23044            self.blink_manager.update(cx, BlinkManager::enable);
23045            self.show_cursor_names(window, cx);
23046            self.buffer.update(cx, |buffer, cx| {
23047                buffer.finalize_last_transaction(cx);
23048                if self.leader_id.is_none() {
23049                    buffer.set_active_selections(
23050                        &self.selections.disjoint_anchors_arc(),
23051                        self.selections.line_mode(),
23052                        self.cursor_shape,
23053                        cx,
23054                    );
23055                }
23056            });
23057
23058            if let Some(position_map) = self.last_position_map.clone() {
23059                EditorElement::mouse_moved(
23060                    self,
23061                    &MouseMoveEvent {
23062                        position: window.mouse_position(),
23063                        pressed_button: None,
23064                        modifiers: window.modifiers(),
23065                    },
23066                    &position_map,
23067                    window,
23068                    cx,
23069                );
23070            }
23071        }
23072    }
23073
23074    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23075        cx.emit(EditorEvent::FocusedIn)
23076    }
23077
23078    fn handle_focus_out(
23079        &mut self,
23080        event: FocusOutEvent,
23081        _window: &mut Window,
23082        cx: &mut Context<Self>,
23083    ) {
23084        if event.blurred != self.focus_handle {
23085            self.last_focused_descendant = Some(event.blurred);
23086        }
23087        self.selection_drag_state = SelectionDragState::None;
23088        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
23089    }
23090
23091    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23092        self.blink_manager.update(cx, BlinkManager::disable);
23093        self.buffer
23094            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
23095
23096        if let Some(blame) = self.blame.as_ref() {
23097            blame.update(cx, GitBlame::blur)
23098        }
23099        if !self.hover_state.focused(window, cx) {
23100            hide_hover(self, cx);
23101        }
23102        if !self
23103            .context_menu
23104            .borrow()
23105            .as_ref()
23106            .is_some_and(|context_menu| context_menu.focused(window, cx))
23107        {
23108            self.hide_context_menu(window, cx);
23109        }
23110        self.take_active_edit_prediction(cx);
23111        cx.emit(EditorEvent::Blurred);
23112        cx.notify();
23113    }
23114
23115    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23116        let mut pending: String = window
23117            .pending_input_keystrokes()
23118            .into_iter()
23119            .flatten()
23120            .filter_map(|keystroke| keystroke.key_char.clone())
23121            .collect();
23122
23123        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
23124            pending = "".to_string();
23125        }
23126
23127        let existing_pending = self
23128            .text_highlights::<PendingInput>(cx)
23129            .map(|(_, ranges)| ranges.to_vec());
23130        if existing_pending.is_none() && pending.is_empty() {
23131            return;
23132        }
23133        let transaction =
23134            self.transact(window, cx, |this, window, cx| {
23135                let selections = this
23136                    .selections
23137                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
23138                let edits = selections
23139                    .iter()
23140                    .map(|selection| (selection.end..selection.end, pending.clone()));
23141                this.edit(edits, cx);
23142                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23143                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
23144                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
23145                    }));
23146                });
23147                if let Some(existing_ranges) = existing_pending {
23148                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
23149                    this.edit(edits, cx);
23150                }
23151            });
23152
23153        let snapshot = self.snapshot(window, cx);
23154        let ranges = self
23155            .selections
23156            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
23157            .into_iter()
23158            .map(|selection| {
23159                snapshot.buffer_snapshot().anchor_after(selection.end)
23160                    ..snapshot
23161                        .buffer_snapshot()
23162                        .anchor_before(selection.end + pending.len())
23163            })
23164            .collect();
23165
23166        if pending.is_empty() {
23167            self.clear_highlights::<PendingInput>(cx);
23168        } else {
23169            self.highlight_text::<PendingInput>(
23170                ranges,
23171                HighlightStyle {
23172                    underline: Some(UnderlineStyle {
23173                        thickness: px(1.),
23174                        color: None,
23175                        wavy: false,
23176                    }),
23177                    ..Default::default()
23178                },
23179                cx,
23180            );
23181        }
23182
23183        self.ime_transaction = self.ime_transaction.or(transaction);
23184        if let Some(transaction) = self.ime_transaction {
23185            self.buffer.update(cx, |buffer, cx| {
23186                buffer.group_until_transaction(transaction, cx);
23187            });
23188        }
23189
23190        if self.text_highlights::<PendingInput>(cx).is_none() {
23191            self.ime_transaction.take();
23192        }
23193    }
23194
23195    pub fn register_action_renderer(
23196        &mut self,
23197        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23198    ) -> Subscription {
23199        let id = self.next_editor_action_id.post_inc();
23200        self.editor_actions
23201            .borrow_mut()
23202            .insert(id, Box::new(listener));
23203
23204        let editor_actions = self.editor_actions.clone();
23205        Subscription::new(move || {
23206            editor_actions.borrow_mut().remove(&id);
23207        })
23208    }
23209
23210    pub fn register_action<A: Action>(
23211        &mut self,
23212        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23213    ) -> Subscription {
23214        let id = self.next_editor_action_id.post_inc();
23215        let listener = Arc::new(listener);
23216        self.editor_actions.borrow_mut().insert(
23217            id,
23218            Box::new(move |_, window, _| {
23219                let listener = listener.clone();
23220                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23221                    let action = action.downcast_ref().unwrap();
23222                    if phase == DispatchPhase::Bubble {
23223                        listener(action, window, cx)
23224                    }
23225                })
23226            }),
23227        );
23228
23229        let editor_actions = self.editor_actions.clone();
23230        Subscription::new(move || {
23231            editor_actions.borrow_mut().remove(&id);
23232        })
23233    }
23234
23235    pub fn file_header_size(&self) -> u32 {
23236        FILE_HEADER_HEIGHT
23237    }
23238
23239    pub fn restore(
23240        &mut self,
23241        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23242        window: &mut Window,
23243        cx: &mut Context<Self>,
23244    ) {
23245        self.buffer().update(cx, |multi_buffer, cx| {
23246            for (buffer_id, changes) in revert_changes {
23247                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23248                    buffer.update(cx, |buffer, cx| {
23249                        buffer.edit(
23250                            changes
23251                                .into_iter()
23252                                .map(|(range, text)| (range, text.to_string())),
23253                            None,
23254                            cx,
23255                        );
23256                    });
23257                }
23258            }
23259        });
23260        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23261            selections.refresh()
23262        });
23263    }
23264
23265    pub fn to_pixel_point(
23266        &mut self,
23267        source: multi_buffer::Anchor,
23268        editor_snapshot: &EditorSnapshot,
23269        window: &mut Window,
23270        cx: &App,
23271    ) -> Option<gpui::Point<Pixels>> {
23272        let source_point = source.to_display_point(editor_snapshot);
23273        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23274    }
23275
23276    pub fn display_to_pixel_point(
23277        &mut self,
23278        source: DisplayPoint,
23279        editor_snapshot: &EditorSnapshot,
23280        window: &mut Window,
23281        cx: &App,
23282    ) -> Option<gpui::Point<Pixels>> {
23283        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23284        let text_layout_details = self.text_layout_details(window);
23285        let scroll_top = text_layout_details
23286            .scroll_anchor
23287            .scroll_position(editor_snapshot)
23288            .y;
23289
23290        if source.row().as_f64() < scroll_top.floor() {
23291            return None;
23292        }
23293        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23294        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23295        Some(gpui::Point::new(source_x, source_y))
23296    }
23297
23298    pub fn has_visible_completions_menu(&self) -> bool {
23299        !self.edit_prediction_preview_is_active()
23300            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23301                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23302            })
23303    }
23304
23305    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23306        if self.mode.is_minimap() {
23307            return;
23308        }
23309        self.addons
23310            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23311    }
23312
23313    pub fn unregister_addon<T: Addon>(&mut self) {
23314        self.addons.remove(&std::any::TypeId::of::<T>());
23315    }
23316
23317    pub fn addon<T: Addon>(&self) -> Option<&T> {
23318        let type_id = std::any::TypeId::of::<T>();
23319        self.addons
23320            .get(&type_id)
23321            .and_then(|item| item.to_any().downcast_ref::<T>())
23322    }
23323
23324    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23325        let type_id = std::any::TypeId::of::<T>();
23326        self.addons
23327            .get_mut(&type_id)
23328            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23329    }
23330
23331    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23332        let text_layout_details = self.text_layout_details(window);
23333        let style = &text_layout_details.editor_style;
23334        let font_id = window.text_system().resolve_font(&style.text.font());
23335        let font_size = style.text.font_size.to_pixels(window.rem_size());
23336        let line_height = style.text.line_height_in_pixels(window.rem_size());
23337        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23338        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23339
23340        CharacterDimensions {
23341            em_width,
23342            em_advance,
23343            line_height,
23344        }
23345    }
23346
23347    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23348        self.load_diff_task.clone()
23349    }
23350
23351    fn read_metadata_from_db(
23352        &mut self,
23353        item_id: u64,
23354        workspace_id: WorkspaceId,
23355        window: &mut Window,
23356        cx: &mut Context<Editor>,
23357    ) {
23358        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23359            && !self.mode.is_minimap()
23360            && WorkspaceSettings::get(None, cx).restore_on_startup
23361                != RestoreOnStartupBehavior::EmptyTab
23362        {
23363            let buffer_snapshot = OnceCell::new();
23364
23365            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23366                && !folds.is_empty()
23367            {
23368                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23369                let snapshot_len = snapshot.len().0;
23370
23371                // Helper: search for fingerprint in buffer, return offset if found
23372                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
23373                    // Ensure we start at a character boundary (defensive)
23374                    let search_start = snapshot
23375                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
23376                        .0;
23377                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
23378
23379                    let mut byte_offset = search_start;
23380                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
23381                        if byte_offset > search_end {
23382                            break;
23383                        }
23384                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
23385                            return Some(byte_offset);
23386                        }
23387                        byte_offset += ch.len_utf8();
23388                    }
23389                    None
23390                };
23391
23392                // Track search position to handle duplicate fingerprints correctly.
23393                // Folds are stored in document order, so we advance after each match.
23394                let mut search_start = 0usize;
23395
23396                let valid_folds: Vec<_> = folds
23397                    .into_iter()
23398                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
23399                        // Skip folds without fingerprints (old data before migration)
23400                        let sfp = start_fp?;
23401                        let efp = end_fp?;
23402                        let efp_len = efp.len();
23403
23404                        // Fast path: check if fingerprints match at stored offsets
23405                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
23406                        let start_matches = stored_start < snapshot_len
23407                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
23408                        let efp_check_pos = stored_end.saturating_sub(efp_len);
23409                        let end_matches = efp_check_pos >= stored_start
23410                            && stored_end <= snapshot_len
23411                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
23412
23413                        let (new_start, new_end) = if start_matches && end_matches {
23414                            // Offsets unchanged, use stored values
23415                            (stored_start, stored_end)
23416                        } else if sfp == efp {
23417                            // Short fold: identical fingerprints can only match once per search
23418                            // Use stored fold length to compute new_end
23419                            let new_start = find_fingerprint(&sfp, search_start)?;
23420                            let fold_len = stored_end - stored_start;
23421                            let new_end = new_start + fold_len;
23422                            (new_start, new_end)
23423                        } else {
23424                            // Slow path: search for fingerprints in buffer
23425                            let new_start = find_fingerprint(&sfp, search_start)?;
23426                            // Search for end_fp after start, then add efp_len to get actual fold end
23427                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
23428                            let new_end = efp_pos + efp_len;
23429                            (new_start, new_end)
23430                        };
23431
23432                        // Advance search position for next fold
23433                        search_start = new_end;
23434
23435                        // Validate fold makes sense (end must be after start)
23436                        if new_end <= new_start {
23437                            return None;
23438                        }
23439
23440                        Some(
23441                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
23442                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
23443                        )
23444                    })
23445                    .collect();
23446
23447                if !valid_folds.is_empty() {
23448                    self.fold_ranges(valid_folds, false, window, cx);
23449
23450                    // Migrate folds to current entity_id before workspace cleanup runs.
23451                    // Entity IDs change between sessions, but workspace cleanup deletes
23452                    // old editor rows (cascading to folds) based on current entity IDs.
23453                    let new_editor_id = cx.entity().entity_id().as_u64() as ItemId;
23454                    if new_editor_id != item_id {
23455                        cx.spawn(async move |_, _| {
23456                            DB.migrate_editor_folds(item_id, new_editor_id, workspace_id)
23457                                .await
23458                                .log_err();
23459                        })
23460                        .detach();
23461                    }
23462                }
23463            }
23464
23465            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23466                && !selections.is_empty()
23467            {
23468                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23469                // skip adding the initial selection to selection history
23470                self.selection_history.mode = SelectionHistoryMode::Skipping;
23471                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23472                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23473                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23474                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23475                    }));
23476                });
23477                self.selection_history.mode = SelectionHistoryMode::Normal;
23478            };
23479        }
23480
23481        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23482    }
23483
23484    fn update_lsp_data(
23485        &mut self,
23486        for_buffer: Option<BufferId>,
23487        window: &mut Window,
23488        cx: &mut Context<'_, Self>,
23489    ) {
23490        self.pull_diagnostics(for_buffer, window, cx);
23491        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23492    }
23493
23494    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23495        if self.ignore_lsp_data() {
23496            return;
23497        }
23498        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23499            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23500        }
23501    }
23502
23503    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23504        if self.ignore_lsp_data() {
23505            return;
23506        }
23507
23508        if !self.registered_buffers.contains_key(&buffer_id)
23509            && let Some(project) = self.project.as_ref()
23510        {
23511            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23512                project.update(cx, |project, cx| {
23513                    self.registered_buffers.insert(
23514                        buffer_id,
23515                        project.register_buffer_with_language_servers(&buffer, cx),
23516                    );
23517                });
23518            } else {
23519                self.registered_buffers.remove(&buffer_id);
23520            }
23521        }
23522    }
23523
23524    fn ignore_lsp_data(&self) -> bool {
23525        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23526        // skip any LSP updates for it.
23527        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23528    }
23529
23530    fn create_style(&self, cx: &App) -> EditorStyle {
23531        let settings = ThemeSettings::get_global(cx);
23532
23533        let mut text_style = match self.mode {
23534            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23535                color: cx.theme().colors().editor_foreground,
23536                font_family: settings.ui_font.family.clone(),
23537                font_features: settings.ui_font.features.clone(),
23538                font_fallbacks: settings.ui_font.fallbacks.clone(),
23539                font_size: rems(0.875).into(),
23540                font_weight: settings.ui_font.weight,
23541                line_height: relative(settings.buffer_line_height.value()),
23542                ..Default::default()
23543            },
23544            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23545                color: cx.theme().colors().editor_foreground,
23546                font_family: settings.buffer_font.family.clone(),
23547                font_features: settings.buffer_font.features.clone(),
23548                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23549                font_size: settings.buffer_font_size(cx).into(),
23550                font_weight: settings.buffer_font.weight,
23551                line_height: relative(settings.buffer_line_height.value()),
23552                ..Default::default()
23553            },
23554        };
23555        if let Some(text_style_refinement) = &self.text_style_refinement {
23556            text_style.refine(text_style_refinement)
23557        }
23558
23559        let background = match self.mode {
23560            EditorMode::SingleLine => cx.theme().system().transparent,
23561            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23562            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23563            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23564        };
23565
23566        EditorStyle {
23567            background,
23568            border: cx.theme().colors().border,
23569            local_player: cx.theme().players().local(),
23570            text: text_style,
23571            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23572            syntax: cx.theme().syntax().clone(),
23573            status: cx.theme().status().clone(),
23574            inlay_hints_style: make_inlay_hints_style(cx),
23575            edit_prediction_styles: make_suggestion_styles(cx),
23576            unnecessary_code_fade: settings.unnecessary_code_fade,
23577            show_underlines: self.diagnostics_enabled(),
23578        }
23579    }
23580    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
23581        let cursor = self.selections.newest_anchor().head();
23582        let multibuffer = self.buffer().read(cx);
23583        let is_singleton = multibuffer.is_singleton();
23584        let (buffer_id, symbols) = multibuffer
23585            .read(cx)
23586            .symbols_containing(cursor, Some(variant.syntax()))?;
23587        let buffer = multibuffer.buffer(buffer_id)?;
23588
23589        let buffer = buffer.read(cx);
23590        let settings = ThemeSettings::get_global(cx);
23591        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
23592        let mut breadcrumbs = if is_singleton {
23593            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
23594                buffer
23595                    .snapshot()
23596                    .resolve_file_path(
23597                        self.project
23598                            .as_ref()
23599                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
23600                            .unwrap_or_default(),
23601                        cx,
23602                    )
23603                    .unwrap_or_else(|| {
23604                        if multibuffer.is_singleton() {
23605                            multibuffer.title(cx).to_string()
23606                        } else {
23607                            "untitled".to_string()
23608                        }
23609                    })
23610            });
23611            vec![BreadcrumbText {
23612                text,
23613                highlights: None,
23614                font: Some(settings.buffer_font.clone()),
23615            }]
23616        } else {
23617            vec![]
23618        };
23619
23620        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
23621            text: symbol.text,
23622            highlights: Some(symbol.highlight_ranges),
23623            font: Some(settings.buffer_font.clone()),
23624        }));
23625        Some(breadcrumbs)
23626    }
23627}
23628
23629fn edit_for_markdown_paste<'a>(
23630    buffer: &MultiBufferSnapshot,
23631    range: Range<MultiBufferOffset>,
23632    to_insert: &'a str,
23633    url: Option<url::Url>,
23634) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23635    if url.is_none() {
23636        return (range, Cow::Borrowed(to_insert));
23637    };
23638
23639    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23640
23641    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23642        Cow::Borrowed(to_insert)
23643    } else {
23644        Cow::Owned(format!("[{old_text}]({to_insert})"))
23645    };
23646    (range, new_text)
23647}
23648
23649fn process_completion_for_edit(
23650    completion: &Completion,
23651    intent: CompletionIntent,
23652    buffer: &Entity<Buffer>,
23653    cursor_position: &text::Anchor,
23654    cx: &mut Context<Editor>,
23655) -> CompletionEdit {
23656    let buffer = buffer.read(cx);
23657    let buffer_snapshot = buffer.snapshot();
23658    let (snippet, new_text) = if completion.is_snippet() {
23659        let mut snippet_source = completion.new_text.clone();
23660        // Workaround for typescript language server issues so that methods don't expand within
23661        // strings and functions with type expressions. The previous point is used because the query
23662        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23663        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23664        let previous_point = if previous_point.column > 0 {
23665            cursor_position.to_previous_offset(&buffer_snapshot)
23666        } else {
23667            cursor_position.to_offset(&buffer_snapshot)
23668        };
23669        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23670            && scope.prefers_label_for_snippet_in_completion()
23671            && let Some(label) = completion.label()
23672            && matches!(
23673                completion.kind(),
23674                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23675            )
23676        {
23677            snippet_source = label;
23678        }
23679        match Snippet::parse(&snippet_source).log_err() {
23680            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23681            None => (None, completion.new_text.clone()),
23682        }
23683    } else {
23684        (None, completion.new_text.clone())
23685    };
23686
23687    let mut range_to_replace = {
23688        let replace_range = &completion.replace_range;
23689        if let CompletionSource::Lsp {
23690            insert_range: Some(insert_range),
23691            ..
23692        } = &completion.source
23693        {
23694            debug_assert_eq!(
23695                insert_range.start, replace_range.start,
23696                "insert_range and replace_range should start at the same position"
23697            );
23698            debug_assert!(
23699                insert_range
23700                    .start
23701                    .cmp(cursor_position, &buffer_snapshot)
23702                    .is_le(),
23703                "insert_range should start before or at cursor position"
23704            );
23705            debug_assert!(
23706                replace_range
23707                    .start
23708                    .cmp(cursor_position, &buffer_snapshot)
23709                    .is_le(),
23710                "replace_range should start before or at cursor position"
23711            );
23712
23713            let should_replace = match intent {
23714                CompletionIntent::CompleteWithInsert => false,
23715                CompletionIntent::CompleteWithReplace => true,
23716                CompletionIntent::Complete | CompletionIntent::Compose => {
23717                    let insert_mode =
23718                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23719                            .completions
23720                            .lsp_insert_mode;
23721                    match insert_mode {
23722                        LspInsertMode::Insert => false,
23723                        LspInsertMode::Replace => true,
23724                        LspInsertMode::ReplaceSubsequence => {
23725                            let mut text_to_replace = buffer.chars_for_range(
23726                                buffer.anchor_before(replace_range.start)
23727                                    ..buffer.anchor_after(replace_range.end),
23728                            );
23729                            let mut current_needle = text_to_replace.next();
23730                            for haystack_ch in completion.label.text.chars() {
23731                                if let Some(needle_ch) = current_needle
23732                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23733                                {
23734                                    current_needle = text_to_replace.next();
23735                                }
23736                            }
23737                            current_needle.is_none()
23738                        }
23739                        LspInsertMode::ReplaceSuffix => {
23740                            if replace_range
23741                                .end
23742                                .cmp(cursor_position, &buffer_snapshot)
23743                                .is_gt()
23744                            {
23745                                let range_after_cursor = *cursor_position..replace_range.end;
23746                                let text_after_cursor = buffer
23747                                    .text_for_range(
23748                                        buffer.anchor_before(range_after_cursor.start)
23749                                            ..buffer.anchor_after(range_after_cursor.end),
23750                                    )
23751                                    .collect::<String>()
23752                                    .to_ascii_lowercase();
23753                                completion
23754                                    .label
23755                                    .text
23756                                    .to_ascii_lowercase()
23757                                    .ends_with(&text_after_cursor)
23758                            } else {
23759                                true
23760                            }
23761                        }
23762                    }
23763                }
23764            };
23765
23766            if should_replace {
23767                replace_range.clone()
23768            } else {
23769                insert_range.clone()
23770            }
23771        } else {
23772            replace_range.clone()
23773        }
23774    };
23775
23776    if range_to_replace
23777        .end
23778        .cmp(cursor_position, &buffer_snapshot)
23779        .is_lt()
23780    {
23781        range_to_replace.end = *cursor_position;
23782    }
23783
23784    let replace_range = range_to_replace.to_offset(buffer);
23785    CompletionEdit {
23786        new_text,
23787        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23788        snippet,
23789    }
23790}
23791
23792struct CompletionEdit {
23793    new_text: String,
23794    replace_range: Range<BufferOffset>,
23795    snippet: Option<Snippet>,
23796}
23797
23798fn comment_delimiter_for_newline(
23799    start_point: &Point,
23800    buffer: &MultiBufferSnapshot,
23801    language: &LanguageScope,
23802) -> Option<Arc<str>> {
23803    let delimiters = language.line_comment_prefixes();
23804    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23805    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23806
23807    let num_of_whitespaces = snapshot
23808        .chars_for_range(range.clone())
23809        .take_while(|c| c.is_whitespace())
23810        .count();
23811    let comment_candidate = snapshot
23812        .chars_for_range(range.clone())
23813        .skip(num_of_whitespaces)
23814        .take(max_len_of_delimiter)
23815        .collect::<String>();
23816    let (delimiter, trimmed_len) = delimiters
23817        .iter()
23818        .filter_map(|delimiter| {
23819            let prefix = delimiter.trim_end();
23820            if comment_candidate.starts_with(prefix) {
23821                Some((delimiter, prefix.len()))
23822            } else {
23823                None
23824            }
23825        })
23826        .max_by_key(|(_, len)| *len)?;
23827
23828    if let Some(BlockCommentConfig {
23829        start: block_start, ..
23830    }) = language.block_comment()
23831    {
23832        let block_start_trimmed = block_start.trim_end();
23833        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23834            let line_content = snapshot
23835                .chars_for_range(range)
23836                .skip(num_of_whitespaces)
23837                .take(block_start_trimmed.len())
23838                .collect::<String>();
23839
23840            if line_content.starts_with(block_start_trimmed) {
23841                return None;
23842            }
23843        }
23844    }
23845
23846    let cursor_is_placed_after_comment_marker =
23847        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23848    if cursor_is_placed_after_comment_marker {
23849        Some(delimiter.clone())
23850    } else {
23851        None
23852    }
23853}
23854
23855fn documentation_delimiter_for_newline(
23856    start_point: &Point,
23857    buffer: &MultiBufferSnapshot,
23858    language: &LanguageScope,
23859    newline_config: &mut NewlineConfig,
23860) -> Option<Arc<str>> {
23861    let BlockCommentConfig {
23862        start: start_tag,
23863        end: end_tag,
23864        prefix: delimiter,
23865        tab_size: len,
23866    } = language.documentation_comment()?;
23867    let is_within_block_comment = buffer
23868        .language_scope_at(*start_point)
23869        .is_some_and(|scope| scope.override_name() == Some("comment"));
23870    if !is_within_block_comment {
23871        return None;
23872    }
23873
23874    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23875
23876    let num_of_whitespaces = snapshot
23877        .chars_for_range(range.clone())
23878        .take_while(|c| c.is_whitespace())
23879        .count();
23880
23881    // 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.
23882    let column = start_point.column;
23883    let cursor_is_after_start_tag = {
23884        let start_tag_len = start_tag.len();
23885        let start_tag_line = snapshot
23886            .chars_for_range(range.clone())
23887            .skip(num_of_whitespaces)
23888            .take(start_tag_len)
23889            .collect::<String>();
23890        if start_tag_line.starts_with(start_tag.as_ref()) {
23891            num_of_whitespaces + start_tag_len <= column as usize
23892        } else {
23893            false
23894        }
23895    };
23896
23897    let cursor_is_after_delimiter = {
23898        let delimiter_trim = delimiter.trim_end();
23899        let delimiter_line = snapshot
23900            .chars_for_range(range.clone())
23901            .skip(num_of_whitespaces)
23902            .take(delimiter_trim.len())
23903            .collect::<String>();
23904        if delimiter_line.starts_with(delimiter_trim) {
23905            num_of_whitespaces + delimiter_trim.len() <= column as usize
23906        } else {
23907            false
23908        }
23909    };
23910
23911    let mut needs_extra_line = false;
23912    let mut extra_line_additional_indent = IndentSize::spaces(0);
23913
23914    let cursor_is_before_end_tag_if_exists = {
23915        let mut char_position = 0u32;
23916        let mut end_tag_offset = None;
23917
23918        'outer: for chunk in snapshot.text_for_range(range) {
23919            if let Some(byte_pos) = chunk.find(&**end_tag) {
23920                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23921                end_tag_offset = Some(char_position + chars_before_match);
23922                break 'outer;
23923            }
23924            char_position += chunk.chars().count() as u32;
23925        }
23926
23927        if let Some(end_tag_offset) = end_tag_offset {
23928            let cursor_is_before_end_tag = column <= end_tag_offset;
23929            if cursor_is_after_start_tag {
23930                if cursor_is_before_end_tag {
23931                    needs_extra_line = true;
23932                }
23933                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23934                if cursor_is_at_start_of_end_tag {
23935                    extra_line_additional_indent.len = *len;
23936                }
23937            }
23938            cursor_is_before_end_tag
23939        } else {
23940            true
23941        }
23942    };
23943
23944    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23945        && cursor_is_before_end_tag_if_exists
23946    {
23947        let additional_indent = if cursor_is_after_start_tag {
23948            IndentSize::spaces(*len)
23949        } else {
23950            IndentSize::spaces(0)
23951        };
23952
23953        *newline_config = NewlineConfig::Newline {
23954            additional_indent,
23955            extra_line_additional_indent: if needs_extra_line {
23956                Some(extra_line_additional_indent)
23957            } else {
23958                None
23959            },
23960            prevent_auto_indent: true,
23961        };
23962        Some(delimiter.clone())
23963    } else {
23964        None
23965    }
23966}
23967
23968const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23969
23970fn list_delimiter_for_newline(
23971    start_point: &Point,
23972    buffer: &MultiBufferSnapshot,
23973    language: &LanguageScope,
23974    newline_config: &mut NewlineConfig,
23975) -> Option<Arc<str>> {
23976    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23977
23978    let num_of_whitespaces = snapshot
23979        .chars_for_range(range.clone())
23980        .take_while(|c| c.is_whitespace())
23981        .count();
23982
23983    let task_list_entries: Vec<_> = language
23984        .task_list()
23985        .into_iter()
23986        .flat_map(|config| {
23987            config
23988                .prefixes
23989                .iter()
23990                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23991        })
23992        .collect();
23993    let unordered_list_entries: Vec<_> = language
23994        .unordered_list()
23995        .iter()
23996        .map(|marker| (marker.as_ref(), marker.as_ref()))
23997        .collect();
23998
23999    let all_entries: Vec<_> = task_list_entries
24000        .into_iter()
24001        .chain(unordered_list_entries)
24002        .collect();
24003
24004    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
24005        let candidate: String = snapshot
24006            .chars_for_range(range.clone())
24007            .skip(num_of_whitespaces)
24008            .take(max_prefix_len)
24009            .collect();
24010
24011        if let Some((prefix, continuation)) = all_entries
24012            .iter()
24013            .filter(|(prefix, _)| candidate.starts_with(*prefix))
24014            .max_by_key(|(prefix, _)| prefix.len())
24015        {
24016            let end_of_prefix = num_of_whitespaces + prefix.len();
24017            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
24018            let has_content_after_marker = snapshot
24019                .chars_for_range(range)
24020                .skip(end_of_prefix)
24021                .any(|c| !c.is_whitespace());
24022
24023            if has_content_after_marker && cursor_is_after_prefix {
24024                return Some((*continuation).into());
24025            }
24026
24027            if start_point.column as usize == end_of_prefix {
24028                if num_of_whitespaces == 0 {
24029                    *newline_config = NewlineConfig::ClearCurrentLine;
24030                } else {
24031                    *newline_config = NewlineConfig::UnindentCurrentLine {
24032                        continuation: (*continuation).into(),
24033                    };
24034                }
24035            }
24036
24037            return None;
24038        }
24039    }
24040
24041    let candidate: String = snapshot
24042        .chars_for_range(range.clone())
24043        .skip(num_of_whitespaces)
24044        .take(ORDERED_LIST_MAX_MARKER_LEN)
24045        .collect();
24046
24047    for ordered_config in language.ordered_list() {
24048        let regex = match Regex::new(&ordered_config.pattern) {
24049            Ok(r) => r,
24050            Err(_) => continue,
24051        };
24052
24053        if let Some(captures) = regex.captures(&candidate) {
24054            let full_match = captures.get(0)?;
24055            let marker_len = full_match.len();
24056            let end_of_prefix = num_of_whitespaces + marker_len;
24057            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
24058
24059            let has_content_after_marker = snapshot
24060                .chars_for_range(range)
24061                .skip(end_of_prefix)
24062                .any(|c| !c.is_whitespace());
24063
24064            if has_content_after_marker && cursor_is_after_prefix {
24065                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
24066                let continuation = ordered_config
24067                    .format
24068                    .replace("{1}", &(number + 1).to_string());
24069                return Some(continuation.into());
24070            }
24071
24072            if start_point.column as usize == end_of_prefix {
24073                let continuation = ordered_config.format.replace("{1}", "1");
24074                if num_of_whitespaces == 0 {
24075                    *newline_config = NewlineConfig::ClearCurrentLine;
24076                } else {
24077                    *newline_config = NewlineConfig::UnindentCurrentLine {
24078                        continuation: continuation.into(),
24079                    };
24080                }
24081            }
24082
24083            return None;
24084        }
24085    }
24086
24087    None
24088}
24089
24090fn is_list_prefix_row(
24091    row: MultiBufferRow,
24092    buffer: &MultiBufferSnapshot,
24093    language: &LanguageScope,
24094) -> bool {
24095    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
24096        return false;
24097    };
24098
24099    let num_of_whitespaces = snapshot
24100        .chars_for_range(range.clone())
24101        .take_while(|c| c.is_whitespace())
24102        .count();
24103
24104    let task_list_prefixes: Vec<_> = language
24105        .task_list()
24106        .into_iter()
24107        .flat_map(|config| {
24108            config
24109                .prefixes
24110                .iter()
24111                .map(|p| p.as_ref())
24112                .collect::<Vec<_>>()
24113        })
24114        .collect();
24115    let unordered_list_markers: Vec<_> = language
24116        .unordered_list()
24117        .iter()
24118        .map(|marker| marker.as_ref())
24119        .collect();
24120    let all_prefixes: Vec<_> = task_list_prefixes
24121        .into_iter()
24122        .chain(unordered_list_markers)
24123        .collect();
24124    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
24125        let candidate: String = snapshot
24126            .chars_for_range(range.clone())
24127            .skip(num_of_whitespaces)
24128            .take(max_prefix_len)
24129            .collect();
24130        if all_prefixes
24131            .iter()
24132            .any(|prefix| candidate.starts_with(*prefix))
24133        {
24134            return true;
24135        }
24136    }
24137
24138    let ordered_list_candidate: String = snapshot
24139        .chars_for_range(range)
24140        .skip(num_of_whitespaces)
24141        .take(ORDERED_LIST_MAX_MARKER_LEN)
24142        .collect();
24143    for ordered_config in language.ordered_list() {
24144        let regex = match Regex::new(&ordered_config.pattern) {
24145            Ok(r) => r,
24146            Err(_) => continue,
24147        };
24148        if let Some(captures) = regex.captures(&ordered_list_candidate) {
24149            return captures.get(0).is_some();
24150        }
24151    }
24152
24153    false
24154}
24155
24156#[derive(Debug)]
24157enum NewlineConfig {
24158    /// Insert newline with optional additional indent and optional extra blank line
24159    Newline {
24160        additional_indent: IndentSize,
24161        extra_line_additional_indent: Option<IndentSize>,
24162        prevent_auto_indent: bool,
24163    },
24164    /// Clear the current line
24165    ClearCurrentLine,
24166    /// Unindent the current line and add continuation
24167    UnindentCurrentLine { continuation: Arc<str> },
24168}
24169
24170impl NewlineConfig {
24171    fn has_extra_line(&self) -> bool {
24172        matches!(
24173            self,
24174            Self::Newline {
24175                extra_line_additional_indent: Some(_),
24176                ..
24177            }
24178        )
24179    }
24180
24181    fn insert_extra_newline_brackets(
24182        buffer: &MultiBufferSnapshot,
24183        range: Range<MultiBufferOffset>,
24184        language: &language::LanguageScope,
24185    ) -> bool {
24186        let leading_whitespace_len = buffer
24187            .reversed_chars_at(range.start)
24188            .take_while(|c| c.is_whitespace() && *c != '\n')
24189            .map(|c| c.len_utf8())
24190            .sum::<usize>();
24191        let trailing_whitespace_len = buffer
24192            .chars_at(range.end)
24193            .take_while(|c| c.is_whitespace() && *c != '\n')
24194            .map(|c| c.len_utf8())
24195            .sum::<usize>();
24196        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
24197
24198        language.brackets().any(|(pair, enabled)| {
24199            let pair_start = pair.start.trim_end();
24200            let pair_end = pair.end.trim_start();
24201
24202            enabled
24203                && pair.newline
24204                && buffer.contains_str_at(range.end, pair_end)
24205                && buffer.contains_str_at(
24206                    range.start.saturating_sub_usize(pair_start.len()),
24207                    pair_start,
24208                )
24209        })
24210    }
24211
24212    fn insert_extra_newline_tree_sitter(
24213        buffer: &MultiBufferSnapshot,
24214        range: Range<MultiBufferOffset>,
24215    ) -> bool {
24216        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
24217            [(buffer, range, _)] => (*buffer, range.clone()),
24218            _ => return false,
24219        };
24220        let pair = {
24221            let mut result: Option<BracketMatch<usize>> = None;
24222
24223            for pair in buffer
24224                .all_bracket_ranges(range.start.0..range.end.0)
24225                .filter(move |pair| {
24226                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
24227                })
24228            {
24229                let len = pair.close_range.end - pair.open_range.start;
24230
24231                if let Some(existing) = &result {
24232                    let existing_len = existing.close_range.end - existing.open_range.start;
24233                    if len > existing_len {
24234                        continue;
24235                    }
24236                }
24237
24238                result = Some(pair);
24239            }
24240
24241            result
24242        };
24243        let Some(pair) = pair else {
24244            return false;
24245        };
24246        pair.newline_only
24247            && buffer
24248                .chars_for_range(pair.open_range.end..range.start.0)
24249                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
24250                .all(|c| c.is_whitespace() && c != '\n')
24251    }
24252}
24253
24254fn update_uncommitted_diff_for_buffer(
24255    editor: Entity<Editor>,
24256    project: &Entity<Project>,
24257    buffers: impl IntoIterator<Item = Entity<Buffer>>,
24258    buffer: Entity<MultiBuffer>,
24259    cx: &mut App,
24260) -> Task<()> {
24261    let mut tasks = Vec::new();
24262    project.update(cx, |project, cx| {
24263        for buffer in buffers {
24264            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
24265                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
24266            }
24267        }
24268    });
24269    cx.spawn(async move |cx| {
24270        let diffs = future::join_all(tasks).await;
24271        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
24272            return;
24273        }
24274
24275        buffer.update(cx, |buffer, cx| {
24276            for diff in diffs.into_iter().flatten() {
24277                buffer.add_diff(diff, cx);
24278            }
24279        });
24280    })
24281}
24282
24283fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
24284    let tab_size = tab_size.get() as usize;
24285    let mut width = offset;
24286
24287    for ch in text.chars() {
24288        width += if ch == '\t' {
24289            tab_size - (width % tab_size)
24290        } else {
24291            1
24292        };
24293    }
24294
24295    width - offset
24296}
24297
24298#[cfg(test)]
24299mod tests {
24300    use super::*;
24301
24302    #[test]
24303    fn test_string_size_with_expanded_tabs() {
24304        let nz = |val| NonZeroU32::new(val).unwrap();
24305        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
24306        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
24307        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
24308        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
24309        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
24310        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
24311        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
24312        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
24313    }
24314}
24315
24316/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
24317struct WordBreakingTokenizer<'a> {
24318    input: &'a str,
24319}
24320
24321impl<'a> WordBreakingTokenizer<'a> {
24322    fn new(input: &'a str) -> Self {
24323        Self { input }
24324    }
24325}
24326
24327fn is_char_ideographic(ch: char) -> bool {
24328    use unicode_script::Script::*;
24329    use unicode_script::UnicodeScript;
24330    matches!(ch.script(), Han | Tangut | Yi)
24331}
24332
24333fn is_grapheme_ideographic(text: &str) -> bool {
24334    text.chars().any(is_char_ideographic)
24335}
24336
24337fn is_grapheme_whitespace(text: &str) -> bool {
24338    text.chars().any(|x| x.is_whitespace())
24339}
24340
24341fn should_stay_with_preceding_ideograph(text: &str) -> bool {
24342    text.chars()
24343        .next()
24344        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
24345}
24346
24347#[derive(PartialEq, Eq, Debug, Clone, Copy)]
24348enum WordBreakToken<'a> {
24349    Word { token: &'a str, grapheme_len: usize },
24350    InlineWhitespace { token: &'a str, grapheme_len: usize },
24351    Newline,
24352}
24353
24354impl<'a> Iterator for WordBreakingTokenizer<'a> {
24355    /// Yields a span, the count of graphemes in the token, and whether it was
24356    /// whitespace. Note that it also breaks at word boundaries.
24357    type Item = WordBreakToken<'a>;
24358
24359    fn next(&mut self) -> Option<Self::Item> {
24360        use unicode_segmentation::UnicodeSegmentation;
24361        if self.input.is_empty() {
24362            return None;
24363        }
24364
24365        let mut iter = self.input.graphemes(true).peekable();
24366        let mut offset = 0;
24367        let mut grapheme_len = 0;
24368        if let Some(first_grapheme) = iter.next() {
24369            let is_newline = first_grapheme == "\n";
24370            let is_whitespace = is_grapheme_whitespace(first_grapheme);
24371            offset += first_grapheme.len();
24372            grapheme_len += 1;
24373            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
24374                if let Some(grapheme) = iter.peek().copied()
24375                    && should_stay_with_preceding_ideograph(grapheme)
24376                {
24377                    offset += grapheme.len();
24378                    grapheme_len += 1;
24379                }
24380            } else {
24381                let mut words = self.input[offset..].split_word_bound_indices().peekable();
24382                let mut next_word_bound = words.peek().copied();
24383                if next_word_bound.is_some_and(|(i, _)| i == 0) {
24384                    next_word_bound = words.next();
24385                }
24386                while let Some(grapheme) = iter.peek().copied() {
24387                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
24388                        break;
24389                    };
24390                    if is_grapheme_whitespace(grapheme) != is_whitespace
24391                        || (grapheme == "\n") != is_newline
24392                    {
24393                        break;
24394                    };
24395                    offset += grapheme.len();
24396                    grapheme_len += 1;
24397                    iter.next();
24398                }
24399            }
24400            let token = &self.input[..offset];
24401            self.input = &self.input[offset..];
24402            if token == "\n" {
24403                Some(WordBreakToken::Newline)
24404            } else if is_whitespace {
24405                Some(WordBreakToken::InlineWhitespace {
24406                    token,
24407                    grapheme_len,
24408                })
24409            } else {
24410                Some(WordBreakToken::Word {
24411                    token,
24412                    grapheme_len,
24413                })
24414            }
24415        } else {
24416            None
24417        }
24418    }
24419}
24420
24421#[test]
24422fn test_word_breaking_tokenizer() {
24423    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24424        ("", &[]),
24425        ("  ", &[whitespace("  ", 2)]),
24426        ("Ʒ", &[word("Ʒ", 1)]),
24427        ("Ǽ", &[word("Ǽ", 1)]),
24428        ("", &[word("", 1)]),
24429        ("⋑⋑", &[word("⋑⋑", 2)]),
24430        (
24431            "原理,进而",
24432            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24433        ),
24434        (
24435            "hello world",
24436            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24437        ),
24438        (
24439            "hello, world",
24440            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24441        ),
24442        (
24443            "  hello world",
24444            &[
24445                whitespace("  ", 2),
24446                word("hello", 5),
24447                whitespace(" ", 1),
24448                word("world", 5),
24449            ],
24450        ),
24451        (
24452            "这是什么 \n 钢笔",
24453            &[
24454                word("", 1),
24455                word("", 1),
24456                word("", 1),
24457                word("", 1),
24458                whitespace(" ", 1),
24459                newline(),
24460                whitespace(" ", 1),
24461                word("", 1),
24462                word("", 1),
24463            ],
24464        ),
24465        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24466    ];
24467
24468    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24469        WordBreakToken::Word {
24470            token,
24471            grapheme_len,
24472        }
24473    }
24474
24475    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24476        WordBreakToken::InlineWhitespace {
24477            token,
24478            grapheme_len,
24479        }
24480    }
24481
24482    fn newline() -> WordBreakToken<'static> {
24483        WordBreakToken::Newline
24484    }
24485
24486    for (input, result) in tests {
24487        assert_eq!(
24488            WordBreakingTokenizer::new(input)
24489                .collect::<Vec<_>>()
24490                .as_slice(),
24491            *result,
24492        );
24493    }
24494}
24495
24496fn wrap_with_prefix(
24497    first_line_prefix: String,
24498    subsequent_lines_prefix: String,
24499    unwrapped_text: String,
24500    wrap_column: usize,
24501    tab_size: NonZeroU32,
24502    preserve_existing_whitespace: bool,
24503) -> String {
24504    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24505    let subsequent_lines_prefix_len =
24506        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24507    let mut wrapped_text = String::new();
24508    let mut current_line = first_line_prefix;
24509    let mut is_first_line = true;
24510
24511    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24512    let mut current_line_len = first_line_prefix_len;
24513    let mut in_whitespace = false;
24514    for token in tokenizer {
24515        let have_preceding_whitespace = in_whitespace;
24516        match token {
24517            WordBreakToken::Word {
24518                token,
24519                grapheme_len,
24520            } => {
24521                in_whitespace = false;
24522                let current_prefix_len = if is_first_line {
24523                    first_line_prefix_len
24524                } else {
24525                    subsequent_lines_prefix_len
24526                };
24527                if current_line_len + grapheme_len > wrap_column
24528                    && current_line_len != current_prefix_len
24529                {
24530                    wrapped_text.push_str(current_line.trim_end());
24531                    wrapped_text.push('\n');
24532                    is_first_line = false;
24533                    current_line = subsequent_lines_prefix.clone();
24534                    current_line_len = subsequent_lines_prefix_len;
24535                }
24536                current_line.push_str(token);
24537                current_line_len += grapheme_len;
24538            }
24539            WordBreakToken::InlineWhitespace {
24540                mut token,
24541                mut grapheme_len,
24542            } => {
24543                in_whitespace = true;
24544                if have_preceding_whitespace && !preserve_existing_whitespace {
24545                    continue;
24546                }
24547                if !preserve_existing_whitespace {
24548                    // Keep a single whitespace grapheme as-is
24549                    if let Some(first) =
24550                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24551                    {
24552                        token = first;
24553                    } else {
24554                        token = " ";
24555                    }
24556                    grapheme_len = 1;
24557                }
24558                let current_prefix_len = if is_first_line {
24559                    first_line_prefix_len
24560                } else {
24561                    subsequent_lines_prefix_len
24562                };
24563                if current_line_len + grapheme_len > wrap_column {
24564                    wrapped_text.push_str(current_line.trim_end());
24565                    wrapped_text.push('\n');
24566                    is_first_line = false;
24567                    current_line = subsequent_lines_prefix.clone();
24568                    current_line_len = subsequent_lines_prefix_len;
24569                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24570                    current_line.push_str(token);
24571                    current_line_len += grapheme_len;
24572                }
24573            }
24574            WordBreakToken::Newline => {
24575                in_whitespace = true;
24576                let current_prefix_len = if is_first_line {
24577                    first_line_prefix_len
24578                } else {
24579                    subsequent_lines_prefix_len
24580                };
24581                if preserve_existing_whitespace {
24582                    wrapped_text.push_str(current_line.trim_end());
24583                    wrapped_text.push('\n');
24584                    is_first_line = false;
24585                    current_line = subsequent_lines_prefix.clone();
24586                    current_line_len = subsequent_lines_prefix_len;
24587                } else if have_preceding_whitespace {
24588                    continue;
24589                } else if current_line_len + 1 > wrap_column
24590                    && current_line_len != current_prefix_len
24591                {
24592                    wrapped_text.push_str(current_line.trim_end());
24593                    wrapped_text.push('\n');
24594                    is_first_line = false;
24595                    current_line = subsequent_lines_prefix.clone();
24596                    current_line_len = subsequent_lines_prefix_len;
24597                } else if current_line_len != current_prefix_len {
24598                    current_line.push(' ');
24599                    current_line_len += 1;
24600                }
24601            }
24602        }
24603    }
24604
24605    if !current_line.is_empty() {
24606        wrapped_text.push_str(&current_line);
24607    }
24608    wrapped_text
24609}
24610
24611#[test]
24612fn test_wrap_with_prefix() {
24613    assert_eq!(
24614        wrap_with_prefix(
24615            "# ".to_string(),
24616            "# ".to_string(),
24617            "abcdefg".to_string(),
24618            4,
24619            NonZeroU32::new(4).unwrap(),
24620            false,
24621        ),
24622        "# abcdefg"
24623    );
24624    assert_eq!(
24625        wrap_with_prefix(
24626            "".to_string(),
24627            "".to_string(),
24628            "\thello world".to_string(),
24629            8,
24630            NonZeroU32::new(4).unwrap(),
24631            false,
24632        ),
24633        "hello\nworld"
24634    );
24635    assert_eq!(
24636        wrap_with_prefix(
24637            "// ".to_string(),
24638            "// ".to_string(),
24639            "xx \nyy zz aa bb cc".to_string(),
24640            12,
24641            NonZeroU32::new(4).unwrap(),
24642            false,
24643        ),
24644        "// xx yy zz\n// aa bb cc"
24645    );
24646    assert_eq!(
24647        wrap_with_prefix(
24648            String::new(),
24649            String::new(),
24650            "这是什么 \n 钢笔".to_string(),
24651            3,
24652            NonZeroU32::new(4).unwrap(),
24653            false,
24654        ),
24655        "这是什\n么 钢\n"
24656    );
24657    assert_eq!(
24658        wrap_with_prefix(
24659            String::new(),
24660            String::new(),
24661            format!("foo{}bar", '\u{2009}'), // thin space
24662            80,
24663            NonZeroU32::new(4).unwrap(),
24664            false,
24665        ),
24666        format!("foo{}bar", '\u{2009}')
24667    );
24668}
24669
24670pub trait CollaborationHub {
24671    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24672    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24673    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24674}
24675
24676impl CollaborationHub for Entity<Project> {
24677    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24678        self.read(cx).collaborators()
24679    }
24680
24681    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24682        self.read(cx).user_store().read(cx).participant_indices()
24683    }
24684
24685    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24686        let this = self.read(cx);
24687        let user_ids = this.collaborators().values().map(|c| c.user_id);
24688        this.user_store().read(cx).participant_names(user_ids, cx)
24689    }
24690}
24691
24692pub trait SemanticsProvider {
24693    fn hover(
24694        &self,
24695        buffer: &Entity<Buffer>,
24696        position: text::Anchor,
24697        cx: &mut App,
24698    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24699
24700    fn inline_values(
24701        &self,
24702        buffer_handle: Entity<Buffer>,
24703        range: Range<text::Anchor>,
24704        cx: &mut App,
24705    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24706
24707    fn applicable_inlay_chunks(
24708        &self,
24709        buffer: &Entity<Buffer>,
24710        ranges: &[Range<text::Anchor>],
24711        cx: &mut App,
24712    ) -> Vec<Range<BufferRow>>;
24713
24714    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24715
24716    fn inlay_hints(
24717        &self,
24718        invalidate: InvalidationStrategy,
24719        buffer: Entity<Buffer>,
24720        ranges: Vec<Range<text::Anchor>>,
24721        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24722        cx: &mut App,
24723    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24724
24725    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24726
24727    fn document_highlights(
24728        &self,
24729        buffer: &Entity<Buffer>,
24730        position: text::Anchor,
24731        cx: &mut App,
24732    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24733
24734    fn definitions(
24735        &self,
24736        buffer: &Entity<Buffer>,
24737        position: text::Anchor,
24738        kind: GotoDefinitionKind,
24739        cx: &mut App,
24740    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24741
24742    fn range_for_rename(
24743        &self,
24744        buffer: &Entity<Buffer>,
24745        position: text::Anchor,
24746        cx: &mut App,
24747    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24748
24749    fn perform_rename(
24750        &self,
24751        buffer: &Entity<Buffer>,
24752        position: text::Anchor,
24753        new_name: String,
24754        cx: &mut App,
24755    ) -> Option<Task<Result<ProjectTransaction>>>;
24756}
24757
24758pub trait CompletionProvider {
24759    fn completions(
24760        &self,
24761        excerpt_id: ExcerptId,
24762        buffer: &Entity<Buffer>,
24763        buffer_position: text::Anchor,
24764        trigger: CompletionContext,
24765        window: &mut Window,
24766        cx: &mut Context<Editor>,
24767    ) -> Task<Result<Vec<CompletionResponse>>>;
24768
24769    fn resolve_completions(
24770        &self,
24771        _buffer: Entity<Buffer>,
24772        _completion_indices: Vec<usize>,
24773        _completions: Rc<RefCell<Box<[Completion]>>>,
24774        _cx: &mut Context<Editor>,
24775    ) -> Task<Result<bool>> {
24776        Task::ready(Ok(false))
24777    }
24778
24779    fn apply_additional_edits_for_completion(
24780        &self,
24781        _buffer: Entity<Buffer>,
24782        _completions: Rc<RefCell<Box<[Completion]>>>,
24783        _completion_index: usize,
24784        _push_to_history: bool,
24785        _cx: &mut Context<Editor>,
24786    ) -> Task<Result<Option<language::Transaction>>> {
24787        Task::ready(Ok(None))
24788    }
24789
24790    fn is_completion_trigger(
24791        &self,
24792        buffer: &Entity<Buffer>,
24793        position: language::Anchor,
24794        text: &str,
24795        trigger_in_words: bool,
24796        cx: &mut Context<Editor>,
24797    ) -> bool;
24798
24799    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24800
24801    fn sort_completions(&self) -> bool {
24802        true
24803    }
24804
24805    fn filter_completions(&self) -> bool {
24806        true
24807    }
24808
24809    fn show_snippets(&self) -> bool {
24810        false
24811    }
24812}
24813
24814pub trait CodeActionProvider {
24815    fn id(&self) -> Arc<str>;
24816
24817    fn code_actions(
24818        &self,
24819        buffer: &Entity<Buffer>,
24820        range: Range<text::Anchor>,
24821        window: &mut Window,
24822        cx: &mut App,
24823    ) -> Task<Result<Vec<CodeAction>>>;
24824
24825    fn apply_code_action(
24826        &self,
24827        buffer_handle: Entity<Buffer>,
24828        action: CodeAction,
24829        excerpt_id: ExcerptId,
24830        push_to_history: bool,
24831        window: &mut Window,
24832        cx: &mut App,
24833    ) -> Task<Result<ProjectTransaction>>;
24834}
24835
24836impl CodeActionProvider for Entity<Project> {
24837    fn id(&self) -> Arc<str> {
24838        "project".into()
24839    }
24840
24841    fn code_actions(
24842        &self,
24843        buffer: &Entity<Buffer>,
24844        range: Range<text::Anchor>,
24845        _window: &mut Window,
24846        cx: &mut App,
24847    ) -> Task<Result<Vec<CodeAction>>> {
24848        self.update(cx, |project, cx| {
24849            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24850            let code_actions = project.code_actions(buffer, range, None, cx);
24851            cx.background_spawn(async move {
24852                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24853                Ok(code_lens_actions
24854                    .context("code lens fetch")?
24855                    .into_iter()
24856                    .flatten()
24857                    .chain(
24858                        code_actions
24859                            .context("code action fetch")?
24860                            .into_iter()
24861                            .flatten(),
24862                    )
24863                    .collect())
24864            })
24865        })
24866    }
24867
24868    fn apply_code_action(
24869        &self,
24870        buffer_handle: Entity<Buffer>,
24871        action: CodeAction,
24872        _excerpt_id: ExcerptId,
24873        push_to_history: bool,
24874        _window: &mut Window,
24875        cx: &mut App,
24876    ) -> Task<Result<ProjectTransaction>> {
24877        self.update(cx, |project, cx| {
24878            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24879        })
24880    }
24881}
24882
24883fn snippet_completions(
24884    project: &Project,
24885    buffer: &Entity<Buffer>,
24886    buffer_anchor: text::Anchor,
24887    classifier: CharClassifier,
24888    cx: &mut App,
24889) -> Task<Result<CompletionResponse>> {
24890    let languages = buffer.read(cx).languages_at(buffer_anchor);
24891    let snippet_store = project.snippets().read(cx);
24892
24893    let scopes: Vec<_> = languages
24894        .iter()
24895        .filter_map(|language| {
24896            let language_name = language.lsp_id();
24897            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24898
24899            if snippets.is_empty() {
24900                None
24901            } else {
24902                Some((language.default_scope(), snippets))
24903            }
24904        })
24905        .collect();
24906
24907    if scopes.is_empty() {
24908        return Task::ready(Ok(CompletionResponse {
24909            completions: vec![],
24910            display_options: CompletionDisplayOptions::default(),
24911            is_incomplete: false,
24912        }));
24913    }
24914
24915    let snapshot = buffer.read(cx).text_snapshot();
24916    let executor = cx.background_executor().clone();
24917
24918    cx.background_spawn(async move {
24919        let is_word_char = |c| classifier.is_word(c);
24920
24921        let mut is_incomplete = false;
24922        let mut completions: Vec<Completion> = Vec::new();
24923
24924        const MAX_PREFIX_LEN: usize = 128;
24925        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24926        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24927        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24928
24929        let max_buffer_window: String = snapshot
24930            .text_for_range(window_start..buffer_offset)
24931            .collect();
24932
24933        if max_buffer_window.is_empty() {
24934            return Ok(CompletionResponse {
24935                completions: vec![],
24936                display_options: CompletionDisplayOptions::default(),
24937                is_incomplete: true,
24938            });
24939        }
24940
24941        for (_scope, snippets) in scopes.into_iter() {
24942            // Sort snippets by word count to match longer snippet prefixes first.
24943            let mut sorted_snippet_candidates = snippets
24944                .iter()
24945                .enumerate()
24946                .flat_map(|(snippet_ix, snippet)| {
24947                    snippet
24948                        .prefix
24949                        .iter()
24950                        .enumerate()
24951                        .map(move |(prefix_ix, prefix)| {
24952                            let word_count =
24953                                snippet_candidate_suffixes(prefix, is_word_char).count();
24954                            ((snippet_ix, prefix_ix), prefix, word_count)
24955                        })
24956                })
24957                .collect_vec();
24958            sorted_snippet_candidates
24959                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24960
24961            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24962
24963            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24964                .take(
24965                    sorted_snippet_candidates
24966                        .first()
24967                        .map(|(_, _, word_count)| *word_count)
24968                        .unwrap_or_default(),
24969                )
24970                .collect_vec();
24971
24972            const MAX_RESULTS: usize = 100;
24973            // Each match also remembers how many characters from the buffer it consumed
24974            let mut matches: Vec<(StringMatch, usize)> = vec![];
24975
24976            let mut snippet_list_cutoff_index = 0;
24977            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24978                let word_count = buffer_index + 1;
24979                // Increase `snippet_list_cutoff_index` until we have all of the
24980                // snippets with sufficiently many words.
24981                while sorted_snippet_candidates
24982                    .get(snippet_list_cutoff_index)
24983                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24984                        *snippet_word_count >= word_count
24985                    })
24986                {
24987                    snippet_list_cutoff_index += 1;
24988                }
24989
24990                // Take only the candidates with at least `word_count` many words
24991                let snippet_candidates_at_word_len =
24992                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24993
24994                let candidates = snippet_candidates_at_word_len
24995                    .iter()
24996                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24997                    .enumerate() // index in `sorted_snippet_candidates`
24998                    // First char must match
24999                    .filter(|(_ix, prefix)| {
25000                        itertools::equal(
25001                            prefix
25002                                .chars()
25003                                .next()
25004                                .into_iter()
25005                                .flat_map(|c| c.to_lowercase()),
25006                            buffer_window
25007                                .chars()
25008                                .next()
25009                                .into_iter()
25010                                .flat_map(|c| c.to_lowercase()),
25011                        )
25012                    })
25013                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
25014                    .collect::<Vec<StringMatchCandidate>>();
25015
25016                matches.extend(
25017                    fuzzy::match_strings(
25018                        &candidates,
25019                        &buffer_window,
25020                        buffer_window.chars().any(|c| c.is_uppercase()),
25021                        true,
25022                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
25023                        &Default::default(),
25024                        executor.clone(),
25025                    )
25026                    .await
25027                    .into_iter()
25028                    .map(|string_match| (string_match, buffer_window.len())),
25029                );
25030
25031                if matches.len() >= MAX_RESULTS {
25032                    break;
25033                }
25034            }
25035
25036            let to_lsp = |point: &text::Anchor| {
25037                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
25038                point_to_lsp(end)
25039            };
25040            let lsp_end = to_lsp(&buffer_anchor);
25041
25042            if matches.len() >= MAX_RESULTS {
25043                is_incomplete = true;
25044            }
25045
25046            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
25047                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
25048                    sorted_snippet_candidates[string_match.candidate_id];
25049                let snippet = &snippets[snippet_index];
25050                let start = buffer_offset - buffer_window_len;
25051                let start = snapshot.anchor_before(start);
25052                let range = start..buffer_anchor;
25053                let lsp_start = to_lsp(&start);
25054                let lsp_range = lsp::Range {
25055                    start: lsp_start,
25056                    end: lsp_end,
25057                };
25058                Completion {
25059                    replace_range: range,
25060                    new_text: snippet.body.clone(),
25061                    source: CompletionSource::Lsp {
25062                        insert_range: None,
25063                        server_id: LanguageServerId(usize::MAX),
25064                        resolved: true,
25065                        lsp_completion: Box::new(lsp::CompletionItem {
25066                            label: snippet.prefix.first().unwrap().clone(),
25067                            kind: Some(CompletionItemKind::SNIPPET),
25068                            label_details: snippet.description.as_ref().map(|description| {
25069                                lsp::CompletionItemLabelDetails {
25070                                    detail: Some(description.clone()),
25071                                    description: None,
25072                                }
25073                            }),
25074                            insert_text_format: Some(InsertTextFormat::SNIPPET),
25075                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
25076                                lsp::InsertReplaceEdit {
25077                                    new_text: snippet.body.clone(),
25078                                    insert: lsp_range,
25079                                    replace: lsp_range,
25080                                },
25081                            )),
25082                            filter_text: Some(snippet.body.clone()),
25083                            sort_text: Some(char::MAX.to_string()),
25084                            ..lsp::CompletionItem::default()
25085                        }),
25086                        lsp_defaults: None,
25087                    },
25088                    label: CodeLabel {
25089                        text: matching_prefix.clone(),
25090                        runs: Vec::new(),
25091                        filter_range: 0..matching_prefix.len(),
25092                    },
25093                    icon_path: None,
25094                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
25095                        single_line: snippet.name.clone().into(),
25096                        plain_text: snippet
25097                            .description
25098                            .clone()
25099                            .map(|description| description.into()),
25100                    }),
25101                    insert_text_mode: None,
25102                    confirm: None,
25103                    match_start: Some(start),
25104                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
25105                }
25106            }));
25107        }
25108
25109        Ok(CompletionResponse {
25110            completions,
25111            display_options: CompletionDisplayOptions::default(),
25112            is_incomplete,
25113        })
25114    })
25115}
25116
25117impl CompletionProvider for Entity<Project> {
25118    fn completions(
25119        &self,
25120        _excerpt_id: ExcerptId,
25121        buffer: &Entity<Buffer>,
25122        buffer_position: text::Anchor,
25123        options: CompletionContext,
25124        _window: &mut Window,
25125        cx: &mut Context<Editor>,
25126    ) -> Task<Result<Vec<CompletionResponse>>> {
25127        self.update(cx, |project, cx| {
25128            let task = project.completions(buffer, buffer_position, options, cx);
25129            cx.background_spawn(task)
25130        })
25131    }
25132
25133    fn resolve_completions(
25134        &self,
25135        buffer: Entity<Buffer>,
25136        completion_indices: Vec<usize>,
25137        completions: Rc<RefCell<Box<[Completion]>>>,
25138        cx: &mut Context<Editor>,
25139    ) -> Task<Result<bool>> {
25140        self.update(cx, |project, cx| {
25141            project.lsp_store().update(cx, |lsp_store, cx| {
25142                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
25143            })
25144        })
25145    }
25146
25147    fn apply_additional_edits_for_completion(
25148        &self,
25149        buffer: Entity<Buffer>,
25150        completions: Rc<RefCell<Box<[Completion]>>>,
25151        completion_index: usize,
25152        push_to_history: bool,
25153        cx: &mut Context<Editor>,
25154    ) -> Task<Result<Option<language::Transaction>>> {
25155        self.update(cx, |project, cx| {
25156            project.lsp_store().update(cx, |lsp_store, cx| {
25157                lsp_store.apply_additional_edits_for_completion(
25158                    buffer,
25159                    completions,
25160                    completion_index,
25161                    push_to_history,
25162                    cx,
25163                )
25164            })
25165        })
25166    }
25167
25168    fn is_completion_trigger(
25169        &self,
25170        buffer: &Entity<Buffer>,
25171        position: language::Anchor,
25172        text: &str,
25173        trigger_in_words: bool,
25174        cx: &mut Context<Editor>,
25175    ) -> bool {
25176        let mut chars = text.chars();
25177        let char = if let Some(char) = chars.next() {
25178            char
25179        } else {
25180            return false;
25181        };
25182        if chars.next().is_some() {
25183            return false;
25184        }
25185
25186        let buffer = buffer.read(cx);
25187        let snapshot = buffer.snapshot();
25188        let classifier = snapshot
25189            .char_classifier_at(position)
25190            .scope_context(Some(CharScopeContext::Completion));
25191        if trigger_in_words && classifier.is_word(char) {
25192            return true;
25193        }
25194
25195        buffer.completion_triggers().contains(text)
25196    }
25197
25198    fn show_snippets(&self) -> bool {
25199        true
25200    }
25201}
25202
25203impl SemanticsProvider for Entity<Project> {
25204    fn hover(
25205        &self,
25206        buffer: &Entity<Buffer>,
25207        position: text::Anchor,
25208        cx: &mut App,
25209    ) -> Option<Task<Option<Vec<project::Hover>>>> {
25210        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
25211    }
25212
25213    fn document_highlights(
25214        &self,
25215        buffer: &Entity<Buffer>,
25216        position: text::Anchor,
25217        cx: &mut App,
25218    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
25219        Some(self.update(cx, |project, cx| {
25220            project.document_highlights(buffer, position, cx)
25221        }))
25222    }
25223
25224    fn definitions(
25225        &self,
25226        buffer: &Entity<Buffer>,
25227        position: text::Anchor,
25228        kind: GotoDefinitionKind,
25229        cx: &mut App,
25230    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
25231        Some(self.update(cx, |project, cx| match kind {
25232            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
25233            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
25234            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
25235            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
25236        }))
25237    }
25238
25239    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
25240        self.update(cx, |project, cx| {
25241            if project
25242                .active_debug_session(cx)
25243                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
25244            {
25245                return true;
25246            }
25247
25248            buffer.update(cx, |buffer, cx| {
25249                project.any_language_server_supports_inlay_hints(buffer, cx)
25250            })
25251        })
25252    }
25253
25254    fn inline_values(
25255        &self,
25256        buffer_handle: Entity<Buffer>,
25257        range: Range<text::Anchor>,
25258        cx: &mut App,
25259    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
25260        self.update(cx, |project, cx| {
25261            let (session, active_stack_frame) = project.active_debug_session(cx)?;
25262
25263            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
25264        })
25265    }
25266
25267    fn applicable_inlay_chunks(
25268        &self,
25269        buffer: &Entity<Buffer>,
25270        ranges: &[Range<text::Anchor>],
25271        cx: &mut App,
25272    ) -> Vec<Range<BufferRow>> {
25273        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25274            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
25275        })
25276    }
25277
25278    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
25279        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
25280            lsp_store.invalidate_inlay_hints(for_buffers)
25281        });
25282    }
25283
25284    fn inlay_hints(
25285        &self,
25286        invalidate: InvalidationStrategy,
25287        buffer: Entity<Buffer>,
25288        ranges: Vec<Range<text::Anchor>>,
25289        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
25290        cx: &mut App,
25291    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
25292        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25293            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
25294        }))
25295    }
25296
25297    fn range_for_rename(
25298        &self,
25299        buffer: &Entity<Buffer>,
25300        position: text::Anchor,
25301        cx: &mut App,
25302    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
25303        Some(self.update(cx, |project, cx| {
25304            let buffer = buffer.clone();
25305            let task = project.prepare_rename(buffer.clone(), position, cx);
25306            cx.spawn(async move |_, cx| {
25307                Ok(match task.await? {
25308                    PrepareRenameResponse::Success(range) => Some(range),
25309                    PrepareRenameResponse::InvalidPosition => None,
25310                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
25311                        // Fallback on using TreeSitter info to determine identifier range
25312                        buffer.read_with(cx, |buffer, _| {
25313                            let snapshot = buffer.snapshot();
25314                            let (range, kind) = snapshot.surrounding_word(position, None);
25315                            if kind != Some(CharKind::Word) {
25316                                return None;
25317                            }
25318                            Some(
25319                                snapshot.anchor_before(range.start)
25320                                    ..snapshot.anchor_after(range.end),
25321                            )
25322                        })
25323                    }
25324                })
25325            })
25326        }))
25327    }
25328
25329    fn perform_rename(
25330        &self,
25331        buffer: &Entity<Buffer>,
25332        position: text::Anchor,
25333        new_name: String,
25334        cx: &mut App,
25335    ) -> Option<Task<Result<ProjectTransaction>>> {
25336        Some(self.update(cx, |project, cx| {
25337            project.perform_rename(buffer.clone(), position, new_name, cx)
25338        }))
25339    }
25340}
25341
25342fn consume_contiguous_rows(
25343    contiguous_row_selections: &mut Vec<Selection<Point>>,
25344    selection: &Selection<Point>,
25345    display_map: &DisplaySnapshot,
25346    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
25347) -> (MultiBufferRow, MultiBufferRow) {
25348    contiguous_row_selections.push(selection.clone());
25349    let start_row = starting_row(selection, display_map);
25350    let mut end_row = ending_row(selection, display_map);
25351
25352    while let Some(next_selection) = selections.peek() {
25353        if next_selection.start.row <= end_row.0 {
25354            end_row = ending_row(next_selection, display_map);
25355            contiguous_row_selections.push(selections.next().unwrap().clone());
25356        } else {
25357            break;
25358        }
25359    }
25360    (start_row, end_row)
25361}
25362
25363fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25364    if selection.start.column > 0 {
25365        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
25366    } else {
25367        MultiBufferRow(selection.start.row)
25368    }
25369}
25370
25371fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25372    if next_selection.end.column > 0 || next_selection.is_empty() {
25373        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
25374    } else {
25375        MultiBufferRow(next_selection.end.row)
25376    }
25377}
25378
25379impl EditorSnapshot {
25380    pub fn remote_selections_in_range<'a>(
25381        &'a self,
25382        range: &'a Range<Anchor>,
25383        collaboration_hub: &dyn CollaborationHub,
25384        cx: &'a App,
25385    ) -> impl 'a + Iterator<Item = RemoteSelection> {
25386        let participant_names = collaboration_hub.user_names(cx);
25387        let participant_indices = collaboration_hub.user_participant_indices(cx);
25388        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
25389        let collaborators_by_replica_id = collaborators_by_peer_id
25390            .values()
25391            .map(|collaborator| (collaborator.replica_id, collaborator))
25392            .collect::<HashMap<_, _>>();
25393        self.buffer_snapshot()
25394            .selections_in_range(range, false)
25395            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
25396                if replica_id == ReplicaId::AGENT {
25397                    Some(RemoteSelection {
25398                        replica_id,
25399                        selection,
25400                        cursor_shape,
25401                        line_mode,
25402                        collaborator_id: CollaboratorId::Agent,
25403                        user_name: Some("Agent".into()),
25404                        color: cx.theme().players().agent(),
25405                    })
25406                } else {
25407                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
25408                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
25409                    let user_name = participant_names.get(&collaborator.user_id).cloned();
25410                    Some(RemoteSelection {
25411                        replica_id,
25412                        selection,
25413                        cursor_shape,
25414                        line_mode,
25415                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25416                        user_name,
25417                        color: if let Some(index) = participant_index {
25418                            cx.theme().players().color_for_participant(index.0)
25419                        } else {
25420                            cx.theme().players().absent()
25421                        },
25422                    })
25423                }
25424            })
25425    }
25426
25427    pub fn hunks_for_ranges(
25428        &self,
25429        ranges: impl IntoIterator<Item = Range<Point>>,
25430    ) -> Vec<MultiBufferDiffHunk> {
25431        let mut hunks = Vec::new();
25432        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25433            HashMap::default();
25434        for query_range in ranges {
25435            let query_rows =
25436                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25437            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25438                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25439            ) {
25440                // Include deleted hunks that are adjacent to the query range, because
25441                // otherwise they would be missed.
25442                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25443                if hunk.status().is_deleted() {
25444                    intersects_range |= hunk.row_range.start == query_rows.end;
25445                    intersects_range |= hunk.row_range.end == query_rows.start;
25446                }
25447                if intersects_range {
25448                    if !processed_buffer_rows
25449                        .entry(hunk.buffer_id)
25450                        .or_default()
25451                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25452                    {
25453                        continue;
25454                    }
25455                    hunks.push(hunk);
25456                }
25457            }
25458        }
25459
25460        hunks
25461    }
25462
25463    fn display_diff_hunks_for_rows<'a>(
25464        &'a self,
25465        display_rows: Range<DisplayRow>,
25466        folded_buffers: &'a HashSet<BufferId>,
25467    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25468        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25469        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25470
25471        self.buffer_snapshot()
25472            .diff_hunks_in_range(buffer_start..buffer_end)
25473            .filter_map(|hunk| {
25474                if folded_buffers.contains(&hunk.buffer_id) {
25475                    return None;
25476                }
25477
25478                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25479                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25480
25481                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25482                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25483
25484                let display_hunk = if hunk_display_start.column() != 0 {
25485                    DisplayDiffHunk::Folded {
25486                        display_row: hunk_display_start.row(),
25487                    }
25488                } else {
25489                    let mut end_row = hunk_display_end.row();
25490                    if hunk_display_end.column() > 0 {
25491                        end_row.0 += 1;
25492                    }
25493                    let is_created_file = hunk.is_created_file();
25494
25495                    DisplayDiffHunk::Unfolded {
25496                        status: hunk.status(),
25497                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25498                            ..hunk.diff_base_byte_range.end.0,
25499                        word_diffs: hunk.word_diffs,
25500                        display_row_range: hunk_display_start.row()..end_row,
25501                        multi_buffer_range: Anchor::range_in_buffer(
25502                            hunk.excerpt_id,
25503                            hunk.buffer_range,
25504                        ),
25505                        is_created_file,
25506                    }
25507                };
25508
25509                Some(display_hunk)
25510            })
25511    }
25512
25513    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25514        self.display_snapshot
25515            .buffer_snapshot()
25516            .language_at(position)
25517    }
25518
25519    pub fn is_focused(&self) -> bool {
25520        self.is_focused
25521    }
25522
25523    pub fn placeholder_text(&self) -> Option<String> {
25524        self.placeholder_display_snapshot
25525            .as_ref()
25526            .map(|display_map| display_map.text())
25527    }
25528
25529    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25530        self.scroll_anchor.scroll_position(&self.display_snapshot)
25531    }
25532
25533    pub fn gutter_dimensions(
25534        &self,
25535        font_id: FontId,
25536        font_size: Pixels,
25537        style: &EditorStyle,
25538        window: &mut Window,
25539        cx: &App,
25540    ) -> GutterDimensions {
25541        if self.show_gutter
25542            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25543            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25544        {
25545            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25546                matches!(
25547                    ProjectSettings::get_global(cx).git.git_gutter,
25548                    GitGutterSetting::TrackedFiles
25549                )
25550            });
25551            let gutter_settings = EditorSettings::get_global(cx).gutter;
25552            let show_line_numbers = self
25553                .show_line_numbers
25554                .unwrap_or(gutter_settings.line_numbers);
25555            let line_gutter_width = if show_line_numbers {
25556                // Avoid flicker-like gutter resizes when the line number gains another digit by
25557                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25558                let min_width_for_number_on_gutter =
25559                    ch_advance * gutter_settings.min_line_number_digits as f32;
25560                self.max_line_number_width(style, window)
25561                    .max(min_width_for_number_on_gutter)
25562            } else {
25563                0.0.into()
25564            };
25565
25566            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25567            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25568
25569            let git_blame_entries_width =
25570                self.git_blame_gutter_max_author_length
25571                    .map(|max_author_length| {
25572                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25573                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25574
25575                        /// The number of characters to dedicate to gaps and margins.
25576                        const SPACING_WIDTH: usize = 4;
25577
25578                        let max_char_count = max_author_length.min(renderer.max_author_length())
25579                            + ::git::SHORT_SHA_LENGTH
25580                            + MAX_RELATIVE_TIMESTAMP.len()
25581                            + SPACING_WIDTH;
25582
25583                        ch_advance * max_char_count
25584                    });
25585
25586            let is_singleton = self.buffer_snapshot().is_singleton();
25587
25588            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25589            left_padding += if !is_singleton {
25590                ch_width * 4.0
25591            } else if show_runnables || show_breakpoints {
25592                ch_width * 3.0
25593            } else if show_git_gutter && show_line_numbers {
25594                ch_width * 2.0
25595            } else if show_git_gutter || show_line_numbers {
25596                ch_width
25597            } else {
25598                px(0.)
25599            };
25600
25601            let shows_folds = is_singleton && gutter_settings.folds;
25602
25603            let right_padding = if shows_folds && show_line_numbers {
25604                ch_width * 4.0
25605            } else if shows_folds || (!is_singleton && show_line_numbers) {
25606                ch_width * 3.0
25607            } else if show_line_numbers {
25608                ch_width
25609            } else {
25610                px(0.)
25611            };
25612
25613            GutterDimensions {
25614                left_padding,
25615                right_padding,
25616                width: line_gutter_width + left_padding + right_padding,
25617                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25618                git_blame_entries_width,
25619            }
25620        } else if self.offset_content {
25621            GutterDimensions::default_with_margin(font_id, font_size, cx)
25622        } else {
25623            GutterDimensions::default()
25624        }
25625    }
25626
25627    pub fn render_crease_toggle(
25628        &self,
25629        buffer_row: MultiBufferRow,
25630        row_contains_cursor: bool,
25631        editor: Entity<Editor>,
25632        window: &mut Window,
25633        cx: &mut App,
25634    ) -> Option<AnyElement> {
25635        let folded = self.is_line_folded(buffer_row);
25636        let mut is_foldable = false;
25637
25638        if let Some(crease) = self
25639            .crease_snapshot
25640            .query_row(buffer_row, self.buffer_snapshot())
25641        {
25642            is_foldable = true;
25643            match crease {
25644                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25645                    if let Some(render_toggle) = render_toggle {
25646                        let toggle_callback =
25647                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25648                                if folded {
25649                                    editor.update(cx, |editor, cx| {
25650                                        editor.fold_at(buffer_row, window, cx)
25651                                    });
25652                                } else {
25653                                    editor.update(cx, |editor, cx| {
25654                                        editor.unfold_at(buffer_row, window, cx)
25655                                    });
25656                                }
25657                            });
25658                        return Some((render_toggle)(
25659                            buffer_row,
25660                            folded,
25661                            toggle_callback,
25662                            window,
25663                            cx,
25664                        ));
25665                    }
25666                }
25667            }
25668        }
25669
25670        is_foldable |= self.starts_indent(buffer_row);
25671
25672        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25673            Some(
25674                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25675                    .toggle_state(folded)
25676                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25677                        if folded {
25678                            this.unfold_at(buffer_row, window, cx);
25679                        } else {
25680                            this.fold_at(buffer_row, window, cx);
25681                        }
25682                    }))
25683                    .into_any_element(),
25684            )
25685        } else {
25686            None
25687        }
25688    }
25689
25690    pub fn render_crease_trailer(
25691        &self,
25692        buffer_row: MultiBufferRow,
25693        window: &mut Window,
25694        cx: &mut App,
25695    ) -> Option<AnyElement> {
25696        let folded = self.is_line_folded(buffer_row);
25697        if let Crease::Inline { render_trailer, .. } = self
25698            .crease_snapshot
25699            .query_row(buffer_row, self.buffer_snapshot())?
25700        {
25701            let render_trailer = render_trailer.as_ref()?;
25702            Some(render_trailer(buffer_row, folded, window, cx))
25703        } else {
25704            None
25705        }
25706    }
25707
25708    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25709        let digit_count = self.widest_line_number().ilog10() + 1;
25710        column_pixels(style, digit_count as usize, window)
25711    }
25712
25713    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
25714    ///
25715    /// This is positive if `base` is before `line`.
25716    fn relative_line_delta(
25717        &self,
25718        current_selection_head: DisplayRow,
25719        first_visible_row: DisplayRow,
25720        consider_wrapped_lines: bool,
25721    ) -> i64 {
25722        let current_selection_head = current_selection_head.as_display_point().to_point(self);
25723        let first_visible_row = first_visible_row.as_display_point().to_point(self);
25724
25725        if consider_wrapped_lines {
25726            let wrap_snapshot = self.wrap_snapshot();
25727            let base_wrap_row = wrap_snapshot
25728                .make_wrap_point(current_selection_head, Bias::Left)
25729                .row();
25730            let wrap_row = wrap_snapshot
25731                .make_wrap_point(first_visible_row, Bias::Left)
25732                .row();
25733            wrap_row.0 as i64 - base_wrap_row.0 as i64
25734        } else {
25735            let folds = if current_selection_head < first_visible_row {
25736                self.folds_in_range(current_selection_head..first_visible_row)
25737            } else {
25738                self.folds_in_range(first_visible_row..current_selection_head)
25739            };
25740
25741            let folded_lines = folds
25742                .map(|fold| {
25743                    let range = fold.range.0.to_point(self);
25744                    range.end.row.saturating_sub(range.start.row)
25745                })
25746                .sum::<u32>() as i64;
25747
25748            first_visible_row.row as i64 - current_selection_head.row as i64 + folded_lines
25749        }
25750    }
25751
25752    /// Returns the unsigned relative line number to display for each row in `rows`.
25753    ///
25754    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
25755    pub fn calculate_relative_line_numbers(
25756        &self,
25757        rows: &Range<DisplayRow>,
25758        current_selection_head: DisplayRow,
25759        count_wrapped_lines: bool,
25760    ) -> HashMap<DisplayRow, u32> {
25761        let initial_offset =
25762            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
25763        let current_selection_point = current_selection_head.as_display_point().to_point(self);
25764
25765        self.row_infos(rows.start)
25766            .take(rows.len())
25767            .enumerate()
25768            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
25769            .filter(|(_row, row_info)| {
25770                row_info.buffer_row.is_some()
25771                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
25772            })
25773            .enumerate()
25774            .filter(|(_, (row, row_info))| {
25775                // We want to check here that
25776                // - the row is not the current selection head to ensure the current
25777                // line has absolute numbering
25778                // - similarly, should the selection head live in a soft-wrapped line
25779                // and we are not counting those, that the parent line keeps its
25780                // absolute number
25781                // - lastly, if we are in a deleted line, it is fine to number this
25782                // relative with 0, as otherwise it would have no line number at all
25783                (*row != current_selection_head
25784                    && (count_wrapped_lines
25785                        || row_info.buffer_row != Some(current_selection_point.row)))
25786                    || row_info
25787                        .diff_status
25788                        .is_some_and(|status| status.is_deleted())
25789            })
25790            .map(|(i, (row, _))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
25791            .collect()
25792    }
25793}
25794
25795pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25796    let font_size = style.text.font_size.to_pixels(window.rem_size());
25797    let layout = window.text_system().shape_line(
25798        SharedString::from(" ".repeat(column)),
25799        font_size,
25800        &[TextRun {
25801            len: column,
25802            font: style.text.font(),
25803            color: Hsla::default(),
25804            ..Default::default()
25805        }],
25806        None,
25807    );
25808
25809    layout.width
25810}
25811
25812impl Deref for EditorSnapshot {
25813    type Target = DisplaySnapshot;
25814
25815    fn deref(&self) -> &Self::Target {
25816        &self.display_snapshot
25817    }
25818}
25819
25820#[derive(Clone, Debug, PartialEq, Eq)]
25821pub enum EditorEvent {
25822    InputIgnored {
25823        text: Arc<str>,
25824    },
25825    InputHandled {
25826        utf16_range_to_replace: Option<Range<isize>>,
25827        text: Arc<str>,
25828    },
25829    ExcerptsAdded {
25830        buffer: Entity<Buffer>,
25831        predecessor: ExcerptId,
25832        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25833    },
25834    ExcerptsRemoved {
25835        ids: Vec<ExcerptId>,
25836        removed_buffer_ids: Vec<BufferId>,
25837    },
25838    BufferFoldToggled {
25839        ids: Vec<ExcerptId>,
25840        folded: bool,
25841    },
25842    ExcerptsEdited {
25843        ids: Vec<ExcerptId>,
25844    },
25845    ExcerptsExpanded {
25846        ids: Vec<ExcerptId>,
25847    },
25848    ExpandExcerptsRequested {
25849        excerpt_ids: Vec<ExcerptId>,
25850        lines: u32,
25851        direction: ExpandExcerptDirection,
25852    },
25853    BufferEdited,
25854    Edited {
25855        transaction_id: clock::Lamport,
25856    },
25857    Reparsed(BufferId),
25858    Focused,
25859    FocusedIn,
25860    Blurred,
25861    DirtyChanged,
25862    Saved,
25863    TitleChanged,
25864    SelectionsChanged {
25865        local: bool,
25866    },
25867    ScrollPositionChanged {
25868        local: bool,
25869        autoscroll: bool,
25870    },
25871    TransactionUndone {
25872        transaction_id: clock::Lamport,
25873    },
25874    TransactionBegun {
25875        transaction_id: clock::Lamport,
25876    },
25877    CursorShapeChanged,
25878    BreadcrumbsChanged,
25879    PushedToNavHistory {
25880        anchor: Anchor,
25881        is_deactivate: bool,
25882    },
25883}
25884
25885impl EventEmitter<EditorEvent> for Editor {}
25886
25887impl Focusable for Editor {
25888    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25889        self.focus_handle.clone()
25890    }
25891}
25892
25893impl Render for Editor {
25894    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25895        EditorElement::new(&cx.entity(), self.create_style(cx))
25896    }
25897}
25898
25899impl EntityInputHandler for Editor {
25900    fn text_for_range(
25901        &mut self,
25902        range_utf16: Range<usize>,
25903        adjusted_range: &mut Option<Range<usize>>,
25904        _: &mut Window,
25905        cx: &mut Context<Self>,
25906    ) -> Option<String> {
25907        let snapshot = self.buffer.read(cx).read(cx);
25908        let start = snapshot.clip_offset_utf16(
25909            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25910            Bias::Left,
25911        );
25912        let end = snapshot.clip_offset_utf16(
25913            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25914            Bias::Right,
25915        );
25916        if (start.0.0..end.0.0) != range_utf16 {
25917            adjusted_range.replace(start.0.0..end.0.0);
25918        }
25919        Some(snapshot.text_for_range(start..end).collect())
25920    }
25921
25922    fn selected_text_range(
25923        &mut self,
25924        ignore_disabled_input: bool,
25925        _: &mut Window,
25926        cx: &mut Context<Self>,
25927    ) -> Option<UTF16Selection> {
25928        // Prevent the IME menu from appearing when holding down an alphabetic key
25929        // while input is disabled.
25930        if !ignore_disabled_input && !self.input_enabled {
25931            return None;
25932        }
25933
25934        let selection = self
25935            .selections
25936            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25937        let range = selection.range();
25938
25939        Some(UTF16Selection {
25940            range: range.start.0.0..range.end.0.0,
25941            reversed: selection.reversed,
25942        })
25943    }
25944
25945    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25946        let snapshot = self.buffer.read(cx).read(cx);
25947        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25948        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25949    }
25950
25951    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25952        self.clear_highlights::<InputComposition>(cx);
25953        self.ime_transaction.take();
25954    }
25955
25956    fn replace_text_in_range(
25957        &mut self,
25958        range_utf16: Option<Range<usize>>,
25959        text: &str,
25960        window: &mut Window,
25961        cx: &mut Context<Self>,
25962    ) {
25963        if !self.input_enabled {
25964            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25965            return;
25966        }
25967
25968        self.transact(window, cx, |this, window, cx| {
25969            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25970                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25971                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25972                Some(this.selection_replacement_ranges(range_utf16, cx))
25973            } else {
25974                this.marked_text_ranges(cx)
25975            };
25976
25977            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25978                let newest_selection_id = this.selections.newest_anchor().id;
25979                this.selections
25980                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25981                    .iter()
25982                    .zip(ranges_to_replace.iter())
25983                    .find_map(|(selection, range)| {
25984                        if selection.id == newest_selection_id {
25985                            Some(
25986                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25987                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25988                            )
25989                        } else {
25990                            None
25991                        }
25992                    })
25993            });
25994
25995            cx.emit(EditorEvent::InputHandled {
25996                utf16_range_to_replace: range_to_replace,
25997                text: text.into(),
25998            });
25999
26000            if let Some(new_selected_ranges) = new_selected_ranges {
26001                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
26002                    selections.select_ranges(new_selected_ranges)
26003                });
26004                this.backspace(&Default::default(), window, cx);
26005            }
26006
26007            this.handle_input(text, window, cx);
26008        });
26009
26010        if let Some(transaction) = self.ime_transaction {
26011            self.buffer.update(cx, |buffer, cx| {
26012                buffer.group_until_transaction(transaction, cx);
26013            });
26014        }
26015
26016        self.unmark_text(window, cx);
26017    }
26018
26019    fn replace_and_mark_text_in_range(
26020        &mut self,
26021        range_utf16: Option<Range<usize>>,
26022        text: &str,
26023        new_selected_range_utf16: Option<Range<usize>>,
26024        window: &mut Window,
26025        cx: &mut Context<Self>,
26026    ) {
26027        if !self.input_enabled {
26028            return;
26029        }
26030
26031        let transaction = self.transact(window, cx, |this, window, cx| {
26032            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
26033                let snapshot = this.buffer.read(cx).read(cx);
26034                if let Some(relative_range_utf16) = range_utf16.as_ref() {
26035                    for marked_range in &mut marked_ranges {
26036                        marked_range.end = marked_range.start + relative_range_utf16.end;
26037                        marked_range.start += relative_range_utf16.start;
26038                        marked_range.start =
26039                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
26040                        marked_range.end =
26041                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
26042                    }
26043                }
26044                Some(marked_ranges)
26045            } else if let Some(range_utf16) = range_utf16 {
26046                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
26047                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
26048                Some(this.selection_replacement_ranges(range_utf16, cx))
26049            } else {
26050                None
26051            };
26052
26053            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
26054                let newest_selection_id = this.selections.newest_anchor().id;
26055                this.selections
26056                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
26057                    .iter()
26058                    .zip(ranges_to_replace.iter())
26059                    .find_map(|(selection, range)| {
26060                        if selection.id == newest_selection_id {
26061                            Some(
26062                                (range.start.0.0 as isize - selection.head().0.0 as isize)
26063                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
26064                            )
26065                        } else {
26066                            None
26067                        }
26068                    })
26069            });
26070
26071            cx.emit(EditorEvent::InputHandled {
26072                utf16_range_to_replace: range_to_replace,
26073                text: text.into(),
26074            });
26075
26076            if let Some(ranges) = ranges_to_replace {
26077                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
26078                    s.select_ranges(ranges)
26079                });
26080            }
26081
26082            let marked_ranges = {
26083                let snapshot = this.buffer.read(cx).read(cx);
26084                this.selections
26085                    .disjoint_anchors_arc()
26086                    .iter()
26087                    .map(|selection| {
26088                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
26089                    })
26090                    .collect::<Vec<_>>()
26091            };
26092
26093            if text.is_empty() {
26094                this.unmark_text(window, cx);
26095            } else {
26096                this.highlight_text::<InputComposition>(
26097                    marked_ranges.clone(),
26098                    HighlightStyle {
26099                        underline: Some(UnderlineStyle {
26100                            thickness: px(1.),
26101                            color: None,
26102                            wavy: false,
26103                        }),
26104                        ..Default::default()
26105                    },
26106                    cx,
26107                );
26108            }
26109
26110            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
26111            let use_autoclose = this.use_autoclose;
26112            let use_auto_surround = this.use_auto_surround;
26113            this.set_use_autoclose(false);
26114            this.set_use_auto_surround(false);
26115            this.handle_input(text, window, cx);
26116            this.set_use_autoclose(use_autoclose);
26117            this.set_use_auto_surround(use_auto_surround);
26118
26119            if let Some(new_selected_range) = new_selected_range_utf16 {
26120                let snapshot = this.buffer.read(cx).read(cx);
26121                let new_selected_ranges = marked_ranges
26122                    .into_iter()
26123                    .map(|marked_range| {
26124                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
26125                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
26126                            insertion_start.0 + new_selected_range.start,
26127                        ));
26128                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
26129                            insertion_start.0 + new_selected_range.end,
26130                        ));
26131                        snapshot.clip_offset_utf16(new_start, Bias::Left)
26132                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
26133                    })
26134                    .collect::<Vec<_>>();
26135
26136                drop(snapshot);
26137                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
26138                    selections.select_ranges(new_selected_ranges)
26139                });
26140            }
26141        });
26142
26143        self.ime_transaction = self.ime_transaction.or(transaction);
26144        if let Some(transaction) = self.ime_transaction {
26145            self.buffer.update(cx, |buffer, cx| {
26146                buffer.group_until_transaction(transaction, cx);
26147            });
26148        }
26149
26150        if self.text_highlights::<InputComposition>(cx).is_none() {
26151            self.ime_transaction.take();
26152        }
26153    }
26154
26155    fn bounds_for_range(
26156        &mut self,
26157        range_utf16: Range<usize>,
26158        element_bounds: gpui::Bounds<Pixels>,
26159        window: &mut Window,
26160        cx: &mut Context<Self>,
26161    ) -> Option<gpui::Bounds<Pixels>> {
26162        let text_layout_details = self.text_layout_details(window);
26163        let CharacterDimensions {
26164            em_width,
26165            em_advance,
26166            line_height,
26167        } = self.character_dimensions(window);
26168
26169        let snapshot = self.snapshot(window, cx);
26170        let scroll_position = snapshot.scroll_position();
26171        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
26172
26173        let start =
26174            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
26175        let x = Pixels::from(
26176            ScrollOffset::from(
26177                snapshot.x_for_display_point(start, &text_layout_details)
26178                    + self.gutter_dimensions.full_width(),
26179            ) - scroll_left,
26180        );
26181        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
26182
26183        Some(Bounds {
26184            origin: element_bounds.origin + point(x, y),
26185            size: size(em_width, line_height),
26186        })
26187    }
26188
26189    fn character_index_for_point(
26190        &mut self,
26191        point: gpui::Point<Pixels>,
26192        _window: &mut Window,
26193        _cx: &mut Context<Self>,
26194    ) -> Option<usize> {
26195        let position_map = self.last_position_map.as_ref()?;
26196        if !position_map.text_hitbox.contains(&point) {
26197            return None;
26198        }
26199        let display_point = position_map.point_for_position(point).previous_valid;
26200        let anchor = position_map
26201            .snapshot
26202            .display_point_to_anchor(display_point, Bias::Left);
26203        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
26204        Some(utf16_offset.0.0)
26205    }
26206
26207    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
26208        self.input_enabled
26209    }
26210}
26211
26212trait SelectionExt {
26213    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
26214    fn spanned_rows(
26215        &self,
26216        include_end_if_at_line_start: bool,
26217        map: &DisplaySnapshot,
26218    ) -> Range<MultiBufferRow>;
26219}
26220
26221impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
26222    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
26223        let start = self
26224            .start
26225            .to_point(map.buffer_snapshot())
26226            .to_display_point(map);
26227        let end = self
26228            .end
26229            .to_point(map.buffer_snapshot())
26230            .to_display_point(map);
26231        if self.reversed {
26232            end..start
26233        } else {
26234            start..end
26235        }
26236    }
26237
26238    fn spanned_rows(
26239        &self,
26240        include_end_if_at_line_start: bool,
26241        map: &DisplaySnapshot,
26242    ) -> Range<MultiBufferRow> {
26243        let start = self.start.to_point(map.buffer_snapshot());
26244        let mut end = self.end.to_point(map.buffer_snapshot());
26245        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
26246            end.row -= 1;
26247        }
26248
26249        let buffer_start = map.prev_line_boundary(start).0;
26250        let buffer_end = map.next_line_boundary(end).0;
26251        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
26252    }
26253}
26254
26255impl<T: InvalidationRegion> InvalidationStack<T> {
26256    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
26257    where
26258        S: Clone + ToOffset,
26259    {
26260        while let Some(region) = self.last() {
26261            let all_selections_inside_invalidation_ranges =
26262                if selections.len() == region.ranges().len() {
26263                    selections
26264                        .iter()
26265                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
26266                        .all(|(selection, invalidation_range)| {
26267                            let head = selection.head().to_offset(buffer);
26268                            invalidation_range.start <= head && invalidation_range.end >= head
26269                        })
26270                } else {
26271                    false
26272                };
26273
26274            if all_selections_inside_invalidation_ranges {
26275                break;
26276            } else {
26277                self.pop();
26278            }
26279        }
26280    }
26281}
26282
26283impl<T> Default for InvalidationStack<T> {
26284    fn default() -> Self {
26285        Self(Default::default())
26286    }
26287}
26288
26289impl<T> Deref for InvalidationStack<T> {
26290    type Target = Vec<T>;
26291
26292    fn deref(&self) -> &Self::Target {
26293        &self.0
26294    }
26295}
26296
26297impl<T> DerefMut for InvalidationStack<T> {
26298    fn deref_mut(&mut self) -> &mut Self::Target {
26299        &mut self.0
26300    }
26301}
26302
26303impl InvalidationRegion for SnippetState {
26304    fn ranges(&self) -> &[Range<Anchor>] {
26305        &self.ranges[self.active_index]
26306    }
26307}
26308
26309fn edit_prediction_edit_text(
26310    current_snapshot: &BufferSnapshot,
26311    edits: &[(Range<Anchor>, impl AsRef<str>)],
26312    edit_preview: &EditPreview,
26313    include_deletions: bool,
26314    cx: &App,
26315) -> HighlightedText {
26316    let edits = edits
26317        .iter()
26318        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
26319        .collect::<Vec<_>>();
26320
26321    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
26322}
26323
26324fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
26325    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
26326    // Just show the raw edit text with basic styling
26327    let mut text = String::new();
26328    let mut highlights = Vec::new();
26329
26330    let insertion_highlight_style = HighlightStyle {
26331        color: Some(cx.theme().colors().text),
26332        ..Default::default()
26333    };
26334
26335    for (_, edit_text) in edits {
26336        let start_offset = text.len();
26337        text.push_str(edit_text);
26338        let end_offset = text.len();
26339
26340        if start_offset < end_offset {
26341            highlights.push((start_offset..end_offset, insertion_highlight_style));
26342        }
26343    }
26344
26345    HighlightedText {
26346        text: text.into(),
26347        highlights,
26348    }
26349}
26350
26351pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
26352    match severity {
26353        lsp::DiagnosticSeverity::ERROR => colors.error,
26354        lsp::DiagnosticSeverity::WARNING => colors.warning,
26355        lsp::DiagnosticSeverity::INFORMATION => colors.info,
26356        lsp::DiagnosticSeverity::HINT => colors.info,
26357        _ => colors.ignored,
26358    }
26359}
26360
26361pub fn styled_runs_for_code_label<'a>(
26362    label: &'a CodeLabel,
26363    syntax_theme: &'a theme::SyntaxTheme,
26364    local_player: &'a theme::PlayerColor,
26365) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
26366    let fade_out = HighlightStyle {
26367        fade_out: Some(0.35),
26368        ..Default::default()
26369    };
26370
26371    let mut prev_end = label.filter_range.end;
26372    label
26373        .runs
26374        .iter()
26375        .enumerate()
26376        .flat_map(move |(ix, (range, highlight_id))| {
26377            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
26378                HighlightStyle {
26379                    color: Some(local_player.cursor),
26380                    ..Default::default()
26381                }
26382            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
26383                HighlightStyle {
26384                    background_color: Some(local_player.selection),
26385                    ..Default::default()
26386                }
26387            } else if let Some(style) = highlight_id.style(syntax_theme) {
26388                style
26389            } else {
26390                return Default::default();
26391            };
26392            let muted_style = style.highlight(fade_out);
26393
26394            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
26395            if range.start >= label.filter_range.end {
26396                if range.start > prev_end {
26397                    runs.push((prev_end..range.start, fade_out));
26398                }
26399                runs.push((range.clone(), muted_style));
26400            } else if range.end <= label.filter_range.end {
26401                runs.push((range.clone(), style));
26402            } else {
26403                runs.push((range.start..label.filter_range.end, style));
26404                runs.push((label.filter_range.end..range.end, muted_style));
26405            }
26406            prev_end = cmp::max(prev_end, range.end);
26407
26408            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
26409                runs.push((prev_end..label.text.len(), fade_out));
26410            }
26411
26412            runs
26413        })
26414}
26415
26416pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
26417    let mut prev_index = 0;
26418    let mut prev_codepoint: Option<char> = None;
26419    text.char_indices()
26420        .chain([(text.len(), '\0')])
26421        .filter_map(move |(index, codepoint)| {
26422            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26423            let is_boundary = index == text.len()
26424                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
26425                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
26426            if is_boundary {
26427                let chunk = &text[prev_index..index];
26428                prev_index = index;
26429                Some(chunk)
26430            } else {
26431                None
26432            }
26433        })
26434}
26435
26436/// Given a string of text immediately before the cursor, iterates over possible
26437/// strings a snippet could match to. More precisely: returns an iterator over
26438/// suffixes of `text` created by splitting at word boundaries (before & after
26439/// every non-word character).
26440///
26441/// Shorter suffixes are returned first.
26442pub(crate) fn snippet_candidate_suffixes(
26443    text: &str,
26444    is_word_char: impl Fn(char) -> bool,
26445) -> impl std::iter::Iterator<Item = &str> {
26446    let mut prev_index = text.len();
26447    let mut prev_codepoint = None;
26448    text.char_indices()
26449        .rev()
26450        .chain([(0, '\0')])
26451        .filter_map(move |(index, codepoint)| {
26452            let prev_index = std::mem::replace(&mut prev_index, index);
26453            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26454            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
26455                None
26456            } else {
26457                let chunk = &text[prev_index..]; // go to end of string
26458                Some(chunk)
26459            }
26460        })
26461}
26462
26463pub trait RangeToAnchorExt: Sized {
26464    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
26465
26466    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
26467        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
26468        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
26469    }
26470}
26471
26472impl<T: ToOffset> RangeToAnchorExt for Range<T> {
26473    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
26474        let start_offset = self.start.to_offset(snapshot);
26475        let end_offset = self.end.to_offset(snapshot);
26476        if start_offset == end_offset {
26477            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
26478        } else {
26479            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
26480        }
26481    }
26482}
26483
26484pub trait RowExt {
26485    fn as_f64(&self) -> f64;
26486
26487    fn next_row(&self) -> Self;
26488
26489    fn previous_row(&self) -> Self;
26490
26491    fn minus(&self, other: Self) -> u32;
26492}
26493
26494impl RowExt for DisplayRow {
26495    fn as_f64(&self) -> f64 {
26496        self.0 as _
26497    }
26498
26499    fn next_row(&self) -> Self {
26500        Self(self.0 + 1)
26501    }
26502
26503    fn previous_row(&self) -> Self {
26504        Self(self.0.saturating_sub(1))
26505    }
26506
26507    fn minus(&self, other: Self) -> u32 {
26508        self.0 - other.0
26509    }
26510}
26511
26512impl RowExt for MultiBufferRow {
26513    fn as_f64(&self) -> f64 {
26514        self.0 as _
26515    }
26516
26517    fn next_row(&self) -> Self {
26518        Self(self.0 + 1)
26519    }
26520
26521    fn previous_row(&self) -> Self {
26522        Self(self.0.saturating_sub(1))
26523    }
26524
26525    fn minus(&self, other: Self) -> u32 {
26526        self.0 - other.0
26527    }
26528}
26529
26530trait RowRangeExt {
26531    type Row;
26532
26533    fn len(&self) -> usize;
26534
26535    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26536}
26537
26538impl RowRangeExt for Range<MultiBufferRow> {
26539    type Row = MultiBufferRow;
26540
26541    fn len(&self) -> usize {
26542        (self.end.0 - self.start.0) as usize
26543    }
26544
26545    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26546        (self.start.0..self.end.0).map(MultiBufferRow)
26547    }
26548}
26549
26550impl RowRangeExt for Range<DisplayRow> {
26551    type Row = DisplayRow;
26552
26553    fn len(&self) -> usize {
26554        (self.end.0 - self.start.0) as usize
26555    }
26556
26557    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26558        (self.start.0..self.end.0).map(DisplayRow)
26559    }
26560}
26561
26562/// If select range has more than one line, we
26563/// just point the cursor to range.start.
26564fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26565    if range.start.row == range.end.row {
26566        range
26567    } else {
26568        range.start..range.start
26569    }
26570}
26571pub struct KillRing(ClipboardItem);
26572impl Global for KillRing {}
26573
26574const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26575
26576enum BreakpointPromptEditAction {
26577    Log,
26578    Condition,
26579    HitCondition,
26580}
26581
26582struct BreakpointPromptEditor {
26583    pub(crate) prompt: Entity<Editor>,
26584    editor: WeakEntity<Editor>,
26585    breakpoint_anchor: Anchor,
26586    breakpoint: Breakpoint,
26587    edit_action: BreakpointPromptEditAction,
26588    block_ids: HashSet<CustomBlockId>,
26589    editor_margins: Arc<Mutex<EditorMargins>>,
26590    _subscriptions: Vec<Subscription>,
26591}
26592
26593impl BreakpointPromptEditor {
26594    const MAX_LINES: u8 = 4;
26595
26596    fn new(
26597        editor: WeakEntity<Editor>,
26598        breakpoint_anchor: Anchor,
26599        breakpoint: Breakpoint,
26600        edit_action: BreakpointPromptEditAction,
26601        window: &mut Window,
26602        cx: &mut Context<Self>,
26603    ) -> Self {
26604        let base_text = match edit_action {
26605            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26606            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26607            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26608        }
26609        .map(|msg| msg.to_string())
26610        .unwrap_or_default();
26611
26612        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26613        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26614
26615        let prompt = cx.new(|cx| {
26616            let mut prompt = Editor::new(
26617                EditorMode::AutoHeight {
26618                    min_lines: 1,
26619                    max_lines: Some(Self::MAX_LINES as usize),
26620                },
26621                buffer,
26622                None,
26623                window,
26624                cx,
26625            );
26626            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26627            prompt.set_show_cursor_when_unfocused(false, cx);
26628            prompt.set_placeholder_text(
26629                match edit_action {
26630                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26631                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26632                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26633                },
26634                window,
26635                cx,
26636            );
26637
26638            prompt
26639        });
26640
26641        Self {
26642            prompt,
26643            editor,
26644            breakpoint_anchor,
26645            breakpoint,
26646            edit_action,
26647            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26648            block_ids: Default::default(),
26649            _subscriptions: vec![],
26650        }
26651    }
26652
26653    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26654        self.block_ids.extend(block_ids)
26655    }
26656
26657    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26658        if let Some(editor) = self.editor.upgrade() {
26659            let message = self
26660                .prompt
26661                .read(cx)
26662                .buffer
26663                .read(cx)
26664                .as_singleton()
26665                .expect("A multi buffer in breakpoint prompt isn't possible")
26666                .read(cx)
26667                .as_rope()
26668                .to_string();
26669
26670            editor.update(cx, |editor, cx| {
26671                editor.edit_breakpoint_at_anchor(
26672                    self.breakpoint_anchor,
26673                    self.breakpoint.clone(),
26674                    match self.edit_action {
26675                        BreakpointPromptEditAction::Log => {
26676                            BreakpointEditAction::EditLogMessage(message.into())
26677                        }
26678                        BreakpointPromptEditAction::Condition => {
26679                            BreakpointEditAction::EditCondition(message.into())
26680                        }
26681                        BreakpointPromptEditAction::HitCondition => {
26682                            BreakpointEditAction::EditHitCondition(message.into())
26683                        }
26684                    },
26685                    cx,
26686                );
26687
26688                editor.remove_blocks(self.block_ids.clone(), None, cx);
26689                cx.focus_self(window);
26690            });
26691        }
26692    }
26693
26694    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26695        self.editor
26696            .update(cx, |editor, cx| {
26697                editor.remove_blocks(self.block_ids.clone(), None, cx);
26698                window.focus(&editor.focus_handle, cx);
26699            })
26700            .log_err();
26701    }
26702
26703    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26704        let settings = ThemeSettings::get_global(cx);
26705        let text_style = TextStyle {
26706            color: if self.prompt.read(cx).read_only(cx) {
26707                cx.theme().colors().text_disabled
26708            } else {
26709                cx.theme().colors().text
26710            },
26711            font_family: settings.buffer_font.family.clone(),
26712            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26713            font_size: settings.buffer_font_size(cx).into(),
26714            font_weight: settings.buffer_font.weight,
26715            line_height: relative(settings.buffer_line_height.value()),
26716            ..Default::default()
26717        };
26718        EditorElement::new(
26719            &self.prompt,
26720            EditorStyle {
26721                background: cx.theme().colors().editor_background,
26722                local_player: cx.theme().players().local(),
26723                text: text_style,
26724                ..Default::default()
26725            },
26726        )
26727    }
26728}
26729
26730impl Render for BreakpointPromptEditor {
26731    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26732        let editor_margins = *self.editor_margins.lock();
26733        let gutter_dimensions = editor_margins.gutter;
26734        h_flex()
26735            .key_context("Editor")
26736            .bg(cx.theme().colors().editor_background)
26737            .border_y_1()
26738            .border_color(cx.theme().status().info_border)
26739            .size_full()
26740            .py(window.line_height() / 2.5)
26741            .on_action(cx.listener(Self::confirm))
26742            .on_action(cx.listener(Self::cancel))
26743            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26744            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26745    }
26746}
26747
26748impl Focusable for BreakpointPromptEditor {
26749    fn focus_handle(&self, cx: &App) -> FocusHandle {
26750        self.prompt.focus_handle(cx)
26751    }
26752}
26753
26754fn all_edits_insertions_or_deletions(
26755    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26756    snapshot: &MultiBufferSnapshot,
26757) -> bool {
26758    let mut all_insertions = true;
26759    let mut all_deletions = true;
26760
26761    for (range, new_text) in edits.iter() {
26762        let range_is_empty = range.to_offset(snapshot).is_empty();
26763        let text_is_empty = new_text.is_empty();
26764
26765        if range_is_empty != text_is_empty {
26766            if range_is_empty {
26767                all_deletions = false;
26768            } else {
26769                all_insertions = false;
26770            }
26771        } else {
26772            return false;
26773        }
26774
26775        if !all_insertions && !all_deletions {
26776            return false;
26777        }
26778    }
26779    all_insertions || all_deletions
26780}
26781
26782struct MissingEditPredictionKeybindingTooltip;
26783
26784impl Render for MissingEditPredictionKeybindingTooltip {
26785    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26786        ui::tooltip_container(cx, |container, cx| {
26787            container
26788                .flex_shrink_0()
26789                .max_w_80()
26790                .min_h(rems_from_px(124.))
26791                .justify_between()
26792                .child(
26793                    v_flex()
26794                        .flex_1()
26795                        .text_ui_sm(cx)
26796                        .child(Label::new("Conflict with Accept Keybinding"))
26797                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26798                )
26799                .child(
26800                    h_flex()
26801                        .pb_1()
26802                        .gap_1()
26803                        .items_end()
26804                        .w_full()
26805                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26806                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26807                        }))
26808                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26809                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26810                        })),
26811                )
26812        })
26813    }
26814}
26815
26816#[derive(Debug, Clone, Copy, PartialEq)]
26817pub struct LineHighlight {
26818    pub background: Background,
26819    pub border: Option<gpui::Hsla>,
26820    pub include_gutter: bool,
26821    pub type_id: Option<TypeId>,
26822}
26823
26824struct LineManipulationResult {
26825    pub new_text: String,
26826    pub line_count_before: usize,
26827    pub line_count_after: usize,
26828}
26829
26830fn render_diff_hunk_controls(
26831    row: u32,
26832    status: &DiffHunkStatus,
26833    hunk_range: Range<Anchor>,
26834    is_created_file: bool,
26835    line_height: Pixels,
26836    editor: &Entity<Editor>,
26837    _window: &mut Window,
26838    cx: &mut App,
26839) -> AnyElement {
26840    h_flex()
26841        .h(line_height)
26842        .mr_1()
26843        .gap_1()
26844        .px_0p5()
26845        .pb_1()
26846        .border_x_1()
26847        .border_b_1()
26848        .border_color(cx.theme().colors().border_variant)
26849        .rounded_b_lg()
26850        .bg(cx.theme().colors().editor_background)
26851        .gap_1()
26852        .block_mouse_except_scroll()
26853        .shadow_md()
26854        .child(if status.has_secondary_hunk() {
26855            Button::new(("stage", row as u64), "Stage")
26856                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26857                .tooltip({
26858                    let focus_handle = editor.focus_handle(cx);
26859                    move |_window, cx| {
26860                        Tooltip::for_action_in(
26861                            "Stage Hunk",
26862                            &::git::ToggleStaged,
26863                            &focus_handle,
26864                            cx,
26865                        )
26866                    }
26867                })
26868                .on_click({
26869                    let editor = editor.clone();
26870                    move |_event, _window, cx| {
26871                        editor.update(cx, |editor, cx| {
26872                            editor.stage_or_unstage_diff_hunks(
26873                                true,
26874                                vec![hunk_range.start..hunk_range.start],
26875                                cx,
26876                            );
26877                        });
26878                    }
26879                })
26880        } else {
26881            Button::new(("unstage", row as u64), "Unstage")
26882                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26883                .tooltip({
26884                    let focus_handle = editor.focus_handle(cx);
26885                    move |_window, cx| {
26886                        Tooltip::for_action_in(
26887                            "Unstage Hunk",
26888                            &::git::ToggleStaged,
26889                            &focus_handle,
26890                            cx,
26891                        )
26892                    }
26893                })
26894                .on_click({
26895                    let editor = editor.clone();
26896                    move |_event, _window, cx| {
26897                        editor.update(cx, |editor, cx| {
26898                            editor.stage_or_unstage_diff_hunks(
26899                                false,
26900                                vec![hunk_range.start..hunk_range.start],
26901                                cx,
26902                            );
26903                        });
26904                    }
26905                })
26906        })
26907        .child(
26908            Button::new(("restore", row as u64), "Restore")
26909                .tooltip({
26910                    let focus_handle = editor.focus_handle(cx);
26911                    move |_window, cx| {
26912                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26913                    }
26914                })
26915                .on_click({
26916                    let editor = editor.clone();
26917                    move |_event, window, cx| {
26918                        editor.update(cx, |editor, cx| {
26919                            let snapshot = editor.snapshot(window, cx);
26920                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26921                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26922                        });
26923                    }
26924                })
26925                .disabled(is_created_file),
26926        )
26927        .when(
26928            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26929            |el| {
26930                el.child(
26931                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26932                        .shape(IconButtonShape::Square)
26933                        .icon_size(IconSize::Small)
26934                        // .disabled(!has_multiple_hunks)
26935                        .tooltip({
26936                            let focus_handle = editor.focus_handle(cx);
26937                            move |_window, cx| {
26938                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26939                            }
26940                        })
26941                        .on_click({
26942                            let editor = editor.clone();
26943                            move |_event, window, cx| {
26944                                editor.update(cx, |editor, cx| {
26945                                    let snapshot = editor.snapshot(window, cx);
26946                                    let position =
26947                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26948                                    editor.go_to_hunk_before_or_after_position(
26949                                        &snapshot,
26950                                        position,
26951                                        Direction::Next,
26952                                        window,
26953                                        cx,
26954                                    );
26955                                    editor.expand_selected_diff_hunks(cx);
26956                                });
26957                            }
26958                        }),
26959                )
26960                .child(
26961                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26962                        .shape(IconButtonShape::Square)
26963                        .icon_size(IconSize::Small)
26964                        // .disabled(!has_multiple_hunks)
26965                        .tooltip({
26966                            let focus_handle = editor.focus_handle(cx);
26967                            move |_window, cx| {
26968                                Tooltip::for_action_in(
26969                                    "Previous Hunk",
26970                                    &GoToPreviousHunk,
26971                                    &focus_handle,
26972                                    cx,
26973                                )
26974                            }
26975                        })
26976                        .on_click({
26977                            let editor = editor.clone();
26978                            move |_event, window, cx| {
26979                                editor.update(cx, |editor, cx| {
26980                                    let snapshot = editor.snapshot(window, cx);
26981                                    let point =
26982                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26983                                    editor.go_to_hunk_before_or_after_position(
26984                                        &snapshot,
26985                                        point,
26986                                        Direction::Prev,
26987                                        window,
26988                                        cx,
26989                                    );
26990                                    editor.expand_selected_diff_hunks(cx);
26991                                });
26992                            }
26993                        }),
26994                )
26995            },
26996        )
26997        .into_any_element()
26998}
26999
27000pub fn multibuffer_context_lines(cx: &App) -> u32 {
27001    EditorSettings::try_get(cx)
27002        .map(|settings| settings.excerpt_context_lines)
27003        .unwrap_or(2)
27004        .min(32)
27005}